{"_id":"destructible","_rev":"218-a76608406596b8a308b0be21d7dfc30c","name":"destructible","description":"Controlled demolition of complex objects.","dist-tags":{"latest":"6.2.5","canary":"7.0.0-alpha.72"},"versions":{"0.0.0":{"name":"destructible","version":"0.0.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/nascent","bugs":{"url":"http://bigeasy.github.com/nascent/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/nascent.git","type":"git"},"dependencies":{"interrupt":"5.0.x","nascent.coalesce":"0.0.0","operation":"1.2.x"},"devDependencies":{"proof":"1.2.x"},"main":"destructor","scripts":{"test":"proof test */*.t.js"},"gitHead":"df39248906f3978996c768d4149f87ecc80794da","_id":"destructible@0.0.0","_shasum":"570b1b0117abcfadcbd96679b8c4064ec7fb655f","_from":".","_npmVersion":"4.0.5","_nodeVersion":"4.7.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"570b1b0117abcfadcbd96679b8c4064ec7fb655f","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.0.0.tgz","integrity":"sha512-KRQ7XgoyMRkKveJGpRbVd8zk+aSvK9EEG5PlCAc1reeJbu1XdajtaQfcnLnpspEL+S0kZ7gPhLOqjHKqIVnQJg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDrxD5IULiIpnfDJHnC1RtNghpofv15XlTFYdiZfMyyOQIhAMdHPEp67qFiAqMYWbC5SiPJVZQxv2UqKOwGEgQhaZqu"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/destructible-0.0.0.tgz_1486821110714_0.23057716386392713"},"directories":{}},"0.0.1":{"name":"destructible","version":"0.0.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"5.0.x","nascent.coalesce":"0.0.0","operation":"1.2.x"},"devDependencies":{"proof":"1.2.x"},"main":"destructor","scripts":{"test":"proof test */*.t.js"},"gitHead":"c920cfc4b9fa0a28ab43ac663a7eb0ac70a9c7fc","_id":"destructible@0.0.1","_shasum":"fa73e03d975069aaa86378d66c6934752573495d","_from":".","_npmVersion":"4.0.5","_nodeVersion":"4.7.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"fa73e03d975069aaa86378d66c6934752573495d","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.0.1.tgz","integrity":"sha512-Yz0m2E+HxRK7S2IKXWgTo5Vs+9GHkmxfIlGql7DA9Acz5vnpvMqpJOor001mRDEmz7wD0NB6M9bSH8Lex+11hg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAb48x2ciy4UcBk064R/vdJ+87gIQEB5OlteX0eyQCiUAiEA2A+xGnk64yzMJTcY2gMq9YXM3ddI7BQfLLujB711keU="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/destructible-0.0.1.tgz_1487111555926_0.7607925394549966"},"directories":{}},"0.0.2":{"name":"destructible","version":"0.0.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"happenstance":"2.8.x","interrupt":"5.0.x","nascent.coalesce":"0.0.0","operation":"1.2.x","procession":"0.0.32","monotonic":"2.0.x"},"devDependencies":{"proof":"1.2.x"},"main":"destructor","scripts":{"test":"proof test */*.t.js"},"gitHead":"a7e6dc22d23ae14dd8b3260cf684944594f6440e","_id":"destructible@0.0.2","_shasum":"0853bec1c9046839e1244f1a7e656cd7aa8594b9","_from":".","_npmVersion":"4.0.5","_nodeVersion":"4.7.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"0853bec1c9046839e1244f1a7e656cd7aa8594b9","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.0.2.tgz","integrity":"sha512-sDggjr/1gf4NkDgoLOrTsXnb9T/tiYDHHeKMzAfFsK1Ray2Wzgms6nPC0xVFB+wXxEkHc1HDrs6iQeSlBzVDmA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD8qGljyzWsgnz5SdTzr+Lle5vQESlyM+EYt+6tGwbhxwIhALiBXGGt16dtRoTjEv8eWJC9lcMxssXMnh8dJACct7dA"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/destructible-0.0.2.tgz_1487149054092_0.9267226720694453"},"directories":{}},"0.1.0":{"name":"destructible","version":"0.1.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"happenstance":"2.8.x","interrupt":"5.0.x","nascent.coalesce":"0.0.0","operation":"1.2.x","procession":"0.1.x","monotonic":"2.0.x"},"devDependencies":{"proof":"1.2.x"},"main":"destructor","scripts":{"test":"proof test */*.t.js"},"gitHead":"8aadc65fdc9473ea5b6de4ddf1de2d755fb318ba","_id":"destructible@0.1.0","_shasum":"169858ee80757208d9a304b3a19367f3d445e5d3","_from":".","_npmVersion":"4.0.5","_nodeVersion":"4.7.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"169858ee80757208d9a304b3a19367f3d445e5d3","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.1.0.tgz","integrity":"sha512-gN4vZfG6nBKWHr0hxRMTjsgXmpVQ4u3G2nJ69NIesvTvy1MltVzDe/kpG2Z9VbvEJDI/v3mNl+qGKNS18EYkfw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDo52qTsn5ff/h5uCs978vGGvPie7Ne0d/+NHVizk1vHQIhAIgOogY034GpLRUCJHbEaLnS2fhpxXAvhvl1YaQXJHyx"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.1.0.tgz_1487243886513_0.7733338717371225"},"directories":{}},"0.1.1":{"name":"destructible","version":"0.1.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"happenstance":"3.0.x","interrupt":"5.0.x","nascent.coalesce":"0.0.0","operation":"1.2.x","procession":"0.1.x","monotonic":"2.0.x"},"devDependencies":{"proof":"1.2.x"},"main":"destructor","scripts":{"test":"proof test */*.t.js"},"gitHead":"730f840d6d395450b80753b5b949be8e44d59052","_id":"destructible@0.1.1","_shasum":"22e858c05dfbb04fcb8b8ddc0b3fb82fe4e9b33e","_from":".","_npmVersion":"4.0.5","_nodeVersion":"4.7.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"22e858c05dfbb04fcb8b8ddc0b3fb82fe4e9b33e","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.1.1.tgz","integrity":"sha512-udx1RC1KHiZ+6dxM7UK4BZuGZMB1hDv3VMtDf28jW5nwD9ONpKiq7PLKglMDq7+E1RDxjMa4RCCsFHRGOeozdA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGPupRj4O43hQss5PUkQ63qLUChIWCJhXSpR1UVGiqKWAiAdqJu82D+SZk9tAsFAa5FhVjzyR3HJ1LVDJLCglloH9w=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.1.1.tgz_1487279648850_0.8169499288778752"},"directories":{}},"0.1.2":{"name":"destructible","version":"0.1.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"happenstance":"3.0.x","interrupt":"5.0.x","nascent.coalesce":"0.0.0","operation":"1.2.x","procession":"0.1.x","monotonic":"2.0.x"},"devDependencies":{"proof":"1.2.x"},"main":"destructor","scripts":{"test":"proof test */*.t.js"},"gitHead":"2e95cf976e169269063a1b68b58cf96f5aacc8b4","_id":"destructible@0.1.2","_shasum":"c444def6ec1095ae47cf811acfd2156040303654","_from":".","_npmVersion":"4.0.5","_nodeVersion":"4.7.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"c444def6ec1095ae47cf811acfd2156040303654","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.1.2.tgz","integrity":"sha512-Uhdu3WDGevqXR+xVsH0QYfeBMe8R2k1PoEP1UQwsUNyHk6s+wAsliPIN521X9DGzLmnrBNxp6HqDYZHodFv3Fg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC1QysdVmtl4TOb3lYwAD7MrRq1oV1IXE3+aiawBg0YEAIgHmcS2KI7lFRyRgr8Kf1hYJmXlMaNWJ/7iTvBj1YOCGY="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.1.2.tgz_1487339471997_0.06697691744193435"},"directories":{}},"0.1.3":{"name":"destructible","version":"0.1.3","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"happenstance":"3.0.x","interrupt":"5.0.x","nascent.coalesce":"0.0.0","operation":"1.2.x","procession":"0.2.1","monotonic":"2.0.x"},"devDependencies":{"proof":"1.2.x"},"main":"destructor","scripts":{"test":"proof test */*.t.js"},"gitHead":"b084cebb7507eb74ae5fe8816daba91b57ca4232","_id":"destructible@0.1.3","_shasum":"e20ee15a8e47bd210f84ee353b2df9fce3f49480","_from":".","_npmVersion":"4.0.5","_nodeVersion":"4.7.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"e20ee15a8e47bd210f84ee353b2df9fce3f49480","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.1.3.tgz","integrity":"sha512-cESN4/XwCM1cSZ7I96b6vD8RAcVOWJ/XNMMJQBO1LHYUoCHTrYwv0b8+IMiaX2xakpPKuMP7m2ZFVIoBVkd08Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBw4KSTNam2S8pn3PNj3ooQcOP1F5mP1ZU26PcqaoNtHAiA3XtXqCuc32NA7+l7vNWz+40bSGdD3Dxp4hMsCg6wDWw=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.1.3.tgz_1489505589719_0.24941521976143122"},"directories":{}},"0.1.4":{"name":"destructible","version":"0.1.4","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"0.0.x","happenstance":"3.0.x","interrupt":"5.0.x","operation":"1.2.x","procession":"0.2.1","monotonic":"2.0.x"},"devDependencies":{"proof":"1.2.x"},"main":"destructor","scripts":{"test":"proof test */*.t.js"},"gitHead":"5f21a993d654a07b7dcd6376c77d601ccd0c14bb","_id":"destructible@0.1.4","_shasum":"58aaa3193e70c546b93a293fbcf9be7e4d0bb0dc","_from":".","_npmVersion":"4.0.5","_nodeVersion":"4.7.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"58aaa3193e70c546b93a293fbcf9be7e4d0bb0dc","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.1.4.tgz","integrity":"sha512-apqGyah4tTDaTngPmCf+DtmB2vYzg8kBG1xT7zbPbvC/g3feeVXYjz932cuT1lj23lx++IWr6wnkH9T4KxMfQw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCYKcnhfC4Bdao4IpVKDPJXL9RW1Qjj72RDhA3XrB1bZAIhAJ+fG86gAmGK6uZEH4lgrRPDk03L1ncNsnr0EgDSoba/"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.1.4.tgz_1489595070514_0.48662120569497347"},"directories":{}},"0.1.5":{"name":"destructible","version":"0.1.5","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"0.0.x","happenstance":"3.0.x","interrupt":"5.0.x","operation":"1.2.x","procession":"0.2.x","monotonic":"2.0.x"},"devDependencies":{"proof":"1.2.x"},"main":"destructor","scripts":{"test":"proof test */*.t.js"},"gitHead":"ced9373a9b6cc89340efb0118e3c23171900a12f","_id":"destructible@0.1.5","_shasum":"5d11fa961833211a495c1a5e36d29b45fef64703","_from":".","_npmVersion":"4.0.5","_nodeVersion":"4.7.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"5d11fa961833211a495c1a5e36d29b45fef64703","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.1.5.tgz","integrity":"sha512-jNiDOLhwCn2TgHdQvj4zGwAxMdoXw/bEywXYMfHAdiEw7pMWKcVFqNu09mAbqaV84Aatw2HMMD6dsABNYu24DQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFGIUXQZy/+PXu1rk2xuMrLVDmJ5Mzm8GVzz0wDe5WZFAiEAsXL7FvM2+lyw31ZNeJuzvY2Gh6j+aWRMeR1ggyEp8i0="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.1.5.tgz_1490195153175_0.786768693709746"},"directories":{}},"0.1.6":{"name":"destructible","version":"0.1.6","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"0.0.x","happenstance":"3.0.x","interrupt":"5.0.x","operation":"1.2.x","procession":"0.2.x","monotonic":"2.0.x"},"devDependencies":{"proof":"1.2.x"},"main":"destructor","scripts":{"test":"proof test */*.t.js"},"gitHead":"d1791fe845994c777139df9231b6805f04b2ca2b","_id":"destructible@0.1.6","_shasum":"ffe8f4a2ab93f5be3447e0c744f76d34a05d5e80","_from":".","_npmVersion":"4.0.5","_nodeVersion":"4.7.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"ffe8f4a2ab93f5be3447e0c744f76d34a05d5e80","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.1.6.tgz","integrity":"sha512-AbS9A+IpL69uA3lXmQKULy/GFK7y6al6mZE8vcNdqyNVVtd3Fm1yA8ukvBUy7QQltoeYe0JIhMCUOGr5RvMRPA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHMcSBwaDk3EOsqlptLPDViNVof9OjSOF25dnXdRHM73AiEA8GZWpT8CHoSQjLOgb/Zu5IOqsQ5zn8x0db0PbghSHIc="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.1.6.tgz_1490905549802_0.4041633631568402"},"directories":{}},"0.1.7":{"name":"destructible","version":"0.1.7","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.0.x","interrupt":"5.0.x","operation":"1.2.x","procession":"0.2.x","monotonic":"2.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructor","scripts":{"test":"proof test */*.t.js"},"gitHead":"c01ef72c5cc3c6a23186cdd9eef121c63c8b986e","_id":"destructible@0.1.7","_shasum":"81b8e046470bb50268344949da81f068a29ea6c9","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"81b8e046470bb50268344949da81f068a29ea6c9","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.1.7.tgz","integrity":"sha512-Pi4mVmjwAXXzp/awOQgEJiQV6OQf2h55fXP6eOGaTU6TC2cqQTfjBiBNzKuV4WBS+6gb7zow8KOgmhmOBLAJ5w==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICDvvcHTRVLfcvW1Lsud1pyVP/Guk4Ouy8dW+koSPtt0AiAofVFoZGBw3cW8YWvfKQ/R+odq2Y080cCeSqqjh6pZrA=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.1.7.tgz_1491495767540_0.8256236233282834"},"directories":{}},"0.1.8":{"name":"destructible","version":"0.1.8","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.0.x","interrupt":"5.0.x","operation":"1.2.x","procession":"0.2.x","monotonic":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructor","scripts":{"test":"proof test */*.t.js"},"gitHead":"dbfcd5a8b248c938c2fab256505c5acc623df094","_id":"destructible@0.1.8","_shasum":"facf96f95b7d8ea5961af005a7ff505aeb0b6808","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"facf96f95b7d8ea5961af005a7ff505aeb0b6808","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.1.8.tgz","integrity":"sha512-EXkjrv8pqBU+0aZ6eYEKhBT+kRHz9EbPIUiGrSWr6FgyccQEmJJCQDcfSJ2WS/xRT/EFek3RmOGTXLNI4vUkww==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHgjA0Q2PnBFiFFuLTN5gwBjojHOCgb7N+1WaMDURBpAAiBXc0F+eyRu0aM/3VRT1OxJGWG19sFnkic3U1+cS8lU8w=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/destructible-0.1.8.tgz_1491550930108_0.19436626927927136"},"directories":{}},"0.2.0":{"name":"destructible","version":"0.2.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.0.x","interrupt":"5.0.x","keyify":"0.0.x","operation":"1.2.x","procession":"0.2.x","monotonic":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof test */*.t.js"},"gitHead":"3c23c266daaec11b73ed5c488a776c2e6e1cef04","_id":"destructible@0.2.0","_shasum":"e82e34cbd596a8bbe393190d3e917fbee11c24b4","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"e82e34cbd596a8bbe393190d3e917fbee11c24b4","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.2.0.tgz","integrity":"sha512-xtHcTTcbYBfV0F4/Qa6Y+qNVQOTimfUGaoetsjBESGfp224Jf7wbAwP4nRnzxyqoIxMPqvSY4TKPBjDKWkrpag==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIECs5/ArQkdNOlRqvxrCfj9rH24e3nXuhcHuN2hMVs0xAiEA5cvyVt/nq+HpaMz+ZVW/D422ez/gZ8ilqJiOf5fSJh8="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/destructible-0.2.0.tgz_1491797173847_0.7520684495102614"},"directories":{}},"0.2.1":{"name":"destructible","version":"0.2.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.0.x","interrupt":"5.0.x","keyify":"0.0.x","operation":"1.2.x","procession":"0.2.x","monotonic":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof test */*.t.js"},"gitHead":"1c96ad03c7f37f319f3066d5eb52f8e453a59ee9","_id":"destructible@0.2.1","_shasum":"2d089b40bf1cb13198e2adecb8a01645a252915b","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"2d089b40bf1cb13198e2adecb8a01645a252915b","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.2.1.tgz","integrity":"sha512-qq7lwn6uzj4FludStX6SXmtc921tzk2taH2W4KLHIcjRpPlW1VhcYfNOCMfW4gjbNF/hcp4aVXscTS/RI1ghIA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAcmFIfrXp4D9v4NxLxijsmWCjjPBFLNXAW2S99BtsUXAiEA3z1RyqaDlvLqVXxreDSioZZnO+JvX66BIYraO2z3okg="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.2.1.tgz_1491798939581_0.18501904048025608"},"directories":{}},"0.2.2":{"name":"destructible","version":"0.2.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.0.x","interrupt":"5.0.x","keyify":"0.0.x","operation":"1.2.x","procession":"0.2.x","monotonic":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof test */*.t.js"},"gitHead":"5abeb09c2c420e36cc1f46dde6c61e2c69588525","_id":"destructible@0.2.2","_shasum":"eb7c7fb6f02b97ea04626212083b22baf84d46f5","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"eb7c7fb6f02b97ea04626212083b22baf84d46f5","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.2.2.tgz","integrity":"sha512-5KE18BtOjiib0aP8CTMdsgn2Q+2txepy0xSoVsFOlci9MKF9YyHzpx4JGhZ5ccPrDI8LRaHQSrAlgTLRFOaUxg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICMjfvUEsDJttdhjM141sglL5l4z3gItkyiGb1zozBjtAiEAwPoKts6VaiLYhoYEZLRVsbdKuP9/vk4PQ1YIWgrNrXc="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/destructible-0.2.2.tgz_1491805453619_0.5986032688524574"},"directories":{}},"0.2.3":{"name":"destructible","version":"0.2.3","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.2.x","procession":"0.2.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof test */*.t.js"},"gitHead":"a580764593f536aedfb88adbd4dc40c0acb7b1fd","_id":"destructible@0.2.3","_shasum":"790d88e465ca2d969da5885f07a0c43b0a1d0141","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"790d88e465ca2d969da5885f07a0c43b0a1d0141","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.2.3.tgz","integrity":"sha512-FfuZo2GaynM1dfyfYQkN+TzWIAMevt2QeDT1D4wlxs9O2urFjeSy1ridrIcwFN+q6bQ/NPUSZerOLZnLahHP5Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCridtt1hyzmKcNTDLBjj2Ky6QA/dSsC0ECpu+pCRYsYwIhAKQ1n5WtOBjtQYZddcnp0XuqOP+WbXIYOwlYipEImSW0"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/destructible-0.2.3.tgz_1491845420113_0.32144338241778314"},"directories":{}},"0.3.0":{"name":"destructible","version":"0.3.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.2.x","procession":"0.2.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof test */*.t.js"},"gitHead":"76e35ec2037ced239dc667c51358bb005431fcde","_id":"destructible@0.3.0","_shasum":"abe21c225e585acad39413a97ceb382c12dcfb27","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"abe21c225e585acad39413a97ceb382c12dcfb27","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.3.0.tgz","integrity":"sha512-avGj8vVg79+x3JF8kpvEzpNBqgd324ngBz4rG2JKG+422AI6R3b94lOp4Bs15s9zFj6rR5aXBsaDLYC9fC5gIQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDYpMFSul2b/HQYLW+5egfXYiSiyne6lgVAWRnhODQLIAiEAxLJuD1ScV8La3ALCrOGLnbGo4zBj1NO7VU0P5yb1vaM="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.3.0.tgz_1491929664132_0.8360887668095529"},"directories":{}},"0.3.1":{"name":"destructible","version":"0.3.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.2.x","procession":"0.2.x","signal":"1.8.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof test */*.t.js"},"gitHead":"38d140b488eb1bc1b241dee649a1188492d0bb16","_id":"destructible@0.3.1","_shasum":"2e4978790b5bf4c1c4b5b72ae709451a175800c2","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"2e4978790b5bf4c1c4b5b72ae709451a175800c2","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.3.1.tgz","integrity":"sha512-fAe2MfdqFUKtRPqCrRcC6gS+vPT4ByAqZc5zltcDJdH6plh9gg9uD7buVbZw+g+cCdOwp1PNTytkgc6eCiB/kQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDIJQFwjWnvULpGamQufEPJZWI0sgATTRIO4NCFrt4HrAIgKC1KqA4GxuvAMompyfJCR5v0dhPY0lfnyxfl6KFm/x8="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/destructible-0.3.1.tgz_1491930656333_0.25829834188334644"},"directories":{}},"0.4.0":{"name":"destructible","version":"0.4.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.2.x","procession":"0.2.x","signal":"1.8.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof test */*.t.js"},"gitHead":"dc36b707f1ab9b01b7895eb77fc9f6fcafe86b47","_id":"destructible@0.4.0","_shasum":"9345f1acbb17affd2eae64a7b8f2efe2771e4663","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"9345f1acbb17affd2eae64a7b8f2efe2771e4663","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.4.0.tgz","integrity":"sha512-lAAqCcKjVAsuKebjAsP1fCWpCzf6pWaO6gTu/a125MdpMOsLB8iIg1egGdbgojCOjwi77ZhH9A53zNMKvwgpJQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDjCrMNYAAJDrxP0FINWuLytABrou33xB2oxx7m7E8QDAIgJUKEuuyG94Utmtr7y4EE+hiAqhhIswEBJiiy2rSi+nI="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.4.0.tgz_1491933054947_0.45048620528541505"},"directories":{}},"0.5.0":{"name":"destructible","version":"0.5.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.2.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof test */*.t.js"},"gitHead":"1b3c470deb968338799e0bdce1e7a36d3683cc71","_id":"destructible@0.5.0","_shasum":"4c7f8ffea1a26d6b604c829cbcb99b53a2290bde","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"4c7f8ffea1a26d6b604c829cbcb99b53a2290bde","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.5.0.tgz","integrity":"sha512-SP9c/GYJMqphghpETMeX6PE5NaMjqWbwafgqG45VLdHCEyXGBFjRW8YOmlDiLZE3pQ2jf7Cq50X/y4RdvkQTuQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBgplPqF85/oePdT3JvVCQDpfcqc/BPFj1fVOmkfX2BTAiEA/R0xXdHazq2gDnvpri4z4Uc9kTq8y1pMGvaHoyOTsZ0="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.5.0.tgz_1491987557498_0.6682048679795116"},"directories":{}},"0.6.0":{"name":"destructible","version":"0.6.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof test */*.t.js"},"gitHead":"92bc11d32b352242845d0a3cc408bd5369f63d74","_id":"destructible@0.6.0","_shasum":"acf165319420896cc104711f48b6eed904e625cb","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"acf165319420896cc104711f48b6eed904e625cb","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.6.0.tgz","integrity":"sha512-h8dJysf2aaNOODbs5gr5Bs807DlZE1FiKm1xDyefZq/FeL42eJXH+AygRdxxScAOHM41VIZYh2pTcaEltMXz7g==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFSdFjTQyS3KmEj+XsUFH7DbwaUHjPgvmHFIiy09PHd3AiBUNiAluuRrhe+UNyzkZzhvPfgeQG5lKNCWTugiMVjjJQ=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/destructible-0.6.0.tgz_1492015364887_0.08164369431324303"},"directories":{}},"0.7.0":{"name":"destructible","version":"0.7.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"5f69feedb08579eed624129ec45a9488e184dd89","_id":"destructible@0.7.0","_shasum":"7052ea48018e65326259c6cb53708c050bbb9027","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"7052ea48018e65326259c6cb53708c050bbb9027","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.7.0.tgz","integrity":"sha512-eF5bpPXeLrnRiMkFpwm/r85gxHtRd6+iZyvgNMn7GZea12ft5Hve6hkKVDwpkUZUAz5F9/S1ys+eCq0FYLoMww==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC/GwoNk12lHunnEFBEOBrJo6PqzKUjXxf+xnR6xTDjKgIgTICWfZLV96cEWHXjfiAKTGD6XqOz2plek5M5DkTXegk="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.7.0.tgz_1492064014507_0.523169168503955"},"directories":{}},"0.8.0":{"name":"destructible","version":"0.8.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"40fdf0667af328f05ef844993eac0c7ea9ca0775","_id":"destructible@0.8.0","_shasum":"e363c9dd3e4dd5fd1562f5571ebdf25dadb7d44a","_from":".","_npmVersion":"4.4.4","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"e363c9dd3e4dd5fd1562f5571ebdf25dadb7d44a","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.8.0.tgz","integrity":"sha512-LSbLnj/jdqRKCzBJxV+4v04RTIFWgrdfkbKDrLPGqU32yj77e/hFKdNTDt6nfzEXlNvB6CIcmhcgnS+A5CjaUQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAFiggv+E9v0E/rjPZNvstSD5TK8DB5hcYbJrBlkDXsYAiAvrwxWLFeh7Yx45CPGLofwNww0rbbEczGZkJNMQQF67g=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.8.0.tgz_1492066812733_0.48469532979652286"},"directories":{}},"0.9.0":{"name":"destructible","version":"0.9.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"0a8da61fdea04f663442e5b8ea71418199443d2c","_id":"destructible@0.9.0","_shasum":"1859258bb926c0e9a478e61132819b1885a47841","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"1859258bb926c0e9a478e61132819b1885a47841","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.9.0.tgz","integrity":"sha512-OzZkfHBeRmG7DECe7pLLlf043VO1Alj/41YjFbNsoqVxmS2SHm9Ku7HRChthBWfTgpUAhrsGDOLYnoLrn9d4uQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCLBklU0aAlzaGfwS75cDE1MnW0vmlRcJWwHRM6RhY3lwIhAIW6VIF9T6P1gk7bkE0qlKZ+VTZZebMSh+flhm+1hJNV"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.9.0.tgz_1492780659226_0.9409191480372101"},"directories":{}},"0.9.1":{"name":"destructible","version":"0.9.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"fe2db58479a6ee07101badb4449205545fa68a67","_id":"destructible@0.9.1","_shasum":"19b46da7fa24a8ca70508933b11b3e1fa1b5cff0","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"19b46da7fa24a8ca70508933b11b3e1fa1b5cff0","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.9.1.tgz","integrity":"sha512-Z3t88AHbbkO9zw6n9qZSETnlLDwlPgwLM53cFIRNO3me0ON+D1xQnm0152bRx/JRYT4jrgjGDreL7eVq1V4WJQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBEtzW2K6eNaK2JamRxvEt8N0fqb4FuPPfI5qOj7SavpAiAET6zdgYycH2/F7q0GllEfFqwJ8IV2kguFeKuxW9yYaA=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/destructible-0.9.1.tgz_1492780932021_0.6204776193480939"},"directories":{}},"0.9.2":{"name":"destructible","version":"0.9.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"a3782267de7f862441c2bec870c06257eb4f0bf0","_id":"destructible@0.9.2","_shasum":"0ce03ed72c0065ce2c9bc7a72f0634317b76920e","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"0ce03ed72c0065ce2c9bc7a72f0634317b76920e","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.9.2.tgz","integrity":"sha512-VkbinC3LF+LQcV+0mg0dxLDGK72iRP4qnXjpqR5/zap32VudJ6jXUDOBI1YCfIP1OEP/ySKpQFYg/hqd2JDilA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCCGK/Q19nrnp0s1T4345Shpgv5IUEHEn3Ue+bmf7DMugIhAKY0kK8BEBFkjpP/EMccgiDOR2S/N7GmIYOHOYdfWU+y"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/destructible-0.9.2.tgz_1492790019608_0.07336048572324216"},"directories":{}},"0.9.3":{"name":"destructible","version":"0.9.3","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"365a9f3274f314dd05f127a0ea1f1bcb6d83753b","_id":"destructible@0.9.3","_shasum":"df08ecbd3798a03979d3101731fc4053e613ba0c","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"df08ecbd3798a03979d3101731fc4053e613ba0c","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.9.3.tgz","integrity":"sha512-UoinTCJPY5HpPQ6f/zgxc+CWuwOzYh2iVpYlR2jq+tkS6Ku0I8Tb3cz3MRbkkg8f5yo4ghXAbVyk/IJCHnP8jQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCWNEyio9ehGcvJMkF+xJMQZyQN0pfxuhEiNgMFIMv7xgIhAIMYTUCKJyRbHoDukBJFymiR2gN5Osvdq9w7muqryYg/"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/destructible-0.9.3.tgz_1492920417355_0.9054593078326434"},"directories":{}},"0.9.4":{"name":"destructible","version":"0.9.4","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"e6f8a62e43444c890ffe9d653d8b253b709e5231","_id":"destructible@0.9.4","_shasum":"12da91a042298833a66b6c9497cd18bafdcf9ee9","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"12da91a042298833a66b6c9497cd18bafdcf9ee9","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.9.4.tgz","integrity":"sha512-CDuiBYnOSXlrAKr242p83AM8bZ5PoLXNj+h2/ZwNaZ2ad0X0GYqoqFfzk7ytum1xQxzETxiZU18okhcUfqYntw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDjAokd5hUJt/jEjkVqsaErckhJaVRSd+BQAbB9inTEkgIhAPk77Eyjq1pEndI6h51/iOfSpD1bcYbiJ9hBj4gaW+/l"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/destructible-0.9.4.tgz_1492968280217_0.6531444238498807"},"directories":{}},"0.10.0":{"name":"destructible","version":"0.10.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"ea05eebbc0119ce78ee3c99f97b6cde11ea338b3","_id":"destructible@0.10.0","_shasum":"79e3b54c228c8c7a005654dea9831691859856a8","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.7.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"79e3b54c228c8c7a005654dea9831691859856a8","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.10.0.tgz","integrity":"sha512-zzTU1Rel7/PDILf0qNmDVOaFvcMI/KZE/RlLG2BcW/KqYi1nolilOZqNcDHCHCPFSyKyzhPwvI0v7e/RXGRy4w==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGWT9vPnFUC5D0lOFFe1vhNrvWD/CWqe9qe8GKKX28IKAiBqBVXEiYh5l9ouXXHv5H6BaggnHrNUzBdIx4OJH5QsdQ=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.10.0.tgz_1495221882891_0.15030818269588053"},"directories":{}},"0.10.1":{"name":"destructible","version":"0.10.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"2f180196ce3d0f80c10bc23fc34836d690b454d3","_id":"destructible@0.10.1","_shasum":"5c4015aa0447c1df1a60914bf7c95093872d9792","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.7.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"5c4015aa0447c1df1a60914bf7c95093872d9792","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.10.1.tgz","integrity":"sha512-43QcofAHxt4CY+b6qU016UViv3/w3gVqGrEpsxRrp15fw2TJt79hE+BIoIZ4v9f8BqdTz+duy9wcOL5mYFMWVg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDeYpjw0Nx9aWllv0MgYi9N00X8b+ODFYDGFfSL7BbGwwIgOdlTmnZSobDIcxMuRjz6dV6PFEm6WJdikJrVYKj7r9M="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.10.1.tgz_1495248411868_0.08133116806857288"},"directories":{}},"0.10.2":{"name":"destructible","version":"0.10.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"43b8ac1497328f32281565c6ca64d506ff8c0ef8","_id":"destructible@0.10.2","_shasum":"94a46494290f1655449ffab212ce9b0dc1c88d2f","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.7.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"94a46494290f1655449ffab212ce9b0dc1c88d2f","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.10.2.tgz","integrity":"sha512-BNIpdqjbLN/YSdLTKTv1RPsndBnnWPpkIOj6uNSSmasax1eSMWtJwvfEOO0C8R+lfUxP3974ZpO2q+WNAEDv6g==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD1EAuAv9vr4peIxOXqTUafYGLSYsORa7GSChcdvJbjAAIhANhbyt382WTkVFjxCnAbUYwwR505CLs2Ttzi04Jin3qv"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.10.2.tgz_1495337768928_0.025124804815277457"},"directories":{}},"0.10.3":{"name":"destructible","version":"0.10.3","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"f0fe1a6f4e52e43547585af5ae1a7d63b7bff148","_id":"destructible@0.10.3","_shasum":"b41908bda1b203837ee7a9a7c04a72c776a1ad96","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.7.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"b41908bda1b203837ee7a9a7c04a72c776a1ad96","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.10.3.tgz","integrity":"sha512-ZwxbcN6fkSiFSvd2dI0CBTGx+sEzSJjuBtgJ9fn0waNJcmHMGkHoHDdy0wa3tNEgW05PWvuGIyQu89XUbpf69A==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBid9KWLpgm+7v/7cohqP4bIZqvh5skeW7hG2Wz5IYquAiAdCHpmUE9pwslROjLHxeHv0k8pzu0dHmyWlCbowbVzBg=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.10.3.tgz_1495419274342_0.6355317682027817"},"directories":{}},"0.10.4":{"name":"destructible","version":"0.10.4","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"fb64057c65320ed0d3874423b5ca63372a9fcd37","_id":"destructible@0.10.4","_shasum":"32aae8ab905012c6377480574ca87a4fe524ade5","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.7.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"32aae8ab905012c6377480574ca87a4fe524ade5","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.10.4.tgz","integrity":"sha512-FBIJNtkFW91KPBV3hdi49DpXIzSOmW9pb9sPSGvqrrHp1Rd6Za3OmvltW26wJxhOvw/l3wGAbgZ/DNZr/JmBbw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDGTorrQtArCMWKn0nrGAdKFSkLjWp67xo5c44MRUvlPwIgLrOll/EBzl7ussvpim8W4wQglTTr1jYDy6PN+ZVW+tI="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.10.4.tgz_1495461367143_0.49534450145438313"},"directories":{}},"0.11.0":{"name":"destructible","version":"0.11.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"e44699d3812e35046f06a373f7e0eaf478401335","_id":"destructible@0.11.0","_shasum":"1fd272e1bab6e6f26cf706523e5d1a66c568301a","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"1fd272e1bab6e6f26cf706523e5d1a66c568301a","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.11.0.tgz","integrity":"sha512-CMpNi5Q+Z7P1OckFktT/SWyUN3ratoUXGFJzHE65SM+lGaIT7zj8bEKisNWIOvzhs1B1eQpP+SWYgobV6M3BZg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDqmzt4AKms6KluPntab82Xvltxa82FWawzJkms9fl/AQIgecewBQMgz2fB16RHEcdqc7dSXS5FI/dMaw48eypd/Io="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.11.0.tgz_1496117275193_0.6527688154019415"},"directories":{}},"0.12.0":{"name":"destructible","version":"0.12.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"bfb1c69d353dc9c5f7a085fb475f6cb9e147f9e3","_id":"destructible@0.12.0","_shasum":"2df13a4cd9808e0330f08ddf9bdd6389939330d7","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"2df13a4cd9808e0330f08ddf9bdd6389939330d7","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.12.0.tgz","integrity":"sha512-QoMSS4wBuZqT7NLICPgmXTBVvDpu5SDav25YzyDHd78H1QLoG09NwaOWis7utRY2JOsqOsTLcXfHdC5HkDd/hQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDzcI1zry/q6y9eBVfjU6BwpwOEnYSBsxk1NSip8p6nPAIgQ/Hb+bFhpnmciIe3E5aGyhRhi/ylH9kPOW24wX44VCk="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.12.0.tgz_1496296938077_0.4549110736697912"},"directories":{}},"0.12.1":{"name":"destructible","version":"0.12.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"644711805eec86c3896b9611f5fec88031f198ae","_id":"destructible@0.12.1","_shasum":"e2fe00753e9344c443504a3ea78978c0b6ad923d","_from":".","_npmVersion":"4.5.0","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"e2fe00753e9344c443504a3ea78978c0b6ad923d","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.12.1.tgz","integrity":"sha512-nfJrnpDSsq/jjaXvKrkZoCp3R0rE+bAJfXfVGZGwR/TskdQ3Zy4DwCIW5ljpuf2naGTNos/D0x+Sqn3v8TGIiQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDaj0EgQzWvNg9x1QaBiBMixUzxaU1fbK3MQhrKRICLRAIhAM1A0S2vWjWsfVq5BGiduahlElxBo25J8+orbrulNLNA"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.12.1.tgz_1496411596410_0.8069401199463755"},"directories":{}},"0.13.0":{"name":"destructible","version":"0.13.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","procession":"0.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"0a0d8e4aeb74e324b3911afc9132efebb6e6999a","_id":"destructible@0.13.0","_shasum":"cb5e125941fca269b7a846692a7c503e846f3d23","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"cb5e125941fca269b7a846692a7c503e846f3d23","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.13.0.tgz","integrity":"sha512-ODBja6txShdJPnjrXlFbNQR4Tzg3mqKAnZWc+BlMJqvO9ErWblSOtOuct+DgirDkR8R6oQIrVl7SxcygRdMZJA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGl0wI5G0L4z/4yhjxK2uga94asJmBP24/YUa2SXS7wpAiEA2ZIekHtJfhDqNsEO8IgKNlVpuk4/WC2FT61qqOn+7yQ="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.13.0.tgz_1497892562348_0.030750460922718048"},"directories":{}},"0.13.1":{"name":"destructible","version":"0.13.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"efefc143da8aee38aa74ffc3d8057e33cb4bcaee","_id":"destructible@0.13.1","_shasum":"4537d8c8bf9ed138c1a5057dacd2b0b05f2f0481","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.7.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"4537d8c8bf9ed138c1a5057dacd2b0b05f2f0481","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.13.1.tgz","integrity":"sha512-uNp0Ngrw10otfL54+rSJIsC3FmeSU5wVR0Ov7qrzr9fXXbYkjYugn9VWwCzpnLD5cpKjhHaExlZcF4/Xco5LsA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD/nF+KA2ScnY8DRsl0R5kYP1ldZ/3qZIH6/NHgPxA4wAIgcJ/0vwPlqSnajfjodA2QZ6TSJMZFST3oNAndlMHCVkY="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.13.1.tgz_1498965075348_0.2508923013228923"},"directories":{}},"0.13.2":{"name":"destructible","version":"0.13.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"44dbc875a2515d8a0b4f64477e9ee4eb7c8b72f0","_id":"destructible@0.13.2","_shasum":"1f1fb8a572342ce841b94b6e5d96668f06f0cc6e","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.7.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"1f1fb8a572342ce841b94b6e5d96668f06f0cc6e","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.13.2.tgz","integrity":"sha512-Rb96N0uMM80MTvsux0FzNO18V0E9TJsapi7HCKeksB43/x5z9JUPzncPHId4N8Pa2OFZxQZpAwVWRlirzhyY7A==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQChrDsvNxL690MK3aTWbO1uD+Wyh/PV7jP8/bUKkeUnxwIgadkLfBINGxLlToz4m4+vsYisxWZi2GgyrNHJVR5Hsz4="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.13.2.tgz_1499444968409_0.11661882069893181"},"directories":{}},"0.13.3":{"name":"destructible","version":"0.13.3","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","happenstance":"3.4.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.4.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"6f60bf5b6ec768dc8ad34826ce2450747f086fc9","_id":"destructible@0.13.3","_shasum":"59596a41d1cb56ed9fb449280d9ac080bd9c9c6e","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.7.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"59596a41d1cb56ed9fb449280d9ac080bd9c9c6e","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.13.3.tgz","integrity":"sha512-3T+v+0e4swnLEK2KZCSjj83dopbr4jxM2UxqK2ZZOujzajJuT32lhbOhBNoF/ytNYNyOFHeiJzBVy4RkGzVCfg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDtb5NMj8BFnLcsVhryHYpx7m1C8gWXaadERcVDEMmwZAiBuQQN4d6/1QdxYOD9D0CYzVg+9EYXosJJaJYkvpSekcQ=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.13.3.tgz_1499461588792_0.4393042381852865"},"directories":{}},"0.13.4":{"name":"destructible","version":"0.13.4","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.6.x","signal":"1.10.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"6822720a03f4250afef7a8835492b7834aa37326","_id":"destructible@0.13.4","_shasum":"333afeab3827319092232efa48a5da66899ca718","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.7.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"333afeab3827319092232efa48a5da66899ca718","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.13.4.tgz","integrity":"sha512-P85P7ni7KGkSwOBlMxl8XkN/PIwk+LKwx85XkIVonOxob+l1wPRh54XIgFCXCKRjMGQEjxuuN8xmEJVzDaiqUA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC5aaTAtlGL8f/2S1oa4BR769QNFsS5FwM7+E5Nc8/SfgIhAIP4i+qkgnzRp3dL5G7YfqEi+T6Y6gff3Z6SyjIYpI8H"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.13.4.tgz_1500004466535_0.7456895783543587"},"directories":{}},"0.14.0":{"name":"destructible","version":"0.14.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.6.x","signal":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"6aad5afe1c08088ee2d06c7ce7d730db82350a82","_id":"destructible@0.14.0","_shasum":"62513a854ad17fe64fd7ee7104bae7c16e06d437","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.7.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"62513a854ad17fe64fd7ee7104bae7c16e06d437","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.14.0.tgz","integrity":"sha512-W1FJqmnBXdyWlHj2n3H/qsjQ27SNJCWC1YGFq79UmINhBSUipVKQ0GjCj9ron+rmd6piJP7dSKXgv7D+yUKHlQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDxRrtBSTultZX3Leu109fR3Z6ClOwSQVs06CKS9hoRxAiAnSXvOhuHnGT4CedrINh3Ze2wAG8qiV6JDVDSDDLeLcg=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.14.0.tgz_1500052394879_0.6187159975524992"},"directories":{}},"0.14.1":{"name":"destructible","version":"0.14.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.6.x","signal":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"d709d7218069a779475851be0f7cfb2f513fa9ee","_id":"destructible@0.14.1","_shasum":"a4d98c9cc5f78c7aabf5e64f2b1749b754db0926","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"a4d98c9cc5f78c7aabf5e64f2b1749b754db0926","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.14.1.tgz","integrity":"sha512-mQMJCSBm0hnJYDxryVaop/RJcJ0Si3uEFqqtj/ff1sPLYgHkFtBSjU3kUU0ZeMUNfMyjG/hqm3CZcIhdNgLpnw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDWtVcpfjJDY56Z/6oyYajxaZVc8bKpLOU/3cO2qPYdCAIhAPMvhFMAYAOUIpIaLh2db38IaJOLTQmsQjWDtBRQSkIk"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.14.1.tgz_1501786454057_0.15280332905240357"},"directories":{}},"0.14.2":{"name":"destructible","version":"0.14.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.6.x","signal":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"d9483f227272115d95e4b4e4231d8cefe45fea31","_id":"destructible@0.14.2","_shasum":"2f551fb5f43c956196be7b31662ad8a4014b7182","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"2f551fb5f43c956196be7b31662ad8a4014b7182","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.14.2.tgz","integrity":"sha512-54UnzxA/tm4N88f62x36AQM2O1gQF8591/nIDH4lhJObiQIBciYIgo296EqR6LjtTaWYsJmXnFVFJ02yzXn/6g==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBygA+V+fPXf2eJIxth1jaszzAvxDLsJqnnWXVR4Nr86AiEAvKFV3Yb5hcrJhw6ZmZPO5awLKyzrciActqoSS17arK8="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.14.2.tgz_1501812328403_0.926625709515065"},"directories":{}},"0.14.3":{"name":"destructible","version":"0.14.3","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.6.x","signal":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"e55c1eecb5e82fdddc28766f549843019ac723d5","_id":"destructible@0.14.3","_shasum":"bc1f56a90f4d40e7af5121506f56804871e184d6","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.11.0","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"bc1f56a90f4d40e7af5121506f56804871e184d6","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.14.3.tgz","integrity":"sha512-clsV9Zc+y3FbUUmhzr6kxpeuFJiKqdpp0KF1cbnFT+iTTyxC0h9whMTvCb4tAG4EysdA923IsA8gNp49NL1L4w==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHzFc9mwoYObK63szX7LaSojbbwLsTZl4EP1xcmLjkdyAiEAjmpfojiBLRIwLTICquShD30Jy2ZDXEaDTshQ5vY3f9I="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.14.3.tgz_1504805892056_0.27548366342671216"},"directories":{}},"0.14.4":{"name":"destructible","version":"0.14.4","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.6.x","signal":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"d21c1a0d54b3254708ea9ec814ced84a3b7bab8a","_id":"destructible@0.14.4","_shasum":"86b99558510508e6b0acaf538674614083900138","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.11.0","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"86b99558510508e6b0acaf538674614083900138","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.14.4.tgz","integrity":"sha512-nLckstSQaVN3P2d/P9wReZVZsneasMt+19orkK9pyIQfghKLdWgt9X7VX4b0/m2oAE1gwDw6c5QxuLXCqCklvA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEjfuA7PGZGN1yOTnKvdEKBh61+iCD+oGmQuRTudoG2OAiBq9n8rfR8IwFu374joCdRaEvMne8quhpIvj24Txe8vNg=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.14.4.tgz_1505749875156_0.5057977912947536"},"directories":{}},"0.15.0":{"name":"destructible","version":"0.15.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.6.x","signal":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"9d95228a46358f89c5cc50602f8a937e4d4bb3f3","_id":"destructible@0.15.0","_shasum":"b1b34940db3c0c4e666146811cb331d36b76a74e","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"b1b34940db3c0c4e666146811cb331d36b76a74e","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.15.0.tgz","integrity":"sha512-sL4QEwCIYvW7X5Gpp0Cmt2YjhvbR0F2NRx1mSS7R+QxD2zR9vRd7007DPRwqkfD/yar9E4ePWyijkFGqFbt5Yw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDRNmhfKoZ8OlqO5gLafWpvs01PAYnNofmtGdT4zyCh4wIhAOJLWFBZGreF7b0b88DnKyM6G+mV84dPxENGOhsO+6Qh"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.15.0.tgz_1505881305623_0.17052897973917425"},"directories":{}},"0.15.1":{"name":"destructible","version":"0.15.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.6.x","signal":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"f1bb5a2d2176f39e8ca56924301f26ccec37dc26","_id":"destructible@0.15.1","_shasum":"c883139b3eb4101c2c9c9dec813b770e2e960908","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"c883139b3eb4101c2c9c9dec813b770e2e960908","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.15.1.tgz","integrity":"sha512-aZOdP+h/jsJBAp1D2/oGYzBmU4Wxrezlst6/xbJM5sxp5mF4c78UaqqeYRmCLPSKiKoxrZaxiXzh893RC6r9gA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBcIiK0zhnciygocIwLAoC1CQaAjnYNcdtW8Tv6G8+fjAiEA+uqd3hjoB2km8qkTrXdFlu+7G/OiIQyZR078NJ9+UaU="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.15.1.tgz_1505885098956_0.4825249840505421"},"directories":{}},"0.15.2":{"name":"destructible","version":"0.15.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.6.x","signal":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"3879283d929e84fca65dd8406b04bd678639f936","_id":"destructible@0.15.2","_shasum":"0ecf6af40456bd0322e68726fa0e25676bb52924","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"0ecf6af40456bd0322e68726fa0e25676bb52924","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.15.2.tgz","integrity":"sha512-EtDRaoRa9jZcn4fRsW5k9gqequTlOGckdOVVhUFsIsTOKNg4PICaJba4aWn6b1NX4Mh6KulVn62CSJqull4zwg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD1khHxLmIo5afUMFqYp633/xFt3P3fcujoRitX3g19CgIgaagJ9FMHruyp054kw7smMZV/eHEdultTIVOb1Gd4HyI="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.15.2.tgz_1505897455834_0.3965941972564906"},"directories":{}},"0.16.0":{"name":"destructible","version":"0.16.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.6.x","signal":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"326aa1ac1a9098301642efdae1657b77376ea288","_id":"destructible@0.16.0","_shasum":"2bf2e09234e29988c8e95b1d48129570ab8d06c8","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"2bf2e09234e29988c8e95b1d48129570ab8d06c8","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.16.0.tgz","integrity":"sha512-yQ+QSDa88xfWxU0kb1E+i2VQqgtYvwoNu+SekDR819Q05/J5LATbqIHk1E7ejlmWFS9JvFWzkQvG3sIitqglMQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGhdXhAiXGyPHM8zGlC2UtcBnVAZDgAVYcd4Huz3SJBmAiEA20IsOrYmqm2KHJPVEMQY/sNyFId+9RRSxzk/VdLle/w="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.16.0.tgz_1505987422764_0.713800466619432"},"directories":{}},"0.17.0":{"name":"destructible","version":"0.17.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","nop":"1.0.0","operation":"1.6.x","signal":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"e7d183610266edbe8bfb8fbb2a6b0523e9f160e4","_id":"destructible@0.17.0","_shasum":"0e6ec5fc155c1c618ae7af4f8e485b219333e5f0","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"0e6ec5fc155c1c618ae7af4f8e485b219333e5f0","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.17.0.tgz","integrity":"sha512-wCn1SADMhibST9h76I1EN6qRQ+1nrQrYHKoiUrSxlQiqlQPNsXOTAjOPy4Kt51tUZ7jwt84pPtNV0pu5ub+/cQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDwUdcUMg4TBjmJoD8gpKu5O8nqdE3w1n5PMoMOOIZvmwIhAIDCIYhI2jenet1A2YJvpwO2oxSOCFkNYfTs2jawkCNt"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.17.0.tgz_1506879137305_0.9090563827194273"},"directories":{}},"0.17.1":{"name":"destructible","version":"0.17.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"4242a0409bee8f717c53b3da3fed77029d46e23e","_id":"destructible@0.17.1","_shasum":"69365d48c0229b9d37cc2de42704006c7f530506","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.7.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"69365d48c0229b9d37cc2de42704006c7f530506","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.17.1.tgz","integrity":"sha512-BFYCXE7ik+XtjGmugob9S9crbPibNa++KOwV7hPfMigbUMAicTiittPDZUtvPIZb6V0vaY/t6wPdVsPOf2Flpg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIG23VgU5GyQOEoqgYa3rwx+j7akPHclQCZr6wcnibL+PAiEA02+ixUlP4Emf3qqWPVFzOV61/SYXWtqxMA6vxfc5FLo="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.17.1.tgz_1511409014759_0.3490396770648658"},"directories":{}},"0.17.2":{"name":"destructible","version":"0.17.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.2.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"2b8d00cd306fecf35dfb60599555063006aefe2b","_id":"destructible@0.17.2","_shasum":"f948758a480c6b0375679f884227c68877b913d5","_from":".","_npmVersion":"2.15.11","_nodeVersion":"4.8.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"shasum":"f948758a480c6b0375679f884227c68877b913d5","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.17.2.tgz","integrity":"sha512-yyiIaTS2OZkcl3jEuiiSxgvXfUsy/GnfV69ia20WbnCSQ0/Zt9wegLSEhOK3PGrek4k2HvPg5R1cXT//iXfYEA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB0EOXKl94iBI4yKXqXAkLNH1s8TqwYf1gVHfh0LSJvpAiBh3mVxuL/DSrlXo3diNbS48wCq4UrbyyzzvV9V/F4nQg=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.17.2.tgz_1511749842155_0.7359541889745742"},"directories":{}},"0.17.3":{"name":"destructible","version":"0.17.3","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.2.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"8515b06caf45a9d5b580d582e31e5d98e7d48d1f","_id":"destructible@0.17.3","_npmVersion":"5.6.0","_nodeVersion":"4.8.7","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-IuRM2OYljB5CwFSm9OeUmQKfU5irqbSK2qPKxLJwmn/p8GAA4rg6pGl1YvGu1hoKiu6vKFwjML3bdhuRiAX0dw==","shasum":"e47fc2d77be9a942ce224a2323e792c496b8c164","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.17.3.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEN/zPvNtM3FozhFEfHU4r65ouyMTVQeo99ka9gXsglAAiBdR6fHzuvIxzbsF/6/80l7OoyiLysApcFwCJwYUXBOmw=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.17.3.tgz_1516110863115_0.9520866728853434"},"directories":{}},"0.18.0":{"name":"destructible","version":"0.18.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.2.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"4dd24dc43c72303d7dbfb4150845afffbdf49f92","_id":"destructible@0.18.0","_npmVersion":"5.6.0","_nodeVersion":"4.8.7","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-qlDnME2WN2DOdkZWtvbXZfU4UC5QENeKrZL8VQvLhjLePfaV4YIXVOTgglrK+VII5Sm07JBEISC3PEDLUIKqvA==","shasum":"48ac8d9979250a90f601c338e65c645561293e34","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.18.0.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDkNmjxXPw+PLwrIC4YySbZLlHWHBG12tyIA01ykCyxmgIgIIBhh11Eh/pPnhqxCJnqGJ0eUmGQ3+u+wNiYxFYOFlM="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.18.0.tgz_1516951460949_0.06729633454233408"},"directories":{}},"0.18.1":{"name":"destructible","version":"0.18.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.2.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"a455d04e60245df1fe900ac5716bfeac4799afd8","_id":"destructible@0.18.1","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-gb8tqQrtVa1GyrmlcqFig9iCTOxE8Gh71OxREvjx7s6Yz0OEygj6NvnBHZBxDz4JMJAaPY0QGmbcTFqAoDq9Lw==","shasum":"df611a0322779bc53922f24806625dc04ed85292","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.18.1.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD44n0KZinFkHORvgmp52sbSNQw/NFreyjknck7HVDKoQIhANKyQ0sptP0wyNVIfxNGYhiVZ5f3ahZmkZZ1XGF2vULx"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.18.1.tgz_1517118884377_0.2193969504442066"},"directories":{}},"0.18.2":{"name":"destructible","version":"0.18.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.3.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"836b6464c421e6018727af7a6ba300e700bf8588","_id":"destructible@0.18.2","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-JpI3sf3Npp/zRWQZPTeCQXuYkAncD64XYwl9lPfO6jeJQCkylgwrPbIxRz0okQ5AAJXy8MV9D7qRB2y14Pc8GQ==","shasum":"c76e6aaea9018604813c70d53b2d98eed9a2f2a4","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.18.2.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCnq4f7sE6Ci+JvLn6oL6InZiW5E4NOYMe/oW1SK2dzYAIhAMkyL39M7KJ3vq5o80t0S4J9cMKKORoVdCJM4fKm6VGv"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.18.2.tgz_1517299969680_0.8482062376569957"},"directories":{}},"0.18.3":{"name":"destructible","version":"0.18.3","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"0c82edc4577646eb077c2dd3b122e3558b8a2273","_id":"destructible@0.18.3","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-0Ykf8Cf03LDDvla+MeJA4plFKqKu4DAho05BDswELJwfvYUFnVKVG28DaLN44bXwOFd9QbUkJHIwhLbZBKdjYA==","shasum":"125b31f26f746ea22df2cbce54de8b4553389673","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.18.3.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICeVCYJC/CQ4XCCohBVu7U4ns28SEw+7tvFVDMFO8s4zAiEApqJOE1CnOCA2adSHnOWxFIF5VOgTpjS9LswnbUQQG08="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.18.3.tgz_1517494128725_0.18758006719872355"},"directories":{}},"0.19.0":{"name":"destructible","version":"0.19.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"a354c9650316725587d42b82d7a2ec7f8d8882da","_id":"destructible@0.19.0","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-mIMgzOOsHqShcyn79MCb1DiovSYM9TzDpeL5VW305K5gdCgJxZQpnPshIzalTj5QDQG6vsK4W4IaE1BKn8dQeg==","shasum":"f46e2fb80f0f6ef011ae25b183b5f0804c15247a","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.19.0.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIC+gqQtWONjnNXEEEQo7AjrI9BNLkqlP1lmbmeeC2uVFAiEAxDqHyYmIxQKyPa50bP/Q6yu+FuRUnAOzsyYZYg6KfeE="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible-0.19.0.tgz_1517914515131_0.2860643668100238"},"directories":{}},"0.19.1":{"name":"destructible","version":"0.19.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"9122b71b4dfb5d4539ecddfd8649aea93769c2dc","_id":"destructible@0.19.1","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-XpxURmWX3eYztxpTd2yjZWeTJrYw71C8qVyWi8vMLB07EtJ+PVjP4t0pjqaruZAW4Amyw1PXPsEhg7nAhP+V3w==","shasum":"5117e799be2555123a8e66a821b10d8f7fe614e8","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.19.1.tgz","fileCount":12,"unpackedSize":19033,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDShV+day++7msmBtVn+wqkV0vST4+S3lQiycUUq0etggIgZxRC+AY9kXuDhu1k0/xrjULY2SmvMjbLwgzJNe9Xfkw="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.19.1_1517984552363_0.44167711699596834"},"_hasShrinkwrap":false},"0.20.0":{"name":"destructible","version":"0.20.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"fa5f82fde8387d9cc1639d786932465f1abda770","_id":"destructible@0.20.0","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-Nx8/hV4YReWy1A+uCEVE5phkB+n5Em7fuHXteLr3AYr3zaQP7Ym6hHKYLJckzKdc0SpcMbg31Xidc6qyrmXCsg==","shasum":"c7b53837d64c83aa3ebc4bf8794a332d29a0e049","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.20.0.tgz","fileCount":12,"unpackedSize":17986,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC01dl8UBwDeSQTDf3FlZzpohok9cNj46/jR0H2yRK13AIgHjqIgCzNjepHC7KUMCkKEgFTdndZoQByoJSa0RYDRDw="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.20.0_1518811042950_0.4027420458664803"},"_hasShrinkwrap":false},"0.21.0":{"name":"destructible","version":"0.21.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"4572a0f9c05d2fdc51bb6aee0a0cb58e12a0419d","_id":"destructible@0.21.0","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-PfD4bj+howt9mM+amkLB8WIvU8bOW00xWel4Nc6TpmUOdDBhAxNAk8bfBC3KhZZCqcy9NZ8Yx3G0rUtPUi2HXQ==","shasum":"b1dc48dd06814cd1016f13826e799ffe67955422","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.21.0.tgz","fileCount":12,"unpackedSize":18459,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGC6PMz4Az4UEdRDJeg2nWXeTc12TNhBn9CMcf4pqF8FAiAaOh//8Jfw88TwQso1eTQaYSIz+O5f5aJ4YYOMo0MEmQ=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.21.0_1518819351972_0.21555038641785496"},"_hasShrinkwrap":false},"0.21.1":{"name":"destructible","version":"0.21.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"1f36c5dd2ecc825633e584de68d55d3423d6bfd7","_id":"destructible@0.21.1","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-WNP0j5kA/i5P2CJPNEl5fpwUGuX/DlsefrNa4YiUizIpf3kGMd9nkwqrMJcDYmiyX6LjcjRjSrDCYJaVLYJ4fQ==","shasum":"7566482981f75bc43ccc5130285a9766ceefff4a","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.21.1.tgz","fileCount":12,"unpackedSize":18475,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEoR+920q0lY3cQAW5evmQdSQPz/r6QEK2ombP9Jsv7QAiAXJQ3kjQntD/OHLeenRBC9meFCGYxlxynrc9Jq6tKvxw=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.21.1_1518860738800_0.9203014466982011"},"_hasShrinkwrap":false},"0.21.2":{"name":"destructible","version":"0.21.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"d55a507eeeea4e6665864d96a36e75bd8de3fa2f","_id":"destructible@0.21.2","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-cvmKE2hx1zFZP0jv02+ZIZI/ulG22uplppWjzOGFS6H21YBXHDWPud6u5FQZXUW00SQfwt/12TrOaKlpB+XGKg==","shasum":"c989526218b41dd68e09d4d8746587a27b6371e4","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.21.2.tgz","fileCount":12,"unpackedSize":18637,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDUmLk0MTaCGIwiMWmn4KY1WdthZVw5TeC9CTNR+uAtgAiEA2xXhtT1aoigzk4u8m4ysmRIVMGtay/6pn1p/bwMDc5g="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.21.2_1518865156300_0.23033284790028663"},"_hasShrinkwrap":false},"0.22.0":{"name":"destructible","version":"0.22.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"7a26d4142c4e1e5261ab6b6aa576e3b80762cb61","_id":"destructible@0.22.0","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-tkBVdZ8Q6ACmKGL8ZKW6xxVVMdD6KR4m4TosFqaooOSHHIU5zYMpmgJ73FZTeO6q2mpzDeE1QLYSysUyIajchw==","shasum":"c3df42bba5e8b8f4ac2c56f7c838148d15e89e56","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.22.0.tgz","fileCount":12,"unpackedSize":18424,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIF5cA34+SLnkFmPA5OA6xswpAysKXIoFF0Gl6u8FSxmRAiAVhSNuIR48rRHM69bORw36fDpIOM1Vc73jDN+GV72AYw=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.22.0_1519742592207_0.1624793172801633"},"_hasShrinkwrap":false},"0.22.1":{"name":"destructible","version":"0.22.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"9601de3b78afdfbc731173373bb059b2640745b3","_id":"destructible@0.22.1","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-163c/bdRgdy8/CKpwBg6j/2qA5nVrTxIoqeJk9jWqTxnXMM6szN1hWXd8G4mviOPnrjpGgE4J+fdBKzUhKSooQ==","shasum":"e50b45b2693973eccc59a56e2e380cdef92c9884","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.22.1.tgz","fileCount":12,"unpackedSize":19229,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCLR/ob9XZdzDOBw7ZeQO+dxWn6nqoOQ7YLx8mtpy7jewIgGysyZfbcLNSVOy2b/OoZd8RHQDMvoTMkmOKgAqQ7Up8="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.22.1_1519918189728_0.5458677235807834"},"_hasShrinkwrap":false},"0.23.0":{"name":"destructible","version":"0.23.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"7025579670b405e6603eb2fc58b5cfba509dec0e","_id":"destructible@0.23.0","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-YnwpOhEytgSIlP70+GkCa+OpTC/neCDIXme6KTVSRMEyy/NuKH1Of7hGKF7CHyuLZUiDPYgddsR4MYx9JnTEEg==","shasum":"233d279f09c4b1253b4cf2eaccae9c530772c81e","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.23.0.tgz","fileCount":12,"unpackedSize":19229,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCAGheUIA62wwelOAEp22BWnISFPx9FMAzxB7WqdEjenQIhAMBgurF8SXqdJEhEyxrVdosit9u5MzouaZMPXcXD87rM"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.23.0_1519918341147_0.14731696650377524"},"_hasShrinkwrap":false},"0.24.0":{"name":"destructible","version":"0.24.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"78e61db267b424e4a8e1948a2fc80ebe804e7868","_id":"destructible@0.24.0","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-45BHvKrIFoDLB9rlqzgO/dOl1jfndbJkCQ0A4o8KNU+0iDy3+upBtM9znzgIeRrZnBTvkf5MHN+/oKWw8cq4MA==","shasum":"e09b9a765ecf3f83ae8be8a7d397b3199d039840","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.24.0.tgz","fileCount":12,"unpackedSize":19263,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDl6Re00tvMALU1aadFjdOO7fPxI3t7MbK0tr9ezKCASwIgXhV3ZaLNvPZOIURDVRI+shQOKPTR/8Xk/FlnmquPQL8="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.24.0_1519951475949_0.16247309769409557"},"_hasShrinkwrap":false},"0.25.0":{"name":"destructible","version":"0.25.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"d24b76cc0ee23166619dcd13e0ff7549050b67be","_id":"destructible@0.25.0","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-73C9cS3z4sRpkJqnhA4O9vI/D06kVIGBLx3PGf/mu9KpkUgbxValbvfA8Ty7gvtwJwQ6oscMNXFgerIOSi3ZMA==","shasum":"d18207dfbdc6ff0ea757c93cb4821511480be2c3","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.25.0.tgz","fileCount":12,"unpackedSize":20466,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCBG/2TGlvioCl7E6xvlYbYuyfyhdDAeBYSeRTcJnbp4gIgQdw98x9TwVio415GTX4ydkuiRkRrq3PimNMVNGiKAhI="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.25.0_1520360892105_0.5527936327277565"},"_hasShrinkwrap":false},"0.26.0":{"name":"destructible","version":"0.26.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"5.0.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"f2a1ec298e25e360c63278452918e062b3fbd2fa","_id":"destructible@0.26.0","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-rXLMKrpBxplcc178I33KQu0kkjgXIxJS7GbExAD33QzoCTHRYM6tkRv58YLUQsOuzuNQCQh9+cagp8Dw42cuFA==","shasum":"a40dc87f1e8974fa785db6f34fd49e279f132fda","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.26.0.tgz","fileCount":12,"unpackedSize":20576,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFHfy0rw5H+ADeV4YAAI1baGn8NjyMjsuK+e0z5Ao4grAiB2LKUzk+zzCLgSF/S6kz4SYPVWuR6c0JHozl1cSmlKTg=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.26.0_1520434826199_0.08163648114167299"},"_hasShrinkwrap":false},"0.27.0":{"name":"destructible","version":"0.27.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.1.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"9b8cd0ab4209c8bf740a0daacbc7dbc1ec52c077","_id":"destructible@0.27.0","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-C5IS2QzWaDgz+LmTU9t6tmjRbojFInFvfaB2znS+cXUZZGowu0nyNcqk7DkVbJo9yBoOufi4e3ZXM3rrZ/Ch1A==","shasum":"34ea4f1a039d98584d93a4e407dd693bb69ed8d5","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.27.0.tgz","fileCount":12,"unpackedSize":20424,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDP+97/gMKrOaFLBYFLTIA5NBtCEZwAZb2yK/VYCv4f+wIgQ/RxWPVPB/Yjv0u9naDDsZXC8bvyBGcT+oCsh+5bcEg="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.27.0_1520923127780_0.011402128377754561"},"_hasShrinkwrap":false},"0.28.0":{"name":"destructible","version":"0.28.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.2.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"509acb39fc5e08aebae9d641957d63c9b173952d","_id":"destructible@0.28.0","_npmVersion":"5.5.1","_nodeVersion":"8.9.3","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-unxn4PXc2dGJb9h8nO4ZYWV2C+AgTI3tErdo7DTpZvW6698GybnG03cX8GxivYqFL5R5pvSFf2d7N01mbI4qkQ==","shasum":"bcb67863c1eea1b946367dc9b3073b9435ba7086","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.28.0.tgz","fileCount":12,"unpackedSize":20424,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa2DzbCRA9TVsSAnZWagAAVxQQAJ7TwVQ8bS1PkzOijLvT\nmQ1pVm/685pEJk5KOW7tR1fVbflDG0jtU1tVvZSFJb+BeCfcKqWJUmE8DCiA\nM+iFeJokkD+mGoyndOZsINVeSB2Qss5uf3otuREmEd5l6AhvFpMTNUk1xIvh\nWgutKptHcAmenR83FXXn/14OKzgY3+ejT+9DXgCbKE03CGpOuvCFjdV/Sdr2\n7v9gTurRXC8QTDicdwhVNERLSjcHfua4VeFlXpa9hghqMLBJCFFA0c7AAZ7g\nnPGUOsjFzFlg8eZnVOrrfNcAR1JHHHnQ+uKRtvNF4xFVq4BIOGg6h6jgn1UQ\nFBdp3rld7GQspLISDU7mgMFOeDtvLy9xediiHOlI6Swv1EfE1Ujq5V9qME9b\nkraI+YxDHNoConVjbcMB6RuLRs/WjR4OYKUW9mkF5CXcX2rWMy2stCw8mat2\nRbsqWdNlI+lPA/wd3lEYh4HedChrltNytDqCl1XGejZVH4VglsPemrK2z/eM\n9SNqg681aIvNg+KWndClscJUByExOoUaG/EIuJamsUK75EGvvSzyN625nEo8\n0+wWmOd+8ylNiypS3WFaqKBtovDgQcfN+HcmrhPXUliYbdY2wufjXF6wjsUh\nETxP4lDQTn3p9d5HiE05aOkQb0qj2SVV604ZdHbOmgpMVy8PpN4rM9wBLaci\n9G2I\r\n=cY+/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCa9nIFRGPIqOleTtQoKfWvldmbdJ/KduJ4qni5IrFsbQIhAOU2wR/sJDJPct3/NBIH5mTMYH+zYLLm8PCm4MiaIkJi"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.28.0_1524120794832_0.8614078247652786"},"_hasShrinkwrap":false},"0.29.0":{"name":"destructible","version":"0.29.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.2.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"b729fe748f0021a68409643d561cd7a34e5571ad","_id":"destructible@0.29.0","_npmVersion":"5.6.0","_nodeVersion":"10.2.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-XB+la3YbOk/eEafoRYMaCjs595E77sYWwhPTo6atBF7A7MV5X64MvVSNzke0FSRz/jW1pguNB8ikYzOA+T2X7w==","shasum":"fd7c4b3d52f8a012e0451013787d504013429912","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.29.0.tgz","fileCount":12,"unpackedSize":21431,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbDvSvCRA9TVsSAnZWagAAZJEP/0KfHNm67WYQ2/0j3YsL\ncgmKHR2OlkZxXXFSrhlPFrpp74EU4yYkGZb9vaOaDrENqMjUyaU7IhmrxbfB\nmg7bvSATsvP559ufaDmPwHl9nU70mNIHG5ujB3pL1nktQs8/aWBV00BgwE04\niXtSDNjI/CDtSxPVIZiweodCHoWy5mJXVCqMHud6c6DObp0Yjf11dTWdbp4H\nN5GPVGfUG0OHYF8uG2KobC8RKPK23IWXpImUdmEei3lLXB2WDlZiM+fcj30U\nPl0losCs2eVYV7x1q76rOCLt0sLsKeqeVGD2CaSeMHCSA5nQ+jcni8ZVl/R8\nbIhaCGIvO257gn7B5yL2Z4i4kywormP/WfSmb2J4X2rF/gWYkrESIXgHbNtr\ndHGxO5ZbRci63dRniS/pJcRZ3w2n7OEHNAIiv20C/4lExaL7eMVv4rEZVMvr\nduT+fos+JFhKfRoEP2vJG0XdJdo7HUJpwkZPEb2LFcQl5NboVCNHdLtSqUoz\ngRUqB0aUR+2Tot6xwTznoSzw1zKB/gY4jhilRWjY/knABzzTjBGHBtvApRQg\nIQieKAtXuLtCFt064TqowKaPVQK74U5ScgzWVE4lZ40fjtHCsBEhEytj9mLd\njAtVxfYVGfK4yb6D4vTDMiDdwG8A9rksEhP1Fyn8G0L/W09Jlc0zaYT53Gb/\n4pQO\r\n=fM9g\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCHmD9A3sChDqXc+b6i6Rwi7ONNrFIOLVYxvWO7x0SYqwIgc7BPu7RiOQN/vz0/hiuVoHQisyyQ03APwHl7kmSHDeg="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.29.0_1527706798793_0.0582403200665893"},"_hasShrinkwrap":false},"0.30.0":{"name":"destructible","version":"0.30.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.2.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"b735f8ea7db31df824d6dc3760e101e9dbf29143","_id":"destructible@0.30.0","_npmVersion":"5.6.0","_nodeVersion":"10.2.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-+WB5RIomNxGMa4lY5GLhJATCXQy2k0DKr3Rr3rrZgEAW89ic1bKIUQISoITDCW4gEiJxyoLS9BGH/PZQSbWrXA==","shasum":"d75447ac1de92a4bc4eaecc3ca74e6da986444d1","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.30.0.tgz","fileCount":12,"unpackedSize":21431,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbDvVGCRA9TVsSAnZWagAAvOgP/AtMwaQ/N5J1HGFlQEaZ\nCe9fd48jQiUdWMmZ1m2X4OZkPa2fChsFn++4I9LxgCqiXMsmC6vEmBykNHxL\nWmrR5HhSp3qXooAgWjodvHv+lKeK9xsJCGYf+cfghd1MC0vsLVXUKCVG0vdn\nf6GZrdhfKYvnRBxwOi9JX/Oe64zvXzw2v5D2LYh0BlhZxjezXmVrB/pWdLrl\nmwTcuxpadE55LBGHDxce2xhDZmO0puR9Wz8mOmshJiimqmshgsxwIhg9rlli\noIGpbEiu3I6WaS9WgR7eXX3dKYoG7In7P8rCXAWJwnGH/nU9GFg3p2kw/6TG\n9HdSKsB3/lh6w1Tj0VxowJXdxLWIbfPo40BY9eZ0q3fHod4n+hN8N7ABS6/2\ndCRON+juflDz2ZmskQEOUx8eTGeluwiGZbxnMc1AeoiDkKYaYLDwVoITmegc\nrb+7L35GUaqeHBBjDl3RPHFxtbLrzRo+vDzR//qt3wvsARYNid3b+dCXLzwO\nrhiScACdloZ1QGGlp+NX1YMUg3cfJxKr3q7A25QN8F30n32Wzlk7TnIPlMCW\n8MOxNAU77Q1VTLwNrna4KASg7UwVwwaLe9aWewiRVFa7QWwu0+h97dxBXExU\njeLN48hoASR1j3zXWm+r/C8lF5/yNhcREU6W4LNhqwVUJH+k8/MakSeGkv4s\nL9+j\r\n=3dGP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIC0+vgvrjCTqXpKCFIOR1jzLT/X0AjdONwZ30e4vuEScAiEArUsn2xkEf7tXNeX1F6yS0P/Jr0bf7/qPk0Igmh/KwU0="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.30.0_1527706949969_0.5792746442669876"},"_hasShrinkwrap":false},"0.30.1":{"name":"destructible","version":"0.30.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.2.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"3.4.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"c6f21df00de38a688c0a77eaec4b1bec90078aa4","_id":"destructible@0.30.1","_npmVersion":"5.6.0","_nodeVersion":"10.1.0","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-sylk07BATBlflCEu+T3XncCY4b6GARI2yvudrxI+GD2lWffqVUZU9iZaNAOYj+rvu1BJ38biaTZKvbIdZE4AOQ==","shasum":"e708656d8e5056f3d1e852095933279ae21e1717","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.30.1.tgz","fileCount":12,"unpackedSize":21423,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbFvfLCRA9TVsSAnZWagAAgZoP/iSvEKdGs4tT2SXPOuYA\nf4VSY0UN2Y1SdeAO9Re/PxLAAwDpeiO5mTbEHUDJRD2zBFJHJdfNp/LZ1N2k\nBWhZ1VfTrXDzADT+mxedxq4xMFA+PKTwzNVdsCNuVXCMRcvs74RORpggSuOC\nSx+TQUQNdy7CQKdpaUVoYUo5XLt6WFM31eAT7SnkS3bDAB2pOMA3VnIJqcPb\nGfqFL8YsP7ylDasGB9SpZexBqf+2BwYQ3JRECGRSEe8LmnWo4ifOD0BeVGyY\nJwl5/360fd+HwQwf+i6+zA84tx2YMfFbWCxEgz7ND76F4ML6cHo4y0DZG0d/\naa2QQ3DtUxUE32aI/QlsRn5wP5HbWfyYSAhAQFcYwHIUCoV6EvBvIPdfuJVM\n4nyxs9zWgQTRDr00kbw1IRIQwHIfdQSL3lIDuSv2bulWmTdmjscpmdBYG4Sg\njWVYjnXE9Ykt0e9AFR+AZftlV40j2H5Cg+BkhOAWivH7jZVOPBtVWzJuEQRJ\nYbqnQwvXm4Yqdg/N7d6AKa1FKOlj05cY3ZRuJrtbvikznIfCDtCN/m0+YwbP\nbKENUx4ZI5ItwrwkFxdf2xxdA+F321Wc5L8cgUd1Kq1pZOFr/FLWzGglZPTN\neVZmmicwISLYoYCreD3vpDO6Nc1XnYUiCFD0kqjlpltO+7Og2gSnmLP7E7dr\nnNUI\r\n=9Z7P\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBmlJ+VFqIxByk4wb/0CAH7SiEhrkI9kJizovs5YxFVyAiEA+F1Wmyr0lB6My5rM8I1jRKgWwfnr2SwllAVMxGPCpUM="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.30.1_1528231881703_0.3924357292908667"},"_hasShrinkwrap":false},"0.30.2":{"name":"destructible","version":"0.30.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.2.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"1.6.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"8dbc5afe6678e54513ac54249fb65864558d2dac","_id":"destructible@0.30.2","_npmVersion":"5.6.0","_nodeVersion":"10.1.0","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-s+f6YmBlCcAv5HkDqM2UOYJNigvtyUrhT4UMgKnSHlzWI1wFI8sEqmoo9nNHWqeyj0xS4E84gJfGmfxUs3R56A==","shasum":"ba2c6474abaa1f6ad30a224c312e1fe670b0394b","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.30.2.tgz","fileCount":12,"unpackedSize":21423,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbHhfxCRA9TVsSAnZWagAAR+UP/20aL1tSXjEaSkS3WW0G\n810M4Z855vqsgPzFS/ZPFpIjdLoVLX/yK2y9U5rlKpqLHUkiq4rR+ZkeFEVI\na1gYD+S3WvKTC+gJA53T7NKNZcMFe0xofg+t63+fDJ9Efvxg8ShxnXyBoUYF\n0lRpAswjtE6n+2vIBTPSLWdnPb0mgtoUuDW5fKAcLbHp/AP2bIo4Vqhv4acq\nOo4FgVKoIFHdR6NglEh9gccke7evhBwZFrktqQKSWWXTptrvt9rcbZPYY8FU\nts2PnWGDx6R6uzn/L6spx/Sa3cVEw5vXA72UQ+FGaJRi1WqaerCeR9uWu4uR\nlg7HFWBJU8SXgsRfrPMDBWPG1grql1o0swnXTY8I9J+bkZspjmUByrs/ed+8\nP5CACEbe+reG4Eu21Jkf573taOacLppIKR5qGKO+uU9nNHDYVGV4+1wo3JOy\nDyQ5K1sOh5TN9l3bXdmP0VdBUA4OybECh52AREc052qp8R/5p5U4gwndgUPc\n3oGM7ikT8sBR6awKZZrzpi4riJzwKxSU2jl64JK2/S0xzWvjygjwMZ4Ke0Gp\n8GoGOfCYKvSHI+dvPlFNsd8mt5qnw0sQdXSv/cqSPI3UOEt+k8Q9CGkBlo5X\nbi2GF9uLZ1kup5Pxc+GoAHK97WyWsU60CAWgn2fpIfORBsgwLTe0pVsxW83w\naOg3\r\n=hPXQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICgAReOKjdVkq4T72tpavZAjwzl1R+mU/8T/ZOqQOCVYAiB6z16eYBYpY1FO/Owz6TIYfzsSx+vTf9rsRYQO9dvROg=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.30.2_1528698864845_0.8258639323072137"},"_hasShrinkwrap":false},"0.30.3":{"name":"destructible","version":"0.30.3","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.2.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"2.0.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"81c243fd71c0b944fb39ae22e6ce6e487238a9e7","_id":"destructible@0.30.3","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-KuK7X04jYguUJN0FjVyxSC7Tf5DXQqlbcZbhF2TD2vYv+Zk3q/NSigb/EUTXJgG2z2K/kQJ81Xrbaeix5f8beg==","shasum":"d14e3f80e8ba20c28e1bdec84e44f7328101b0f3","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.30.3.tgz","fileCount":12,"unpackedSize":21414,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbKVEJCRA9TVsSAnZWagAA2s0QAJ9QRGEZgD+fVQyaGfxa\nig6Yop/9HN0bqijBJ1ZaBjIM3Sn4AGYEPXFIl0Vf2LmUltkTbsVT0lPPqDjr\nDxu4JKfuv9CbnunBELyLTFMHFJaI86aC7kgkuOfosUGwDmgA4QPiXkAUnBJ+\n7wZRLw12sxhVFJj0I0JlqiIh5Iba3ZHyVEU19DAsxVrGRoql+dX8w5u5pQ10\nE5EJCALxiJs+DD4PY3n4fICkI8EJTZRx5spx+j1JLhufHCI8t+NsncIfhBaz\nLAPnWDy4F2FVKDNzWBib8O9P6TA6eTa2xjPVJEfFqPspn4Ijcs2TdXw9myFc\noDy5LRba7JS/zqLu1bc+FEUSPG+Zhh8nLsSga6HHpaIWa+mK4cX7hIJsjEix\nJR+eerz+06x8RhlM987vR7hGp7YDkO5Ix0XEDf3a6feTPrySoE64iJVxFsRV\nMSev0PszXJ0L6NE6cRKikBTq+TDNRHfkACo/r3EMTPPNtPQcf7fxgPz8ZtgC\n99f8Ce2RVbYoOPQ/9r6Nc3zqVD2eQcU52Ye0+p4Wy8H/cw35x/WiL1tVDhMK\nb3AGXQMTbu1MyBU9maPtR5joaqj45SysQgoTBW0a1sA0oIhEImfoPYg7NAfA\nQ7PZ5QUoHHNiXppwRNvDsB38mCYXhodoXISl0ESirQkrnkPP2FQhXzi/UosJ\naLZF\r\n=axUG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFzzHVe2JwA4AAyPTbg4GrHS610RlRc40yBgrc9ETr2GAiBfscIcTPguk2HvaSmQq9vT1fvusm90ibFdWionqb5Kng=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.30.3_1529434376474_0.5123457137218073"},"_hasShrinkwrap":false},"0.30.4":{"name":"destructible","version":"0.30.4","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.2.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"2.0.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"4759fe881f612fae58756d77bbad4c7ca4330881","_id":"destructible@0.30.4","_npmVersion":"6.1.0","_nodeVersion":"10.4.0","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-HMpih1f6Qgq2hNb+7pDQxxqG4cVVA6kJkGTUfX/thQnEHWWruL7a1pTiVobNwwbUESwXuO9SLu+ZYqKqE8zpKg==","shasum":"566064b3c32e6a72bcf6ed55ba479a7d156d8795","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.30.4.tgz","fileCount":12,"unpackedSize":22251,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbND5nCRA9TVsSAnZWagAA9WsP/1P1c7JE9Q+3WWZLZRiA\nMaLBIAf3tFO3pGBDD0p23p1tu85voc29xUDUkb6QfYkkscgKBoxSySBU1QT1\nK/LZmEv7iXRjiOeNng8vrKRlJ7n7WGhBK+jfarVmrHvg2R6Y42O0fUXlmbNa\ndtOQ4I9Faf8O0WUrGtSUm4hiCAY1DNBIf5c8PZmU/OfQk9ipQkTGLiRo3Dku\nfXkjTCuqwxt4GElPaXHD+EoyfIudsSDev/rpZZlTSca+a7lEiwiX6HN7PI2v\nDtUkMbas/ChR3Au/gyrYkaQr8opKN+Rx7q0/R//4/PfBwL7aJN7PhM97HtQj\nmGWILw+XoSxqJrY3WRFS2LRMmzywSCCBZEgKBFAxPjNGm+q03eLWidEiljhJ\nCYGTzwifxXAwsLvo8LWnO+xCsQdUvTeVtuyR4f/h2GYKPE7y+2nWM0TaM8ob\nba7iC0kXpNQv5KG1fEE/gpLIm1BgwucFmVK/Y5s6NOzITggZBDyL/cBawvdr\nmHhxvN0yYwONG6mJNoKmnrAJleSfahbJ1+BM8edVBq9CM1eX8qac3JPWNCsr\nB34ArL+FLc6bx9HUkoeO7LA0BLjcqeSYDmTuFq3n8MRQSUOiboeM1pEdA7LZ\nrkThBi+Jrg9GFtjxy1NRoSDZECurzv4FLSb1xGGImv8jOtPDhbSsmFZ6CtQV\nkS5B\r\n=md5w\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBNXLj6LOR3QsjH2Q4HWSQhe2BItNInQZpfkJThYvee6AiEAro89T+hqE6OPRJMRj3ijY0IabjAyCxWxPP00dIie48o="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.30.4_1530150503167_0.7061222388695447"},"_hasShrinkwrap":false},"0.30.5":{"name":"destructible","version":"0.30.5","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.2.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"2.0.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"0ea7a0a5c1674ac496b52cbf01e9ae9d90873e9d","_id":"destructible@0.30.5","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-SCPICDT/USqp86h48ulzb7wdXOq8rI9DBeTX0q//RKBSbZvg3DfuCZFlLB6TSGEfukJOvFouuwDUeXg7mAOM9A==","shasum":"b94f5a60e0079881d571eda36feccfca72985316","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.30.5.tgz","fileCount":4,"unpackedSize":12092,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbWVr0CRA9TVsSAnZWagAA9PsP/1/Md2kSsUbq1/tdoxV6\np+GXtvNbv8kuzPxFEE9gtvI8dw7MVcTvvV/qgYSFpj56tJklQKoY5w72YEJ4\nkrHrNX5zUogCtTKOvc1fsrR/Ggn6DSJRouNC95fhrYKrro09AS3eGnlHuu2Z\ndxVr0A8Dla/QsbGw95N0qc2d2sN/HmP4x4xyLBZmCI317VyW6lFTo2lmVMEl\nPIBvxj7BKJhRyo8TsddjZaMFvCDLIFhTC+rIwzsGIrAKAoG844E37+lGB+ha\nQQBG6syE+ZzlU/uXFhaetB94BtjHhTOyGjB/wS1HeG7KIEWYlvCtPCerLmFN\nY21xvwYiPGNAZn+dSdpFMsoBkyIVsxFl3mvg5hoS5nWnZeM3n3w6j9AAqzRU\nnYN/dSztuUT2sP26pU4HTyz2oU3y3e3MiQKqETRJ9RvjFsLR4z5Eu6QfVKM0\nTAoj6QgWki60gP7yOxMBOKWxl3HPrC/fCsMT0P0BWrlt+xqtDIglqvM/SFyc\nZwzCJrddyMpU2d4zBlu98wNdCehOyAs4UGU7k4bbHaRLLBTpnh5rx3fpgeVD\nmdBi/fQCVsul9auQsR3JKUwSBxN5pKKVa/5MJ5/v4KfR1Jq+l4rsQPRqIt6M\noIIXNmRvhusIGfPPBQf8uAPspsxufYLmUzBCewKSqjGyRNmigJ0ykH7RRY3t\nRrRl\r\n=7QqQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDjr8MdqyaPUSZwaSo1ve56CZiMUD19YSANyh+A8srzLQIhAJI6S2eeYvd7ZS4nB5myjHWIXh+irzRTboDy1IMwLXOe"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.30.5_1532582643874_0.24402505134709984"},"_hasShrinkwrap":false},"0.31.0":{"name":"destructible","version":"0.31.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.2.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"2.0.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"565003f0f93a0f2459e9816cc20c1681ea786c82","_id":"destructible@0.31.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-tT2pvVzZRyrS9katIIgtEjIR6p643V51vnJOIs42AdzbYL1pUo+NBPORrkeOHNVZ2QmGEs4X3I6ICN70yHp8QA==","shasum":"754aa6f011b8dfe064826e898630a6227293d784","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.31.0.tgz","fileCount":4,"unpackedSize":11903,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbWrSgCRA9TVsSAnZWagAA5wcP/00VlQeUg/q0v9aH1CW7\n1/eRlI+PFUvlKj79t3wSNNi6CHXO5s8zcWZDTZ38Owfc4g1bFR35BkfmWzBP\nAQQAqUfWvhE5l1m5HFfwRS6BDDgMWzZEZXm9A0DRsft2jdwICzDO9PwPYd8H\nxFStA9KHZjchrEzzVQ8zuFds/9uOf5nxRzrSCbD+r/rUDqsyGj2YX6YqVTg9\nb78M1+QtrP+F72fpcHJRUC75N3GJXw4XmPXMo0GMlDhokIRF28QU5UbNm0oB\ni2Blp2pZu45yWaqUGHsDgzHpNWbqGlpOd2yPa5VoBwLVpfkEyXTr/sjiwnNm\nPDytv3hrp/a2+lYq3DMhIu09Qi3fy1rDYDM06rxBxe7NkbPO/XgSNVc9lxOt\nHfEvdem5+xSh3RRJbC8OJ4L9JtZvC6IHTmYOuU05p/q4q+rxspPFRMyEJeT4\nkOwfWE26GL5K/zrnmIHvYlQEiLEnsKTmCnFv0lepjew7xdssZOUC7494uiPP\nDVlgVkOxSMibY8f4xfDAMsdnVqmsn15AlK1MIozr5XhMef9vrhSMkiP8HNka\nJTDGjsDVU8D/NS9n1o3EiE1r5xDzCk1Qk6gSjEAZwc6El15++C1bhrtFMXMw\notXCrE0wu0mSexu+y8VA+G6hcCXNlK87DORBQPpr5a5K7fypwA/0Nwjz1VBu\nh/x5\r\n=yBGU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE77gOpgsBDJ3WEeBkJrdFs68IEzN8JHpWvVi+w4ENCEAiEA9ECyfZ2l10W2xo+NpE7TWvm8PByZXRtP1AYfUgvQqH0="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.31.0_1532671136152_0.893499853396527"},"_hasShrinkwrap":false},"0.32.0":{"name":"destructible","version":"0.32.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.2.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"2.0.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"025fe70925166c5722b1e00f12079feb51c93460","_id":"destructible@0.32.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-Q5c9oqewsKUS0uH9IoZmlEQM9Exkt3E/flI1GR5PnbmQIcvOOE9tWFX/ynPfnCqZryIk3t0twZtm47WgcXco3w==","shasum":"f1f1202dceddd499d0951fcc50e8691457f34ead","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.32.0.tgz","fileCount":4,"unpackedSize":11291,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbWsqYCRA9TVsSAnZWagAAExAP/2xPWhsAZ/YKgnnCRfHW\npkL6ut+W0p3+pCu+1gy6i0zXXlm3A+lryjq1fDV+Eh/iVFIbG/RSTxHbHiSx\na5ogfePW2FlAv8o1Ym9XfUSBLuMzNkX/x+nb12B33xXlo4W+HA0x2+EgNfTF\nbtUfcSuU0BEk6OGn8gM02aeSfl5BWHMFa1/YIrbJZcwZpJpBhVnKeJFVlfMx\nsTW7UwVt/k+Gp9jRvEvVVCNubJTSN/xH6YerRFRz8mZdLOXW693u5uEJ7UKI\nBI3DXUEJG4n2KWYZGHuMlgTHg7CT96YYHv3TD76vfVE6VBjUkN1CTvq+Z6js\nOJrtJ3o8EBOaV5eG/Ty8SyhTS1AQEbSGBosiFIGsnuNE8rAHp+RD9cCRbidr\nbzXAzFP2MPXWwCTUntU+z1sfwt58Pn8deVa4ZdV2Rn0bQaUt7GSRVoaw0hFM\nw49bKPhs+WE3Xykj9mQQKV0Qxe+B726luANx+PICUDzvhkyPFGUvoairgNhN\nD+jHLiL0kYqqXKbhx/tocrGz7hntgj+9UGwtRCioDAQ17utkynl8zHIlH30N\n65wxIEzGjzPaogVhlXo1O+TqFeksOUNyplkA/fdCvIbjIsLh1i7Xj/qVs+TJ\n0WZKQ0VXIGuWBXeMyB4cDhmLhvjXKzQGhohJLQkjSnd0JTLCuBPp9eefAPWn\nF/Ug\r\n=xDoQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHvJz1rIoWaSuiZ9WLUbLZ7idQqGznJVLx3uR2XiTxhjAiEA8C3L7r2NCt0A2NOiEeaePYo9u4GkHgojkxZhQD4hd5g="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.32.0_1532676760606_0.6804404702353901"},"_hasShrinkwrap":false},"0.33.0":{"name":"destructible","version":"0.33.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.3.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"2.0.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"d28f9495d0d00ccb1335d636edd2dc0d420ba3ff","_id":"destructible@0.33.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-U9S2EyKAeG1Y2Ai+hhV3wOLDVY0iMLQDmgxSydXfAGRjkgJsR//ck9q85uVmCR54Kdfyu5ivnDGXxvd6T1+rXg==","shasum":"9c334c69cd8344e372f28a9cabc402be72471aae","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.33.0.tgz","fileCount":4,"unpackedSize":11245,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbb+llCRA9TVsSAnZWagAAC9YP/3EYCABaW3GLCzav4gwb\ncXSQeQNnNxn8M+EYKj3pgYJdQei8Vm40gG1pQ9XGzMEKuSzlrgzVHfd98/yo\nUHQhYd7q6sdhMn/elvYd+IBEfn3D0sMXcjHaLu+0yQJQXdmi51Qq43C6w3pG\n0XuBvkfQfkUBu4seKh4TQ5yuHI6CWHWtHtd7fRjZ5fBtVjH5PuUXkZ01PRU/\nwGGY2yCUjAC6IRRD8BddD6fbNU6w3OuPybtELQIXOvLrM7hFCtABwB7omsE9\nN3kHnhiXy/sKVThAxJCqI5mOIwDGin/IwyQR2k2AQxts7AHghZuquaoi6tUn\n/oIVihnzJ+t2g3wwe5/EzAa84bRxsCW2a5/KudCSCU++ueyOqligIquGmVPC\nuPALh5jwDw85mgFjc4QsWzaO62YOVj0ttw/bZhFf9jJKZxVfjan+54dYb5ZS\nkKUsbRFTIjerwiy+OPl49nxuAWAUVFZbgjk9/siwSsh1O4DRKgs7fFWpCv4W\n3+larGhCrL3q2rmg3orh2wo/RXSuWXlOhntTw2Z93q0IULcKDXctm31Vw31T\n5iMAT7T+3FDMmfXrASxFqU92xkbqPKuLeMMiihhFOIezVZdbycLzKaB+AUF8\n/+Itt1DZkfC0m+NVxfwfWwkHMd0r3JvsRgfL+Ig8LOqPyACQWiN91ECHqjsz\n/Qsm\r\n=2yy6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBOSadID2ZpYFYkfey3YxcKR1yV0Hxj9ERXYIwj2aAKmAiEAznIIPU5kzrILtJD6AK9EHSLJSaUJ8Xu0hjvdbIsqSog="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.33.0_1534060901336_0.8523542597552878"},"_hasShrinkwrap":false},"0.33.1":{"name":"destructible","version":"0.33.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","extant":"1.0.x","interrupt":"6.3.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"2.0.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"7a126eb296657f723f4277555775ac3f1180a85d","_id":"destructible@0.33.1","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-n5g7Ji7zgM3S8M7FHRJ/mMr3ilhSv+Nb/UzmSuKQXfv88/J7xDC0vIdziFCkLIIUvkvfklC9gEasqGLeXKT2Hg==","shasum":"18f6473d73db31bb91eb0be00e5512054b736b4c","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.33.1.tgz","fileCount":4,"unpackedSize":11388,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbcS2pCRA9TVsSAnZWagAA90gQAIQ12k60LFn6zY/k8PWL\nhwhP98j7RVbawbD2Th9aO6FI34ZPI6Fb7Y4znwuY6iwytDcXwpi0iX0mh0rS\n5jl0e/MB97eku0Q5HvqGF7+tj8Pr4EdMexU63vvbPU5JkqCw2vsMu4TkJK3Q\nP5LwAeYwSbU50QqByeLVeY/TUO2hZHHjcslnMYHYyam1KdmRejmgjTaApDkM\niPO9LxyP+8x/NzXOQzwRbiIDruVU+/DtzH3OLzyK1ZRwi4OYymsIX6UPCV52\nH77Z8Wj5aYESuL3ayyeFVWjAfzL6He+hA33zoCG4iAmrh90DsTza1pd5Ol4V\nyNn1WYT9g3vmmqdgVJZDoUzLTEih3SH4NUD9iAYSFpEnItmB1mO/WGhISYD8\nLHOq9MvSOXhwYjSBCZpnX9LV4e4b6Mn6Fp04jgrtzDTFhPIyq/bk60DF9d4+\n0dMrm8ER+GXeSI5vrglWALSprid1mOaKq53xVUMBOlTjEEDoMFjD3UkptJxl\n80p6N3HvbKpSJBYBI8E+dY9u8t00uf0iIA4axLf8oWUm6zi2hTmHhQ/hUusY\nNNqDfs1fqenYu6CTr/AbT12zJkrmUq58Zqzvmpnvi2KKrMJ5PzZ8tJ0QPPte\n40Nc3fl7QEfDzj+olbm5u9U7/J/271x4/N7RfE4obGI0ZkLLQM6POtQSDM3i\nZBhr\r\n=uJjB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAR0/mZZCPEcEMKWI1ZoOoQKdNiip3gLSEPW9BMCQoEKAiEAsJfhoHZ9e1yFz75zDXNFahCk5x9Z2Rzl14PbQ6qvTtY="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.33.1_1534143913275_0.46924048088071557"},"_hasShrinkwrap":false},"0.34.0":{"name":"destructible","version":"0.34.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","cubbyhole":"1.3.x","extant":"1.0.x","interrupt":"6.3.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"2.0.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"e8b1a682d06a750074be1743232ebb04522dcc87","_id":"destructible@0.34.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-parbyUSqeXMy2HuvWhVT7xyEhCemCAEFklNkSUbzslPFovnZXtjXBqt9b6JxSj9GMaZ4iKbnUKR7v+Gp+7QJhg==","shasum":"9fe570ca326727a9acbfe8891b43e2f0af608cf5","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.34.0.tgz","fileCount":4,"unpackedSize":11813,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb1eDdCRA9TVsSAnZWagAAH38P/AmVx3J27KLCIqreGazm\nBRD4Hv8MJeEPD5aM6fwbiy3G8mUy3fB2JXzcdmsdNFGd7Z7ErW4W0G+49ndC\nQYwubw7kmMDz43EMx1ibtKCHcs3jbrt1kcxot8wgVBkzn2fXYraSfwiw7YhN\nkmgB8zRMQjIz04XM1HeeADHnZwyBxQbqoP61vGaiTFJDBuhsBXvNZTAV/4FD\nUG6EozhP8c8/ShlwaDlr13ykbMQSPE6sl7CrNQNLFBV44dpeGzWBxZ4u1e/2\nZqXWdO5EimFcwc5ett5MIRFinSsECghLi6LC2d+dLqDURR4TVmPLHmCw0H8K\nJoHCJrdzYKQyUz7KPPjfjVjIJoOWRObbJye+BOp4OKy2Vfg2NmaI1y1R6imV\ngzK06GXQyXxuP0aKh3i2VXU6mNtE3W7913CJbTKqn6EUY/mU/jPIRasU4U3h\nXnCwR9QaCIYfIn/Yjpn7N1oAh0M4Eb13SCGpxyCMUExgTBpdt1g4DVJgaBvy\nyyLhK/th2k7i/0AmPVquiPwCBl/HxL5AGAP/Gn+szuEJPFUmKsdK2dMhojj1\n9kpO24dqEoQ1ZVy4pqa3cP6s6hSiLtxBXgmPUK+qDqAKjZbMOnz2v9ApPWwG\nd/7StNP7UXiQwq+VBFCZ6l9Ns+g6lA0ImeDwht9RDVDH2GZOVwjt91pCOvHR\nfuub\r\n=2B+X\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAmMScoREmHMNaPskS9L8JgOl5HknCAYJzKRQpWlp0Z2AiEAs2EW6aQNx1mKvCi24IOTvhpXRe0MfYYqDEdiRVDy6d4="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.34.0_1540743389082_0.958041899715109"},"_hasShrinkwrap":false},"0.35.0":{"name":"destructible","version":"0.35.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","cubbyhole":"1.3.x","extant":"1.0.x","interrupt":"6.3.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"2.0.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"9b768b6bb94eac1153edf03dbbe9ba3a324c33b9","_id":"destructible@0.35.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-5jM0HVNPWHtjqWEFSs2vy/uk8fWiciQFVOOwaIrOkY95ttku7yFTF1WPu4fqOudKWUeKWp8QrBJupI6/RdQSmw==","shasum":"5ac6c3db3b898f220bab87fa6ff0776f40800633","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.35.0.tgz","fileCount":4,"unpackedSize":11748,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb2J9BCRA9TVsSAnZWagAA9oUP/0A7JQCs7kqPttVNDSki\nAjrJL//TET+7rDHDaU7E5g9lSyG7e/+ZotGHVpvxld0M/SZoX9UAr11sDWKB\n1HBG96Z/7W9P/1yOXYoZd1d6hTHSuUEUb+EwMZpeGhr/+KhpRSHPWzQDCvbt\nluF/EEREldoUu3pMKNn47XMYAW2g1AZLMoccQU8ks/mgx1qxZTlVfnJh7jZ/\nVyD+lBOGYwoc+KGt/AdX+RBGbP8MI9sJgj8JjgPE5KwBjULaOqChwVbR66/X\nZwZg9XeI2EdsMfGeQwuu9JNjzIQ/3med1X+PW3BYk3QYUgZovwZwMxV41FQp\nZpOOTr8xu4HZf1+9ZgR+IzzkZhjHNn0Yn+hCKd12mt1lJ6yBpGsLLH3u802Q\nyn+SnDuilgEKEI0uxtwsFk7sxpyYP0LpsDdn50ug3hEob+ptWjMwZyvy6iIi\nR0dcBvHbAPujjcYLEtfjnKYoQNAz8vZLERDZ8b864tPVDb6fkijGfpE7lkkT\nniCgF6Cqr7WTOubAJk5BLPWJkUYpiCvC2qQrkLnCz27YP0Q1cURqjqkymWeD\nu5WMq40KTwhUiOlN56+rpPz9+q3Uqn0OsItkMT4buVYR9khkUDVveVk1VWL/\nh4Xrf7AShAk1Lkdo+28R3vgjZsN6N49mFbEQmpwSlDCp3TMxgY2ZGhrPBKq1\nHVwx\r\n=EQD9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCcJQLW+vVPWWWu4MIJRg4ROBElSXh4A0JpPb1FCjfb3gIgKmzgP0r9jn5W0nmV/y0Af5vLAFp8yP0i/swims6Mogc="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.35.0_1540923200632_0.06721710924110469"},"_hasShrinkwrap":false},"0.35.1":{"name":"destructible","version":"0.35.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","cubbyhole":"1.3.x","extant":"1.0.x","interrupt":"6.3.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"2.0.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"91c176986c355e1e3eb47d996bb6a0530328b9d8","_id":"destructible@0.35.1","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-bZuPs36qQ0Xd1DuHHfxtoMXIbOFD2Sdmfez1Uhnhjq7IoNEHq5prpjPJKPsNoBZYOV0m3lxm9HfiskNTUyxcVA==","shasum":"34b1a813b58624892b280c84b4d241360519614d","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.35.1.tgz","fileCount":4,"unpackedSize":11706,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb6hdgCRA9TVsSAnZWagAAGacQAJlZEV5MAU0Oorqjq+GU\n+9B+nh7LchDSu5CjwXC8VXWn8Ghz8AB0/MltyU8HZ4D5bryJNdfJ8c1OXuGR\nW1VN40zMNSwGL+fpW/CL9YE9lr0MObv8c0bY3sXk5VnNdZPl/zrDauoJyK1X\nMpF5BeMLU2apcERvkis0qcnYFVTqT1x0OUS3DkkRcL9nTOxv+8W+rYZeOEVY\nZtVql5XNtS2g9MTGrnsCIOMQ+rmqfGbE3fhO9uPLl/p+/7Hv+BF5qDTD1NZy\nT54zwyfrRtSxpvUpBGxF1kQHWDpW7UOglFgkdxjeWfIeMQYJQkvq6fHPZ9Fq\nVpG5fvT1Hdn2RG/nB1ZsnmKx4iij7GmxJQVt69LlEqEBToTXFUvPztjEXZGo\nkO0+YK8qtqBcyQW63Mfx+kStvy+TQBbS+9V1y50rTT2yC9ST+tBK59SUDJ+7\nv2yW08nC1UZFNJDYrc1m6o85GFujAy6nR3rP6UWt85DSyD+wshJHqwDnedwn\nhdG/IClTDYqzl7dVhHsPwEbiaNo63toRqTy2ybvjAXRpjBNcgnCTrTPk9Lby\njIHEMTuuXJ61bs5kKq79/1eY6l849Io/gKBqLqxoMXYJENrG9ZjRk4nLA62o\nTmTetL5A5NS8AEmLIXyMwKl8FLuCcr3N7cfcI/bMrQNOG4rNEc+UJAgmaQQt\nBPlj\r\n=3i7o\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCkUyo+oBke3KNhJYPCKAzUvIahQW2y4QP23/By7WqQ5QIgIGLLHA2CmDBGARMRg8OW65pl6k5K9EPGuYLf3U3I0r4="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.35.1_1542068063341_0.7692333729889955"},"_hasShrinkwrap":false},"0.36.0":{"name":"destructible","version":"0.36.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","cubbyhole":"1.3.x","extant":"1.0.x","interrupt":"6.4.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"2.0.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"b27cc50f3f7504f110e79640961f5b15ec820495","_id":"destructible@0.36.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-izEdDNSAofYtoM8PZaL/ghjimMVhI8DK5KNl/mQW6Osnu+Pw4LMBf3ggXcXknC1gyHQ62pTUKnZy1JHudn4amA==","shasum":"d2e0514e0443500ffe8590e631e6334277bfb2e9","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.36.0.tgz","fileCount":4,"unpackedSize":11706,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb8pRoCRA9TVsSAnZWagAAfJUP/RrXGP5vbIBnbekjnflu\nnmm0xkI4BxtIB/ehbEPewN3TKYBy+mQISMFNr/x9CblsVZzWEP0CglRJwtmF\nDBmF56C25kQyXKf8wIh46Xi6cIgvnzewUyksG+QpmWYghk6Sfeo8u19BZG+J\n3CBuahhrT1ngbknDY119fZK8Olzh3pYoU0ACcN7TRbX36Uv1lMr2OjuuDcv/\nFFb4oHPto6ZRWiX34wq0MHy69E1F44r3Yq18S3d2869Tkp3UIVmZVsJ9O1rJ\nKPoW8VOD05eO7+p6FxnFJpj/O/P9BM7rawuAGm+y/ltUTHROhij04+11Ziy+\nbCXwyzpzo+EeHLMnyYLpd83KJehYy6ahWqRJS4wqTutQMEBP/7Vr2uWz1ATA\n8C7IEdmQc8mJcqEqx3yX7GgHH+bYvsKiweSShsFq5t6bcBgp8Hu9KO9V8NfW\ndDMWaIaQyBOzbOyiINdAaix2xDliGe+n7Hzz2DNLu5BxxUa/kPlnkRO5Hm/E\nQo0iUyTGm7tPGDJRMEsjKsH9qakZ+c+KN8+QrPP/4qmrrUtcGqDVDzS2ckIo\nfuZ3qezjjkjWbPGRNVv44q4DdWvhAo1rhY64rLMRPprCHUEiJgxNsOl+Osy4\nZ+nVrDYjUj8IsAl2zRzMCcm1cAww9z3ZoTA1vSdUNLehwqOSPraftUbpsHMY\n07kF\r\n=Nh/F\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCcC29fYIc9Q7MaBMf96vmzETZVElWUoc6YdqVXiamo1AIgeH/Rn6mm4ONswmKgjhjdzY3Bh61jktyAQ2j8AM3rP9o="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.36.0_1542624359649_0.47654304349013543"},"_hasShrinkwrap":false},"0.36.1":{"name":"destructible","version":"0.36.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"1.0.x","cubbyhole":"1.3.x","extant":"1.0.x","interrupt":"6.4.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"2.0.x","signal":"4.0.x"},"devDependencies":{"proof":"3.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"1b5318db06fd4bed091a3b5c34f38d41e341ee6c","_id":"destructible@0.36.1","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-RwtSYuAZnK0b+2KUJT283mePZ2TWcHbdNcQOXUNY7SN58NGYS5rNHAKAiVRtf+pAddgFVtzBwIbzhJK+FRF7Fg==","shasum":"8f41a1cb222722c779a4f5bab64242d506ea2ae9","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.36.1.tgz","fileCount":4,"unpackedSize":12005,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb8/TpCRA9TVsSAnZWagAAeZgP/iShsKDuRUCIjUzgqxr0\nEfKWgRsBtSLaPxtB79u4DQMFsYBSQFWeENpN8iT2pfEUZ36+Wj1VBrQbYNNA\nKO3E7kuo39QmhWNQTzxwj5dq0Wx5q9uN3W12IX1MmwZdXN+UgWw1NUAD9B+a\n1b0w627E/hn0LnOpTXKyDhjQmJ82pitKXkl+TSuQNTG0v+4vhEqVGXKMBSD1\nNZaU99W2NcmJVwcq76qvdy6lHQOVNrj4OjENAn8LmvMyiBHfqbV6cir4zc9X\nG0GjG89A/zop4gDyc/CrBn2yWdAZe6Uojogil28Lq2x6EJ3WmzfjTMKnUI+G\nYWIlAEo3fFOQ16z+XAfcTDRSCSLW50opXzH/asb5IyMV2xe9mUGBsf46xq1S\n6HA8PgEQf5tZ/vLBBFBHgfYbqcp4X09+B2RwLnqNPFZ7ZbGKRaUoZer9dxzv\nSKrXeOIuzFtC7QCJXKRv0ZDcWe5NM8IQrq6MQyQRk+nG/LqiAmtYibirXaNH\nQqyAPkb/iP8A74JxWVwBSaiUMSNcj8pS5yJG2qfZRTaYdJZlkQv9TYTGC/ae\n3qMGvj4wKWAV25fq89Qy6Ro5j3xGUzSyboKUQocOegxvYAVc6bdOXpsPBi73\nss2G9o1dNX6ZHm1RewXXLe1EY1TOkxXiBduZBX90LIdLpzBlsRwjbgBXa8Qr\nFFz3\r\n=5qZl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHqvyKDoph6QyVzo5Tomt7nb6odrPRsVo8YWR3wV8RgeAiBSxV4TFErRKYJfpLkIRGsM0BOeFPMYOwEDEEXEOQAsYQ=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.36.1_1542714601002_0.7055515170015298"},"_hasShrinkwrap":false},"0.37.0":{"name":"destructible","version":"0.37.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"2.0.x","cubbyhole":"1.3.x","extant":"1.0.x","interrupt":"6.4.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"4.0.x","signal":"6.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"4b7307164974569e009d280d995f743277f61dcd","_id":"destructible@0.37.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-utQ1uDMkYzeeBG+0H0Sdz92v+i5L7NZEjpTBPq5YsjzRX3wW4unbTEixcb/1hlkyy7JoJREB3r6QiMbWACVBWg==","shasum":"90f1352e2fceae0003e280665a4f4957190206aa","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.37.0.tgz","fileCount":4,"unpackedSize":12500,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb+zxHCRA9TVsSAnZWagAAescP/0xDi/CBsNPwFpHQoLYE\nBn72c80kYwLSj2YdN432YsmiT6aCWfRHQP1epyF6GiyB1WJp+hF1nbF10uAA\nhuo8fRuz6TF6odnfBvmwKOoJZ752zt4QM85sDbPmRLk/pz3NOJ5Of0y1Efcz\nAzuHJHDFEDkvOQnYZQ/72+NXOpw5UDv+JUqRkQbWZKveNWSSkR+NgrRF08TI\nMlFTuKWl9jSFwjEeLB8RS2bS85ZWIVkuxcfMvv4cB+XO16IVVguSkbs5ilgv\nz3lQGcQDGxeTDmRJ0ndltspbvcrnfFYvPQ2TnYtCMxJMi3LLF2jbX6udfCH/\nkzlAnwFoG+dUdq2SWBgrrl+1In4uN5euTtRn4TOgaz36qxGuoUm2vpTuBMXY\nTHGamiPsU5D4XuNL+UppzumZYsSyhTyMv53EhmqQ2NV9051ba0W4IRwi/8Pz\n90oSnwpUZoCF5C/LQMGZnlU/ETtZ1QA8fB0IgwltCB4Bp9Mzwo91fJD0/cZG\nRcpvpvE5S+NEJjyptfkC11WENH0rE+QUn12h0poOIc9w+a6xpXkNzdoAwC2t\nmkLiVDwWsqjnmBsLkqjWnYJli7SM6/vzybzvXc3PPbRr7NjwAzD2DCIYv+6x\nh1ubAP4ceEXQFkeCRaXv2lynWzZiFJcXsXwXPNe9IhWr7pYENt7314FNH3XR\nooje\r\n=m7jr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICVcyEM0f7NNSz/HzrjpjzoD1JXoomevVQcneC7mtvVOAiB0VoALMoZsgyrCdQccrs7LdDCSgAabVXGPHi3mLSJE6A=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.37.0_1543191622294_0.733683600252028"},"_hasShrinkwrap":false},"0.37.1":{"name":"destructible","version":"0.37.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"2.0.x","cubbyhole":"1.3.x","extant":"1.0.x","interrupt":"6.4.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"4.0.x","signal":"6.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"1caf8921c1ffc9f77ce549304a4bc606a075a532","_id":"destructible@0.37.1","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-emT/3DQxbzCq7zzJ+rvdYTDOVXCPFtIQd2ZtLo0a9+c9CVdc0JY+EGs4Q4mZhGtdq4zVXQWHsokGd8C4XSm8JQ==","shasum":"a4cc6581c552fb02c1e6ed1da0dae107ae0fffe7","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.37.1.tgz","fileCount":4,"unpackedSize":13433,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb/BPkCRA9TVsSAnZWagAA+qAQAID/FkvRmr4Enba48rkW\nIbNT4GWZrrAme3BzsA8KBf9P6YZfhX5o+Yzlq0MN/hUgWlLODTjn6TaqU96v\n1HRCzCdmtGT7sGt9ZdtyxZMKPmrDcAOFuJZa7iojqsmJLleKeO1h34UQsgUa\nUZi9gu3qXgMLFnY1Ca0RiIRobMWXtI9XIP52B1WDV8b8QeSjNPtmZlI0mayB\nwCa1k6CoKqv9/cx+E5AoSuUUr58zTDpjxMUR8O7GJBsxLdq1vBGS2x4Z5+F5\nUh1/33sjDCk/t9TRuE+LihepIUUHumc6A43fU4rIJqwBM6lyo51l/dGHqxn6\nJy9kaAihIttdoRn6tuFcWMeHLSuA3pNRMJQkdgKzb+ZQpE6jJrxyWLP7TTOT\nR+89GpIk/fPmrpXwOD5mdGFC/Tr9Qr/XzovWUn4Jb3/k+CDPmcVhCdwQNeMw\n/zefbFUUWbaP8h7uTIZlbx/mD/GXr9F3GnbtIHuvt0WMZgW5XaIMN08qMjZq\nfoUJ/63yjciR9I9XYnOb9FhwmtS33ON3YXLfJaZqHNdiix5Ah9WIq9bm0BF3\nlOA9cucVgB8NwDPmPJD8S40xcvrvlmQJnwSti0Bwj38guuM4HO5ofD2DU6JN\nDvKBERCpaPYVjZVR5/GJE+2Xu0z3rh5/Uc5R2WEH85WMQwhoelYcBoR0TYI5\nyoT9\r\n=hmTd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCIUtM+y1aQken5k/qfR6eJlkl22qo92VAJ3FiVKxLVNgIhAPuv2FO/Oe1BfoA+qhvMyCB5CjhZa9anIBoUWaHquOgc"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.37.1_1543246819761_0.5146397302126324"},"_hasShrinkwrap":false},"0.37.2":{"name":"destructible","version":"0.37.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"2.0.x","cubbyhole":"1.3.x","extant":"1.0.x","interrupt":"6.4.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"4.0.x","signal":"6.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"260302cdfa3e29df2fbd81389d9422d030a7144a","_id":"destructible@0.37.2","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-/BeO3zwHVAMJkibssOZ9uIkXwrDAAv0yGjBTr5q1L/VfTOginuvDRbhrT3tAZ/gkNGw4C8lu5l7XiuCepW0eZw==","shasum":"5b8fb9f4a69f4aa536d2cedcb0dc1ad02b98b738","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.37.2.tgz","fileCount":4,"unpackedSize":14323,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb/CC0CRA9TVsSAnZWagAAjUgP/imq/6BAbmSa5mOr/SBl\ndi7O+idpyHFNrp1rSNbatwY+MCYj+o5WwDhf1AiQqvjm7t8l96xXqCXyiB3F\nE81Mmv2ugEHsg6RDdqKx7w1NIV1UADtxxgiLrIWYFUsb5+X9zol8WyW43tNV\nu1bC7enGgAnCSPPxid1cnuzowycZiQTz0n99GzvTO7jpe3GgafhoKRm+9emA\nphFIKElrvC0FX8WkCuKd+Dqd6s124qZtPaNKQAVx5iJkhZrGcgISBJV14W/0\npipz2q1ijyJ0XK6gnFWpq0gsxlPICOdMgvboRYYvYhx2phDupGOa342Pwp5C\nUTY0VbBV58ly01XM+C8GQOVuqDwvT+FoqHh/re11z9SgHwbSSdLDkNaM5BxI\nKIGSL8KY7RIQ6N3PGYU6Vs7OhKiHvxcb70aC4li+ttQhdUHE53rwENb3i7Pz\nQT+300u+yu3Hjy3k+01OHIJdjIh4q3lWLduxSEwnjVYY6CNwem0f6WkWgIU1\n5e3uO/gdG65gmPQJGVet34SdEcyIgBFRl0Z2TqkiuKsx5WYmEC7pvxgO2Kw6\nmmMhKA1+QtNQeeGeIxCuAgjnSAEi5NMW8+p/lHYmsvpgvSN5J9OsRAKSzYNh\nKwNbCRe+zzO/jBIkeDulWkE8NUVahZE+ZKaGB9tu7LWM2g65xcZJbEG7ndi0\ng/1X\r\n=KpkU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID7CHcV3rumsTPbbpMq/7kFy325iBAKlcl9i8vuTTmN0AiEAgvTucx8chOARwclSdRXdpjdg8rpYfriG0VyvJicUsGA="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.37.2_1543250099579_0.7481023626132275"},"_hasShrinkwrap":false},"0.38.0":{"name":"destructible","version":"0.38.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"2.0.x","cubbyhole":"1.3.x","extant":"1.0.x","interrupt":"6.4.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"4.0.x","signal":"6.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"11acc1b0ed256b0d79c8cd3ece2f0fcab0fc7af9","_id":"destructible@0.38.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-nFO0Dz/9O8L87/lWjVPNdX0TWkFeY1NSpvg4Q+8LKxI3KYFwlwXeO1zwSMTNyW2ga1/s6AztQMl7kJPqWIFt/g==","shasum":"270f7157f35caec9d8d7ea6bc34068bf4877f3d9","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.38.0.tgz","fileCount":4,"unpackedSize":13949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb/mlACRA9TVsSAnZWagAAXq8P/2hCvGY8rqq9x87e0+Au\nMikrJ9k32wMNAvLbE4SdDTJqqTjp0JJ2dNb6yd645FOQl1WErDWWq0NAAp6G\nDtOSTVkqaWq15kS7HUFCSCNdTUw2fxqunzLp9RsRHexd6s2/41WP/JHiI2yf\nKk7TiankOUzfHHVzaIL8XgWHqM+fNnf3YQ3VCFd/oAe3jep0yb7rwD1TNNA3\nUzjft+AuTUfmsDuoLhU0Rc1Hd7VEzOufiNSZbC9l2Zcb+EG4RRuMHuDNl21r\nRgJ1JkRO33shRQCsfzV/OQVF+ujPzK/C8lb+dsibLiNQ8xauvvJEilIebO+V\nm8hI0JJg5Z+GRDVWe5RW4hZONL7mbw9hB0aVoE7dE7SPOtY/lzBk5wN4taJi\n17+LmBLs54eOFsL4qPO3FylKvn/kGMEM3sJBgQjZ/gonkTK0wN3na31PNDsN\nDtKocOp703AqnHgKadFO2AwFDQUggj9399tJU9L4ams4+4gKpfBenNTKRVpd\neQd/ynRToiiS3U0IXjYKmjW21b9rkuGFSB7/QgcFx/HwOmeX6uVec8CxPjHY\nW5L08g7Da2/D5RaPj5jPQr8HFGm6u2sVkvs7QaBOSCSu/Nc6drP+vvAbrgse\nNKvDAbAfXMw9Lw6zo4A7gisAn9x8a+WBJ5VD5b4MoaG/d2sHZDEU/XbxJ7Pl\n6jYE\r\n=h9w5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICnceJg+LZjoR921ycmAiwdbUw8KISdM+6S9fyEDCZUoAiA6cD5WtNMkYp8vqCw8CqCgFm6b7RkRjscrjOYU173NZg=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.38.0_1543399744197_0.9820550703729369"},"_hasShrinkwrap":false},"0.39.0":{"name":"destructible","version":"0.39.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"2.0.x","cubbyhole":"1.3.x","extant":"1.0.x","interrupt":"6.4.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"4.0.x","signal":"6.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"3cbdf6d5e61147253dd42d8a29b543eac75160c1","_id":"destructible@0.39.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-2Go4anhY5uj/yyM+7eocZzzxYoarSkOxcoMIGEZdw8PzRwC9RETVEK60LMq6lp1lmNhqCLElKhsmtxqiawSmvQ==","shasum":"eb5487f7f2457c93220a4caa8a1bfec9b55beef4","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.39.0.tgz","fileCount":4,"unpackedSize":13949,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb/m1GCRA9TVsSAnZWagAAtxEP/0/p7x+z35aBpZZfQLde\n5uj2LE2GiM9j81j+t8AtFZcVLRvlRufXsJOqgDB3EuqxtiKJC4dx8v0ESde+\nVwLq3yuQlXrvBweWS/CQMPxC1NAhvSJcRIpC3s/2SkKH6aKU4rTGkgGGTZoT\nVX9C8oVcNugT4u7GyQ7yny8z8q3DH+00CBGUMeS4Nw2NTlbnuTY8HAgEYo55\npVEkfHO2DZEbiKdkAqyG1wrOH8kYP0zKbKH1u4MyXix8LhX7FdxW64xMnSip\nfj1pDr+z4bRdWX6+qQc90YmqKMoZMYBYOi9W9C8jzwKomWSU1ja8CuvCD5is\nvjIjCvEe0Tn1YzTmMEVa9OhbEgI+/zY6abIvp9aKVwy7QKzWyP5SvktHUKDG\n6ATj1LlNTBAk1x5B2oblEGjYMZQ9VgKyLabOWSHq3sHnpDl/LycRIjH4NdJk\nqA+dHA0Te8jnhuOmqOsG8plhaKS8oHb3l2+RQ3ROM5E5xZPdNqrhNRVm1zJZ\ntjTIrqJdTe+Pb/u08uYEe+XYKUER72gSVgjwkpGWy+C6Fs8LAwzD0IoNop2W\n7OFyQFGGT4ygiv1LLqDv0DY0OYx34BcxxbAKaU1MjCeWt6lZ+BygcSdNDffR\nhfL98l+r72am36p547sQqgzT14bcSZQi3tkVAH4sGibw85mTzXM90mnnK+mQ\nvJwT\r\n=tYAM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA6q4s+VjBd8mPWe9OFT2zpS6iJH81k9LQvnopsSS6YMAiEA1aeP4vTDEnR0pAvSpi/1A/ykUCtAq2Dn5Lc19w9ItNs="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.39.0_1543400773478_0.5074822947901716"},"_hasShrinkwrap":false},"0.39.1":{"name":"destructible","version":"0.39.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"2.0.x","cubbyhole":"1.3.x","extant":"1.0.x","interrupt":"6.4.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"4.0.x","signal":"6.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"5c4472ba0afd4f784acc2bef9c84f450f9d9ac07","_id":"destructible@0.39.1","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-FCr151XEo7Wc7EECWMhJwKaUkbHtoDguHqliPDrquImI3uJNkrLWGSW+4m01hTaJn6DkKiyDoFMVlmSEAW/yNQ==","shasum":"b266a1c49376b8c48ce60cdc77fcd1f49c1514a1","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.39.1.tgz","fileCount":4,"unpackedSize":14004,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb/m+6CRA9TVsSAnZWagAAB8EP/1XqOw7j7LRdCoFhVLql\nRNWVzwfIT6MH5626hjYESpJnHc69XBOCG/wHKc5I0IAD/EXgCe/AkHgfZTkm\n1iHUlJ8EWvQNi2dVj17tRWffS/REpMu/cCAjVa+OeWQudfaGtUtNDsdg9MEl\nTqX1r8pwaRvST238ElQFKmcZg4sahsBgpace1CxOVbJ89LdlJeaOPD4ZV8Rb\n8o8CPTpZhYKzQ6kC3ZHBEYTq4a/89nY2mXww6wqzqXw6oyuBnx5RqJ1Cspwl\nXlBw7E9VGI1gIYrtAE+pO7jrile5PxtZ9e0H9v2CoJWSvi7E2OZuqwVHrfjx\noTJ0c3RYqyyhywlsn58GlTRdugy75sCzCbP5AIXEc0PK0n3W5oLT4IRIuEXd\nXlNzihjwWSvwJzgqTww8Z3ADZqr0fq6pOhm92bmvb7JzDyYfbb6gL8y7LxQo\nH0OTqB/rwMZl0WbjRgsvsJxinZL51p5RUPmkC/eF7Vm0iJdQgHBNvBQibKEr\nKxhyEmsKWzZubfSq+tlqIcCtD/XkRSlbXt9FSY3mn5biz0TxFfGoHUXkgmoC\nYLrv/JifT0BmQchp/Y/E4GEgediWZxsFKEd8ef7eFBFdf5MdR9op3cJWshC4\nxEFhltq0k0/zPHjTOa+f9NJe+gdlbf1l+5ogU9w4BbisaKaATYKYmP7UiDoz\ntROr\r\n=Ozsv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDBDrlbOgPtvqG5cd5eDQIfGboA9+7gEnyd1bmMCtDfaAiEAlprJhVp+9ZrZTjRmlUVyGIeaDbrowal2JjqH9Gfl1pI="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.39.1_1543401401837_0.2779551579532962"},"_hasShrinkwrap":false},"0.40.0":{"name":"destructible","version":"0.40.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"abend":"1.0.x","cadence":"2.0.x","cubbyhole":"1.3.x","extant":"1.0.x","interrupt":"6.4.x","keyify":"0.0.x","monotonic":"3.0.x","operation":"4.0.x","signal":"6.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"36342f4c0f81fcc774cec633505c0fb7bff6554c","_id":"destructible@0.40.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-Mac+0e1YRYf9XUiJjF/niIIBGxDjxNh2DhuAWSkrTlMe0z2yOpJyKQ0swK8R9J4556/WFJ7pzwl1O4Y/MHsh3A==","shasum":"e1b403a0f934728585e07ce36c44dfc4d5934939","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.40.0.tgz","fileCount":4,"unpackedSize":14100,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb/nUVCRA9TVsSAnZWagAAdewP/2n6cEHHtGgpQb4maF2J\nXmj0YH+dIhQGzWtFbTF+dcJFFYH06+xekHywIoE09VYdS8a4qtuaeOwhXoKf\ncqFSGaIcEnBp0qtx6Ub06Uo7dycTu/VyCISmrgYZnXq0mJ+X4gdsOXM/a2Lb\nEUBu2YKxDDtDNVZiWkFtXU1wZs3t/58Jzd9ZtB6yQQyGTnqxj2xLYZt7SsbO\nsM+Vrc09nthu10LROwcAbVBGDvMRlEO4TaocKX/Ezx3VbIHIigiOmsylpp96\nG8EDUgZjh1AksDSQCJc+KQoyKZ8q8Vklvlz/QMR/s9ey88sm0aCADqHS3qbB\nsWxIsrwXfA5boGmkYqrIxzoX0lnzanwuSb74qt2gvKPLXoDSsQcNfhyn0J78\nkG9fuBft+ywgAUJw3iL6Qe512lW7TXfvuNJ5qhEWln2FGirDxeIdhprChiXw\n01pPTRhFGvseTjjj57K/o4qGZzvkbADCxh+6jb7wb9MkX+e61BKHL3DGZ8wB\nsq7khZSw6a9Dn29RuOn3diZ+1QxEGPTNIl6FjlYIDKebh0aI/m3ADpiAqGuK\nI+WnkWJXFdIjZHeiA5xmFNdaDwZaBhgfne4nW+O6AeFbB9bNcvzhRO+W8EwD\nK3BakLfsgqA9ZQvU3E6p9LRWjgrffg3igV72zvbD0JhQi6+zd5kuo5gdK1I7\nZ6NC\r\n=ZIOv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDkxlQXGGrZ2NMEWhpizSTu2yap2rZDEwhNniPXaiob/AiBhmzEE102IG7mi9VSFOIyrRXRJ7wRaWOcfd/FeyoLkMw=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.40.0_1543402773146_0.5872063937784444"},"_hasShrinkwrap":false},"0.41.0":{"name":"destructible","version":"0.41.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"2.0.x","interrupt":"6.4.x","operation":"4.0.x","signal":"6.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"9a7312317d3b69156cea49071a7d5cc89f51fd49","_id":"destructible@0.41.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-iRGc9SGwHG8zZeFxEvffq4Y2kmIp2GIuPJExAXNPEuHqyBMUm4HaFWnx5Bo6Wtox7cq2Z8eF3XmE7/FJWxLMoQ==","shasum":"2c75929dd5d2f54046646b4b25da3f0c20551e05","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.41.0.tgz","fileCount":4,"unpackedSize":14264,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb/38+CRA9TVsSAnZWagAA5ogP/3lJn4d7idI7LkO/Xj8S\nRSbuphsq5K8bmQqQSuyzD9AOj9YOqI1n9Hx3NzHYpgtzUcip1BRoW6djTLw+\n04qt2N6NSsMa2aklyJ3C30dhdbb1K+N6bAXq+TvXP0/5nfpEgQtsjZPufWPg\n7GDS5uq2BmBezg58P9izODENPJ7YzBwdhLX+loqUg6hZ/Dn51hoh4zIWGiLx\nIed/vMuSaAFwPNgOjEvIMC+WXm/QO+UH/1xqbB7LCAA86TUVkglQTfE0LHlm\nVxrMD0WTYlyo1x0cQ3A4qwiFtQE2kQeI74Xn+OGaUCPu+4HD75ZQJ3CruMUn\nil/ppdHVG9c1dsB4T/UPk18n9ZIEIVk7zTtS7pjnOYa1Fj7xFRErOgd2n5RI\nm+FTqlgq2OtiyDEWhZC+ZihUvyC7R6RkkgB/KGNTaTuq1rgr3P5IqVFQVKBy\nqfiuJPprgUZh9BGkdbdv8M7s0Va+sO1FigYaqXyhacJTLF6tqhj+iCHzlyiD\nY5SEoyApYJeE4oEcS4jKwQ+xuRdyfUw14JrhpMehBBcmD4ioWRhMv5IoNrZA\nuVRg2z2dkPjYGJI7DX5G4fqRAH11J9vL3h/tv2D1eeipUD9WrPOMNiDjBiaq\nd7x6TFP3BtBulcu87OsU8nKK/SzopKida7j7mQH/PRXsatAAdv9unSk5zddM\nNF6C\r\n=GA/D\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAaWC2X01v77YAmJtq6VVr5vBchli0663lR8kN9GTbgUAiBgpnjMZu+PSre9VYD4S6JjtF5/N85FUl2A4+vUoOJUhg=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.41.0_1543470910078_0.3967239072921722"},"_hasShrinkwrap":false},"0.41.1":{"name":"destructible","version":"0.41.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"2.0.x","interrupt":"6.4.x","operation":"4.0.x","signal":"6.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"1af3b7f773577f5b4b537e295dd16b84bdf86219","_id":"destructible@0.41.1","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-NRj/Vwc7dRMCh3RdF45RaGOZLv8yG+7jr6AFhvVvgp56TU2/JIbB2UBBQe+TvkyKxTgfHhajjFjFlGjK6o+Ayg==","shasum":"915295af934c3941c42bc125a7eb2e818ebde11e","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.41.1.tgz","fileCount":4,"unpackedSize":15238,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb/9f6CRA9TVsSAnZWagAA4ysP/2S0nQCSm3k00XRS+OSG\nCK/aa1pi6NXI4PM5GsKNWcMxb6CtpNjy488EoBPS1RPhTyhVKI1yOAWPZwzY\ncldKXIDb6MS6UGGMCM0qcuFXKZK0Nezo/19fhgkareG8zf1RE23spvzqoc9P\nlQjspqtLYXkod81NJe+g9YJVPObpf0h4wacukuLtthvvo9A+CZJ16YtnSa7z\nShhY0ejRkc5fw7v9jbUubnr9Q4874lkQWKxE+QHBp+Um/D/8ekkrgQ+N4VS1\nj0AefswpgRzKndpMiZ6qnHCPsYdHRk8UlfO3tUZAIc/bSf6r5tgu9hyrRNdJ\neXLrz8wjXILxl7JJrzFlGq4DPr6OIwoHh/IKcP2j/LMO6mJjak5OPdfaH5Si\nu1PMlK+xgnoDPpEmxlCbg4v6lloN8C/42dM4j1peLgoZr+aUW1pYjG7W/PFv\nXjbyxLkqJw5xEMX7+AHcKwSMBE8GlwGF/y4xsDTb3UYjhaxzBZ7RxD7mumpr\nsnImdAlu4414h39yoP4JGsL7UGF1cxl22bjfc9QsxK8DgnaR9JZZ3zaKoHcY\nUgDptywxdVhBvI1+xJfePg2NhxvxkFYIs4CxAu88AiffX6lbPruJVOEZKVGa\noyUBctSer03Ep9bOqnW8LnEdZZ+2R1iARF7Rh3gTkx0T3MZO+pTvA+KWsA3A\nWVia\r\n=sxKI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCwfLnhfosScPCm+TPe8O55fcKdNn7OtocxVFWvwmQAJQIgVJjP78OP09d796qtdMOfw9gZAlMzdYF9xpNaao+8Ovs="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.41.1_1543493626059_0.8648741582194963"},"_hasShrinkwrap":false},"0.41.2":{"name":"destructible","version":"0.41.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"2.0.x","interrupt":"6.4.x","operation":"4.0.x","signal":"6.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"828fdd5c96ad7dead87e9c547917e1c7ab365ec2","_id":"destructible@0.41.2","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-SUGl47iMmpf+ccfmhzOK/4vU3lo51AJS7dMJENjqqk36qS7rNOBqvoHDyYHNr/GvawjhY4KjoIMeYgV/UHDq7w==","shasum":"e463f6a724950b36b19c755a159e05916c0effc8","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.41.2.tgz","fileCount":4,"unpackedSize":15183,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb/9s5CRA9TVsSAnZWagAAPUcP/0VkcD6TdKvuRB/wbvyY\nKPhw5IMI5eJvsug6hOgXH1w3pE3Hapjz0K+dmAvxWh7FIvRWqTiY7H4mTKKv\nlmpuGrlpapY7U9Mk2jEJxbl9ZJzdVTkiq78z7fUfIc256iPADUanP8ISRTIL\npuuFCdHBFZdyGF3pSXtJoiWqIuiNs8q+tMUv+vT8npMTDK1Osx0yWl9EbtTg\nz/rbZS1ye5Ei+6jv7iPIE8mJtVqmoeatSzzG+uFt/s0YgD9CuBq71KRnPMgx\n8jm8BrWkDLG/XY2D8Sf7QwUcTuaw18pT4zhNKXdr/x51+OEIlh9vZm3pXHPi\nq+YDa3scvB5ENCI+kJlZeORdkCqCqfd+rZOS0JXKz7b3lpbmN3HSCOI20331\nBHan0jVFrsaGjF/RVGoVvR8V7pW2Nha8XjtM8fUfFNsK8hJm42PpkrHMbbUk\nUaMSMG3hZbndqS6J9XAAVO7tJZzDA1CjxaU+ZD7UKrDq0XqLlr8ahg4Jvzut\nJPzasDrluhZHQSDOwCE7o2ajZo8hYNtRYkyVf7AV1rsNbZxnUuVIGYgELr2J\nv8GHQelUOzEQFWI18MfpMIy5WvBToZ1KlpIv29ZZzmNxJejG5P/EwweQJe16\nlxGdlF0v7p2rBgOVYuWyLtdpmUgSFGxlXTf2s9rQyeo0nl0jjwprfl6bt8ob\ncEDc\r\n=Kogk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBrlnWrN7PMuqsAbuIV9vo0EClSyaoo1D2yJ23Bk96tbAiBKEQCUBqSlhiuoIsFxDR2m2nh+Zdsy55yS0Tm8M7KozA=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.41.2_1543494456836_0.4666328096695316"},"_hasShrinkwrap":false},"0.42.0":{"name":"destructible","version":"0.42.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"2.0.x","interrupt":"6.4.x","operation":"4.0.x","signal":"6.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"602d5a4bbf041056b91b54debcfb123e17b37c9b","_id":"destructible@0.42.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-jCuAGfpazf4MYJqp9sHb76qMYbH+371xMHoLmZsPfbc8t8uU1yUhq1vT8RybDD1A/Nl5EGU8t45Ah2hYpfpetA==","shasum":"7ecd65f42078ed1bb3d8b64ff00b546743850069","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.42.0.tgz","fileCount":4,"unpackedSize":15093,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcGsbECRA9TVsSAnZWagAAWkcP/RFxn5PCePGmB/MaQ4Cb\niYtgUbThP87vIGB/2xs6ONmHjpSxpdLC/Tw70jpDETMlqoUfiWWJih+jQAy3\nbK/3lKA4Rt2CSYA0jwX5A9olWayLJCPR7Syzth75T2Rx1Sk39+B9R0HFmjbl\nleLQWsY4d1H2b25A1jOVmG1gAlNAXd8ukwP5o5YyNAewPCRvvuXXZfGFhwJG\nIl9zkKccCm1Fyo9APPFb6qBT8KDDgGdi3APITJ8sv/u5oN6fMxqShBjv+9u3\n7/ScVoeD7XMo+QQY0nu1Y0TtaJTxvJP3mmp74Vswp3hXyHh+9bR5xETeCZO4\nFVZL23tr7ZA8FZ7ijopbNOFtt3JzxR+qdU2d8vquWMFduzHJ/+t7sOdwXrfO\n0kcEnI0WbOAM1cfHMdvtY2FfQuO3/GJz+KuKnhq8u5m0Zsvu0eeed8n6VOhj\nUyTvnvw+G7A+qEIWo3z9p+GL9GPfNuOuERyhczt+M7uNBWaiNzw1aQupOJQw\nE0vsEeMc0to1voJ04V+a17vPPmz2JjKVEFafpsw+jVaRTWSelZcaH9aafq7l\nZyWScibKC+qQYg9YzqtUxY5YcMPfHikCpaKwI9yENgz9bySBFcMLOY2xccSW\ndpQG28F7wr74zjYQH3MFD5z9KWWT+k4zCy0UcY52D7RMCiptgBZ788a8AmaK\nL1l4\r\n=OO6/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCiX+BwyjvDZfUDMyHMX4Jqx2F414GViNvpSDfw/lwOtQIgKJIB46JiQHK+GbRKoPcSbaoAnLfrONYfCQvVcLZmZVQ="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.42.0_1545258691590_0.1095802926423668"},"_hasShrinkwrap":false},"0.43.0":{"name":"destructible","version":"0.43.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"3.0.x","interrupt":"7.0.x","operation":"5.0.x","signal":"7.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"94a3d65bac2d5c034578b34c833221269689de0b","_id":"destructible@0.43.0","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-ncPL4eDsqcNJpr1J6o+moU61xq95GMTjTwx8rSp1I+BYchkWG3hGe+ynVPkR2q43AjMw4DFmyKd7BIilY9dJkA==","shasum":"e9ac14333fc832c237df71915e51b23c0dc6cb9f","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.43.0.tgz","fileCount":4,"unpackedSize":15093,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcG1dxCRA9TVsSAnZWagAArGEQAJl+hGpg1L5xL6J0yyRU\nfkTyguqUpNkbiDIL1jnG4ckCz0NmStkempj6tCjyK9RGHqpt6W53r2/uqEXy\nsXwINQ6VOitKG+STszQqLjpNkcJRXUqFDHka6evkG+fxiSWw6uhBprMpnfuB\nE0mVmja32VApjTrz+XeOoe9/XWpAjGRsTTyoFtqg66nnC8XkMjvhTnUD2ntO\nLR7rLk7AXhgOLi8589hITmMW9oM9HWqOO59n+1UQCNhuldxB/M4Z2Deqydsy\n3NujB8gGz2auW/4TTyjjgbcq/ix34Nrsea3lhJoPqTLDUhmKsBzanK8hDkyx\n+SVFrKa4tKvxC/VhGDunaUnup2K+1oNTcw/Ow0NE0DF4LeWfZY4QCLpKcdGj\ng6zNaVpxTNmoCq6ZXEyV0yQYmF6V48mtxbp4gqYg+bbk1bqg7xrv31QjVzOf\npp3fIEk+wG1SlVyKXqnI7396/VU2xyvV2v8ejDZqVM2NrYBq+0jUDna3z5U6\ndWBaDj9oCkWvxwsBEj7vqGs7iPU95vHjHn48wLrHVXzZo3sgSIgHX+Iq8H9F\n8e62uPOxq5qzqZprKRRmvUHl5ma4kWGwlnJsDu6dZJKXXF/OzffRp9/o9jNi\nutXHBmSnYzv4w4JpMKUxNovkePTpP1CSayT9rvCLR/sVjuhLX5s3OhWT5Gva\nMxDz\r\n=cLBW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG0KkkRqPsNk9ssMZtLU+sopk50ciyuTjNoVBs7Kv+7HAiBpO0r4ZpOyPDg1lRliUTb8Cfa4TVl99jN7u7PNV55GBQ=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.43.0_1545295729165_0.9429625014945315"},"_hasShrinkwrap":false},"0.43.1":{"name":"destructible","version":"0.43.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"3.0.x","interrupt":"7.0.x","operation":"5.0.x","signal":"7.0.x"},"devDependencies":{"proof":"5.0.x"},"main":"destructible","scripts":{"test":"proof platform win32 && proof test */*.t.js || t/test"},"gitHead":"a4f571ed8bb6fef92fb6b8cb79c351998d4d9a06","_id":"destructible@0.43.1","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-PAW0plyBhfgqtcsPNr96MroLQ4Wh3DwrA9diqTXG0PqIURRVgWNPhjFKSXSZFh0gydOy5MwO2dNRW7WLjb0ffQ==","shasum":"7bd3a11bf40efe8008da651df4d63f0bbe61f59c","tarball":"https://registry.npmjs.org/destructible/-/destructible-0.43.1.tgz","fileCount":4,"unpackedSize":15093,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcSrf3CRA9TVsSAnZWagAAw7EP/0TrjIEvwdYbHm4PqtAE\nq9UKnyfLUnwyK+1UYQNgFNK8I37fz5U2CjOmVe4w7s9oWI377rCP8jvnryr1\nu1x6phB1SIrUd9j+xOxiO3R0+tGRW7RDIEkRtqGB5HwYfC+z074aYmrI1YMp\ndvSEySGCVw7g7BOqZkSZpp5UUT3289sSCAgpQhuesAsl9P/LHbupl7xr3t3Y\nVS1wbR4pl96Ajq/FF7/kxu6mzTbzp6kIiGMGthUrw0yfyFFacQrmv3A+BUZW\nvGZvs1Rm0OAr8E6GAf1zKZGQwb4hKiof5p2s1sFW7AbGWyVnIx+mqsRaKZv/\n4IhSDZJ1UawZ//cRfjglw6TAW16xl1Q2CIRBZ5Xsga9irGp2N8ZD7r9YQqjd\nc7TsSQTfp9bV7ndQ3QFd06B13iUBzkl4Kdayf85bO1zSLQqdABxNMKAd40Fm\nq1CsV0eCecfthkqT9OY2EDV3j+VT6WNtZ76x3iXjNnYFuxMqWrRxTXvA17dg\nlyb1yRGn6zlf/4vhDOIFox2EB1NKkFLJLlN4nSyaTPVS47xM0VpPuPvYAWPO\nZHoqrnlI0sX1R0cb8/BdkFu+ikIhXPyY5bro3U5UsPebgdtdPEM6Wj5s90Dz\ngIzfOpRJCqdl61veWwqGbmqfZEiSoblcOIRHzSuHQ1N7+bxKVJJAHYOExkFI\n37Ob\r\n=nAiM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICVgMKwoLyqsG3+YILDXxMS5wQ7RvPRef9H4Ir/9+rewAiBFH5zVs+2YdQdBdUhIjdkllXHyd8PD0uyY20edw4bW1w=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_0.43.1_1548400630914_0.09804760658804246"},"_hasShrinkwrap":false},"1.0.0":{"name":"destructible","version":"1.0.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"3.0.x","interrupt":"7.0.x","operation":"5.0.x","signal":"7.0.x"},"devDependencies":{"proof":"7.0.x"},"main":"destructible","scripts":{"test":"proof test test/*.t.js"},"gitHead":"af2c246a7a85259728a88c609b09fb7afd5b06c1","_id":"destructible@1.0.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.1","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-p9uxeWVruT7hgX9+q/0xHWDx66xbY21C1ReeOfVZQvGMZSUVqih4FHh0U/lXiQnAMSBm+f4L43Y9HrvjvJ11kg==","shasum":"b6d2c0ac97e63a8fb97da6d0b353257203922f38","tarball":"https://registry.npmjs.org/destructible/-/destructible-1.0.0.tgz","fileCount":4,"unpackedSize":15061,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcd80iCRA9TVsSAnZWagAAOQMQAJzy8zX7jGhDtuCW/mO9\na8VmrY0+M5BVpT7w+zv4r/S7ivjh/naQSve+yQomCdJ1tg2xRx3jbzf4ZYfa\nO0mJKHGQQMNfKc/zPvpTZNz/QOSGWzlWxe9Nn8vuAay1IkxZ2C+aYBTkrSXM\nmOUlrLEYOiQ5sGCxjB8P8FNdBXF2UQKzSqbn2T49ZryvNuIi7UBlaNwsZsfM\nyY1gMO0b/B0E4H5/lcZfWTb6QsgRlCu+1GfuxE89VHZaeK4nuXErBz5zZ9oG\nbiZJgh2OEOJLRWUCf99EbtnBUMWQVGYBFZA2/sl3H/Zu2Kwa+3r+EmSM9GWm\nx1SvVlQqpHp8TXem93VrM/VgsTnJV8f8Ocu1CihwSqSq+5HaNtd38DkL7dN8\nFzV7uLoalvOeYQ8gihe9o+TvmXTquGQS649W6WHEr9jNbS4uE0dywNwa8I/A\nC2Jr9p2FmTOswJRlz8VCXnJsaGmOyrw+UxnSOZVjHbCg/9lPyoLENJ7kkki6\ncUeK/DDBTPq6ynNfrYjo/UvSzK/zL0qngys/bR6ovmYRJckn4RIvJT7a4Lmh\nsv0vzVKCxuMV1PPHK+B/HsxUECoVZhV2ZR7BD7NMcfu870ehNaMgNiTQZsrQ\nOGAqZAQXdbNaBzNp+bwP7rNJPM8T1BKRFPssVJJQhmi9DtzIEB8KkXhKztFU\nq6SA\r\n=IJVb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDBDShAxZsl+cbWz06KQV2/SP+ukYb/+tnACS0dVDlFEgIhAPmXF1T4372BdusH6CjmQE9+sX6F7VSFkbcjNIRDWmRz"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_1.0.0_1551355169840_0.49701349559078256"},"_hasShrinkwrap":false},"1.0.1":{"name":"destructible","version":"1.0.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"3.0.x","interrupt":"7.0.x","operation":"5.0.x","signal":"7.0.x"},"devDependencies":{"proof":"7.0.x"},"main":"destructible","scripts":{"test":"proof test test/*.t.js"},"gitHead":"177f3787d7ad7934f1b96c7e78d63c6b5618ceb5","_id":"destructible@1.0.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-k42GEmrD9gczd6RRj6KuR3hKzR69SGQ0gkrt3xBlBSOqTT5+coOnbuMU6sAJNn3PPPIape/o0aB5KwRVCXefKQ==","shasum":"ca31993600495a2c5e3b1e366a514df896647832","tarball":"https://registry.npmjs.org/destructible/-/destructible-1.0.1.tgz","fileCount":4,"unpackedSize":15528,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcoiR6CRA9TVsSAnZWagAAVuoQAJsQ5jK0OWUZ+D0OkyXK\n9NxIQnj31GONrKMUkmNJU9ZjfuTbmRkUHIpNPR7gY6OR/Jm2TjyiubHHBxoS\nTzfrKhA6hM7HJuB6OqWkpzvxEviEaIKQFUjRG/Toog7CgIw++/jZ6S1Qrj0X\naWN2xf50PXmUcraa1y2W6iLfg1/p4gDcRutdmOFTqXRmi+DQBRiV0IHOCimY\nGRO0rP16EpGAuUPtUWblHq8m01UMsN3IAcamx4IRlZocogLeaHYuvnx0sawH\nUlKzu2fyWdGtJeZNDpjBG/ss6Q2h5KHyTEPRJln+M5HgjxKdtr2Epc0qM8nK\nvkvG8LytsqDWRSskzc2mJjx5yhDO8jLa/Y3FUyIlAXbbAjxmQJkJqfTxesjU\nRvkEejpSYwWJMIW9nntMsirPS51anPq5pinRI9y+YcBFb1mwupMPmmKG3Qvw\nwGqEx3OpRVtLnp3G+E5eSktV83hBpT5l/MNah0UuSJUPx60XzMNeUY+/DH42\nFr+uFbNsxMOvUYwZv05lnbX1YgekV1Yv1YrFn2/ykcPsLrawpc1uD1VmULFm\nz+TTPAW/1pDeIOpzoAxOCs5yN3FQ1kkev2DzCLltERlqSGYEE3TIaKKmlz2u\n3+ikXW+3FKl8xglotKXdIEbfmb9cvHN4FnjUqVOnKpOIr62GF3hjv0lW/5Nw\n3cAt\r\n=/Y/X\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCfJSGQmNZnkUVoEKVEfZ/jH4ecz3M8Shq5rjGeMgQbdgIgeFyfVsIFw6KaRu+gV/3Z60qHK9sas/m7+t8lOgsG4j4="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_1.0.1_1554130042239_0.8229490532692825"},"_hasShrinkwrap":false},"1.0.2":{"name":"destructible","version":"1.0.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"3.0.x","interrupt":"7.0.x","operation":"5.0.x","signal":"7.0.x"},"devDependencies":{"proof":"7.0.x"},"main":"destructible","scripts":{"test":"proof test test/*.t.js"},"gitHead":"fe5e8c8824dfea4ac5c5a939117bc3c9cf317761","_id":"destructible@1.0.2","_npmVersion":"6.4.1","_nodeVersion":"10.15.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-eHcEm3rhpUBjrF5zCE/JIxR6fbQiJmly532HjcnwxIH3oVoeVMPKsKSgQRsJmh9ew5F9/DFSMT2+CBgY9tJNSQ==","shasum":"f09ee4537721c6139437aa118aeb046b367069cc","tarball":"https://registry.npmjs.org/destructible/-/destructible-1.0.2.tgz","fileCount":4,"unpackedSize":15922,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcoibjCRA9TVsSAnZWagAAILcP/10XnqXysTCLOZVHvX02\nZKgA07nAPyLSqIRZXq6V/1dajEpnnCmDHuzmNewqVqaFMipGRSI0m5eowTmo\n004YSEVAoSHN3aLdv7UGx1csHSDHE9Gsp2W+u3YFQMl1HXqCESnCfSTZJZU9\n9RwvIObvpIt373qERs+r+byPARkgl2uPiduETs2XfHajQH1lTzohIH3vOHA5\nkFt+d2Xg8KePluUwzceNuuUrVpk5j7eTq/bWwWzoQzZlT9hnNqBX/kM0oq56\nOeReWHO6bMqCs5ENvsQh5oRPrcoW+ji238n5u0bOW7z/Nw8abaPeE+FDwP0C\njcTgmokf+Zu94PEMj+fvn2PCTcKAG0Hx3Rv4YmMnDilO6gnmRMOdOK0kBwzm\nZzynuMD7rsWUZJzEeDXFUuEnfkLBfckjcMtaAPMAtZmkOuLzGtp9R8pCOzeq\n7AtzAU5KOsc/KrMd7NnRei1hMg9vkODXSkSQwoDTrdZswgFWntUdvJ91zc9M\n84bLk+drUVjN5ptZgkIloX0DiCZ0/KR7k6a3joQCdMkZ0GyWuesfnvasZcSR\nlpMpvRmRsQHoiajKzbELqQC+JMY1vMfYYkJU06HtXKVy6kiPUST7T1zzrNQt\ncMaEs5QbZgBdMDTGl+daaf3qfKHGAaNfcHZmpCnJe+cJcObLJ/vmaTnxPQkJ\nbmDc\r\n=+9mz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDzMTnM8xSKqzXZTmSl38y5t5N+9eaJlMuth5mUnUYLRAiBaWwj04AIPu6eB4lbi7irV+KihyBuxNIyqZmb/XAZ05A=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_1.0.2_1554130659130_0.8515169471952155"},"_hasShrinkwrap":false},"1.0.3":{"name":"destructible","version":"1.0.3","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"3.0.x","interrupt":"7.0.x","operation":"5.0.x","signal":"7.0.x"},"devDependencies":{"proof":"7.0.x"},"main":"destructible","scripts":{"test":"proof test test/*.t.js"},"gitHead":"613c6ebc998b1d0909ee281820aee01baf2e8a2b","_id":"destructible@1.0.3","_npmVersion":"6.4.1","_nodeVersion":"10.15.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-4HgMoZaXnmsLhAf7kY2Dl627kOYl1di5xjd4yl2TuarBzEhFIkcc1ZtGzh4OdSCi4Hlawx2IcS/m40r1Otklbg==","shasum":"ad3586899f2646b5e911098dabc01c7d20d06ac6","tarball":"https://registry.npmjs.org/destructible/-/destructible-1.0.3.tgz","fileCount":4,"unpackedSize":15717,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcok/LCRA9TVsSAnZWagAAcGQP/0k8/BzEb6QPnoyh+c9d\ncECFk39qWOx1S8O2bGQyEKRyzyEVXP9x0bFP6g61JVoF38cIX/do5Oq2a3kR\nCfx1acJRXaBwI0/w0kduQfezN6f3wWC4L/bTIw3gWmUWUV7jPfpOa5pPyGXz\n1ilofP0AMrhkHwF3MS8orhtoQoLd+BGIQ6/6moEY0t7e/uE767FmL64ncfqV\nbNawZl3jNr0hix397+lITO+nzn7XWDjl/DZVLJ2jqU1V3jJH5CeolQVmNO7O\nGAAAFJzSAvZ4i3ex/SJZlCK3lTH7pv5hDWKqBv7D+hjL4mABHivUYoo0HQEd\n8+u9xCdrMYPjqvby5RCIJtihQpWWTaBJSx87LAoACZLidWMv84qmfZ410uic\n/fXn1OboXXsmSF/ohSbk4djVvZ4OQgmNGHgIPwbYvCdyYLFGJPV1U4PajMt7\nLdVJ4rasGxJKxgexp88iaScWeG9CtpDt9T5/hVv46sLJRPOH0pdZzIoNL1h2\nNcasb3CnWO2B8YS95qiZm9DVERACsg0G71sMqw40z518aUTFJN4pVZTI0KaR\naB+/4nGu1eqyCnPWnS5bJN4izRGUfZKmrPqzmLG0zVMXjcxREjpChjfGJ7Ft\nyx3Y6PMJtlscMSS4MimQdNpngaDNHKPSzmWEt8uwhR4N9E38t9Jl3+SGMUa/\nlTus\r\n=EtGS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD8hYoxqW/5rCnFW9X3LFNuRG+8bBWwj00/bLAYKppQ9gIgOF46RyOdxG+R9PX2hqAnHU/xm1zXGl5xHg9Ni4/HiWU="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_1.0.3_1554141130875_0.41761850030479364"},"_hasShrinkwrap":false},"1.0.4":{"name":"destructible","version":"1.0.4","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"3.0.x","interrupt":"7.0.x","operation":"5.0.x","signal":"7.0.x"},"devDependencies":{"proof":"7.0.x"},"main":"destructible","scripts":{"test":"proof test test/*.t.js"},"gitHead":"7374321a64d18da06ce99f9fda8f11bf6b5a175c","_id":"destructible@1.0.4","_npmVersion":"6.4.1","_nodeVersion":"10.15.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-Sy1oTI/g6e2Qm5odhA1y1YehakNsFtDcxc/oMRWKX6yQfzDPTyDEI8FyJO2QOR362OOrmBDSBn+yPqvixxR6KA==","shasum":"20f21d327803bc61c0ef61f0cb416d5e099c5133","tarball":"https://registry.npmjs.org/destructible/-/destructible-1.0.4.tgz","fileCount":4,"unpackedSize":16053,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcopitCRA9TVsSAnZWagAA2KAP/in4nCwVCoLPQSIviYxb\nbhS9muExFgHaIdTzPmWYf+Ja2XCDDpzrhwt1FEAJX7yY+atPXeL6OH42zqno\nQeETQHKx2PV++nIgRq4GrGo3lbYlOlP8f2IFf8m+DomRY/ZmFVDiN60ryTk1\nZ7+TWtgIQ6OFv0azaB4FJ0CTxYEjvUI3B85IMsrdlyik2/6XeJolLDpVsqXE\nW6EtUed4uB/KmPlKUXe6cq/yx1uQbOxh0eme1YeoXW83h1yq1/3PrYQU7cj6\nmiRDzwR/H+dYgHlmDuv9U5tJt0zcd5d4lSx8NXqfY7ywmDbpvGBDRSFax+SU\nbfX3u28JSIjJwdVvjCHgfMx/Zd/ssvPT1vDJuSv4CrfrAThArcwqRzD3R+lg\nmRlyaSrg9QDKei3q9Nx3HFEiGcYXCaojtWb0VUCalAsXFBQ65zmxd07TzG7s\n+HODDlPlFnsewlWOd3j9LWrrhWeIU2KsR6O4xC62UcvpzXm6zk0ecVFs0twh\npeqiNY+FlFYIyBT6p7FtEV6iFbpPQKwtJ9oH1wZbgxXs8RR3EHCTzTb4MwFE\nr7GK0kawfIJD3BmPvLp3GWQfdOeZvotp4j9SLf7YRbGn6YMtKFJhKqyMCTMY\noEy28xl9CAobZutsRIuNigm412v4yDNooJxiA7TGM7D/y50H147GkTyDn5bO\nI4mT\r\n=dP6p\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD1tRCTMp0d3lwrZIZ21pef9SuI7V82VhnE/Ke5DRn9AgIgVmGr/z0nJSuR6ccgErghuvW5B42SskWO3OUZWGit7SM="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_1.0.4_1554159789053_0.6576978729793139"},"_hasShrinkwrap":false},"2.0.0":{"name":"destructible","version":"2.0.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"3.0.x","interrupt":"7.0.x","operation":"5.0.x","signal":"7.0.x"},"devDependencies":{"proof":"7.0.x"},"main":"destructible","scripts":{"test":"proof test test/*.t.js"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"f2399f11bc2213fb0ec112068021199aca0d70fc","_id":"destructible@2.0.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-LpCwfB7HuYPTy/x1q36/L3ycwDA5kCyrxZz4bzwoXlnmHBSig6s6px+T/bQma/Gbo9H87N0VqrJ4Ypvv+gYA4A==","shasum":"ee322c049d12dc343c89e8068984eac93f1d13bb","tarball":"https://registry.npmjs.org/destructible/-/destructible-2.0.0.tgz","fileCount":4,"unpackedSize":16165,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcov5gCRA9TVsSAnZWagAAXeoQAIRQz6I/84WXIIkNgg1Y\nx1lX2SLb3+XDqYxJJq7abzAfRs4t/vEOfq6GuZfM3r/Ej8EzcME75IKxKu/7\nrnTiYKGtkYnK2A+CDB+5Z9jYqoXGN7WpGMIBtb4yFgdhNYTIwzjWYk52EMqC\nsTG9jiQIXgQTdzfW2bBx9R5zBpPoLC54eQfUq4jeEGawIzkpdQO24cjYN6HO\nBCAHPIWAvy8h8dflnIA7Ni1o0IttJSMc9PbPUzGNTBLPcOtlM7cftW7cUstr\nNtTG+enVdBcVSMzvltFoZUkMk8TFFKnOT6ToEplpTvqGU1E15U1H+xrIIF+W\nH5ui+Fb7bLLZBKMmdH+4sWhTCB22aJgY/jqwrBkzicuEJxhclc6N4Z6JbXIz\nabqEEEMz1Gnd0lWRbqfdzd09WZGLGaFLBnCU15gOEt06PACZ8NsosUQOuTdQ\nbCP9yoKPzBcLbbpddFmh67Nk7ZSuLZWG2XBxPLuT8BwIe0B9I+t9bHxn3sMS\nmbno0ca8q+sEdqZ8AmQkqT4lOVBzhyUk3fGZgSraa2Hk6WuV7xR0fMsdnmqR\nPa7q/+RW+KiAlLUO3VSSNU4c80fg7u/qszwGWa3p2jK6hVZTLP2VXyCUoqt4\n+qIV6biQxS7E6t9erOfHMMN/wpgCC+DfK77j91fQKJDxX5IQb3I7GEPVahUK\nTP3y\r\n=LokL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBkCwG/aUImVmqiCFZVhb+tM6iLw9OjprIiVDnz3KO8CAiEAwoLZ7dVbkE1mwku1FuAWUw1rXgqW6I8v2FuqajKlgio="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_2.0.0_1554185823592_0.8247191187975522"},"_hasShrinkwrap":false},"2.0.1":{"name":"destructible","version":"2.0.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"3.0.x","interrupt":"7.0.x","operation":"5.0.x","signal":"7.0.x"},"devDependencies":{"proof":"7.0.x"},"main":"destructible","scripts":{"test":"proof test test/*.t.js"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"89cf2ddffad501c76ded0cda5f5b0310357ace8e","_id":"destructible@2.0.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.2","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"dist":{"integrity":"sha512-H+Nq3WhMjz9iSasm1ommLrWOkpvBU/51P5H0nqpYMlcU5ptLnhW/h5Q5VScNKO+fufgiexRAuE5rgULY4SP77A==","shasum":"4ba92947a742c000050c56480a9c3d7cdb5443e3","tarball":"https://registry.npmjs.org/destructible/-/destructible-2.0.1.tgz","fileCount":4,"unpackedSize":16165,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJctnUOCRA9TVsSAnZWagAAxf8P/iHRrDKwKMzKQwd5d/Gj\naf0u/mDQt62q07Q6OaXw13YEWdBi172/vpMKAko7ZV61iahl3nAMbWewqmBO\n8GE5UrMRY2oTLL8X7S5zw9Oamm54vDBn0ZZT/OnAkCbwBcNeFM5qL7ESRT60\nhnTLwwxqGN2CofkXt8upOpLUCdK92e/4itqF1rg7+yu+TyiEghiXOUuc0HmI\ntgSh6OgPefrVdfdn7D12yMzXVvDZ/ljDi7KxYuGPuoyX2GDc+vnas4tmmn7+\nVh4/pzgb5Nv3Jt+DVq3ghb10EwAH+2nk1gCmlmcQJXxavmoDKaJZmNb4Qok9\nt/qmdBHBwVNPN26ZNeBrqOIQpZopBgtbGt/NkmGTV1OoC3rLI4TyDBWePc9Z\nqPCcKhq300amFRdVpz/fzPW96vTqIK9UlHUlZSlgBbfDtN41AtfUQgtYrJWb\nMMuX5MTbVAiqhfI34FCXVq5hwOqkJFPil/Ig/3nbIcUj5PfpE18ksiWpbaDv\n1mkYrnG/zTNXYFLkBS3YNRsEK5eWVOVSqu6HuU4IXi1/6MU4k3NDSCD2llPC\nKqyC6RSrpnkZ0lkhH0uzmvhthjUkZofxZSHgxSMIeljy/wC29PQlS64W9Auv\nwHWV8PZa2eI3mG1jueKTDgxfh0jaBazj2l+uSjeaGNJD7v2uCvdB+2VpDsuX\nTiGB\r\n=/2IA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGz5FGJFr4e87kj8JfTlXjZA/GQnDKWObYdOEd3ZNQOcAiBjPvS/D9K0ABdzixrAqjZ+fU6XxlvOU5HllIuPjqkREQ=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_2.0.1_1555461389877_0.423769099980533"},"_hasShrinkwrap":false},"2.0.2":{"name":"destructible","version":"2.0.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"cadence":"3.0.x","delay":"4.2.0","interrupt":"7.0.x","operation":"5.0.x","signal":"7.0.x"},"devDependencies":{"proof":"7.0.x"},"main":"destructible","scripts":{"test":"proof test test/*.t.js"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"24d2f165b8c0f398a1ac0da93c8ed7504f911c0d","_id":"destructible@2.0.2","_nodeVersion":"12.1.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-n91xrFgZP8UcfcL6o2bIdZIwr1Wms1/ghLPNCaSliQ9np3l6n7JSLQzBFjGfB2nsYkMIbXanhw4XcYB9cM94GQ==","shasum":"b569d25b935247e059239d727b01c9745dd08bcc","tarball":"https://registry.npmjs.org/destructible/-/destructible-2.0.2.tgz","fileCount":5,"unpackedSize":23987,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJc16jcCRA9TVsSAnZWagAATFkP/3QtCC3J+vck+DBYIKcQ\nqVysPGHEJfsxcbnsnEvfjQOMTyxawKCgYfdKbsK0s1CdthSB5ZT3mG20QJS5\nbceuGZwqvAUK05y51nPZOg/8V4QFlOxBUfTZF88nQkIjMIHkBZLl9d3UW7+D\nDntgEWuBRQXdLV4VZ0d7ityyE8mVoH75mMjbLl8yR+2ghg45Brlvnp6HQUqQ\nI0Qvdeg/5wzddSiW/b71eYLHH6+8os03JnZVzsVNwan4ZUSkPhuJDz/5STai\nyLLTLzskNfNKiPiCyoOcPGiz0HixX5L7QMOPShVAZ8YdfQejFQQSFklEjaRu\nVPR3gd9GpMRbTdpENgss4jdKlPVS7ZmomTfrMaDLS8RLNJINsTPD+rQZYuhw\nb5itHmc8WwGZKwiw05TJguZjUKH5pbdtR4OPJe0Env5HccR2QLH4M1aZq677\nltqlbflVvAMrhmAhidZdiqy8Xdc+1y6ftP9+6xBNi1vA0qWfxMcAcBBs0Vwf\nEmv0Z07Iugj8tkp59CVPGlUM/jsEJgVpjxwlmZhANrUcV81XwMQtLwxIlXUM\nMYC539tUgapFELBqU3DKhmEsIo0iR3EbnK5rwDsUUS+Vfp0SYdRvjf4TsoQF\na8dapB+oDEsPzUh1pXTEBGGNHk+aqQgJFoyIMvITXTh3BwcP39r7aC8JMwCd\nBe4U\r\n=roQa\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDpyUrNRlBlAm1HBzSfa80NLlxefyfkWGoyR4Fg0A+2awIgRJmGHQXVyvofq7iNHMvuEn20i7zzPfig3Ovsk2hvA88="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_2.0.2_1557637340199_0.8920993334823393"},"_hasShrinkwrap":false},"4.0.0":{"name":"destructible","version":"4.0.0","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.2.0","interrupt":"8.0.x","prospective":"0.0.x"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"a264ee57950ab9cd50c3de832dc96ebef0ae5e83","_id":"destructible@4.0.0","_nodeVersion":"12.1.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-TN76hgmbDXa1t5xiFKX/81zbbGwA7V/P1C1YBO5aAuUWEFwQNB22S2nYoxYMFuOU4mHZixANV+F2HNr6wepE2w==","shasum":"7647a5deb8e0ef59b26279e9d47cb77ff515d0a1","tarball":"https://registry.npmjs.org/destructible/-/destructible-4.0.0.tgz","fileCount":4,"unpackedSize":11060,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJc4OM3CRA9TVsSAnZWagAAMUAP/AmDzY9NY0n0Bijcfsxx\nRbjFzFDQuor0q3E4g0kZyUEqYp4uX70vEpJZ71QO7LUY3vBUXl7Quc2017+5\nxiU4ZppXPOL3U5gqoLPBUP4KAUercVwowHt5eQD5pqhBajF1TxpFQooxS6ev\nw6arJFy7Tr4bz8w906R+SlE73xTp/l8/qrZddC1RHoEeYzTnFAjyM0WlS6bz\n94g3IG5ZIVxpaZXPhcMDhSdWDYKCP5EKgWznA1cJjac7ZDsTOMcgDI5aB1rm\nxXcgepyKiVTVr+WiACTQM42p8KHhLe+C5oloWGgLLAZDpmKMZT4qv3CGgkyH\nM6ZTaawP3pFzUf9puUv5zmirrqKNcfyIADqIJk4UMlHI20VM2AYUIU3xljKU\nSugwo4fQN9BfcbtQjtxmnQRyJEmgxjwna8h0a4fN2iKxmC5w9O99XjeKlZsR\n23fIh+vZ3TK5gZLXz4F6Sfnhr0d0ETdW27+ZYe0Z4MRnYkL+cdGxkrbHoLJT\nD86mp0XEozlwn98Ry2N1t6TszQEM00QozANccjbdwITJBhPT5jN2MzltR3eu\nNARCVaObmlEbxUt6jk6rsD+XFjQfumVZb7+Rt7AZwPoWThH6eDYgG62wupG+\nvpjJqYF7WA/ua7HqdmCSQqR1Yfgn6qP5hZ5NMBlSjl0Xr7D+Sw/XNSklL4fx\nt1QM\r\n=q18D\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBBSlIvT4OWKqWMZ6fK670C010WyK4w5e8O8h04TW39MAiEAp9mMn4W1dgfD3XP20QxxtoAoEroPr4xDZB8DT+Tls38="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_4.0.0_1558242102813_0.9893734898684592"},"_hasShrinkwrap":false},"4.0.1":{"name":"destructible","version":"4.0.1","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"8.0.x","prospective":"0.0.x"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"748f09cdfe4014726de48fb611825def506a5905","_id":"destructible@4.0.1","_nodeVersion":"12.3.1","_npmVersion":"6.9.0","dist":{"integrity":"sha512-OACQenhnoV+/1NRXlpj9Izr1WF1MvLwKbx2cdaUWHBUdXiX/M2R20sfhGz4/kLfR7AeZcTMq6iPYcmbDDuT3hQ==","shasum":"64d313dbd7748330d935b61a0f0038aea88d6595","tarball":"https://registry.npmjs.org/destructible/-/destructible-4.0.1.tgz","fileCount":4,"unpackedSize":11060,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdGE1zCRA9TVsSAnZWagAAaCAP+wf0BkW4P4J2wns/Z/9j\nPR+2gLLA26dCoMDH/vCAnCzHHKpy36smneP6rQZfGvCWeY47YPsQWMK+yuk4\nmJxpZVR8H09Ad1aR6cRU8QFubnqRHYUrXUafGLCU0Pdh9NXLA6a6DwUViaD1\n1MgSJeedtaN0xpJTIYFuB0oA6iSoK7XOl2TtpeOKeFjxIVFpNuWj2qeCdIAp\nmn9PywX2hZ0Uzh+rYOfSwlAbMjRS3Htfhp7B5CDTpqYCJnIwscBJnjkGzdb6\nK+RwF3uTxYRiy4GompUcvkJGkzcnVWPHN6k88fT0k5uTxaeNXF0yMcd3o5EN\njTvhQLVkdGeMI0GU7Yb6QNvZBAZG4v6KdJ21dUxwgAnWvGwiy90LigHWDZjh\nz1djKCAHOrihFfvuBaaTlscRHUN0d6IbjMbdo0nqRo73XrnpsJqGNC1G8Vkz\nxzQfkIc8eXsy5FSKXZwpcWFUs/fy2UHX1VVOH+slxWZ8OHQA0yVK+GsntKky\nwseQA2IhoDwHVCo1TrvEL3Snd/fekPDRDGjWTMove/x4D2M6bvCpvE4uoqOg\nWkIFEP5rIxjYca6ONAzj3Czyh1/Mo5XJY3P0hJ8unC8UIOrB+W3B7Vp/BUjl\nDsTdW1771keQTUymuwaE+L/1le49xy2rCi85HXSsH8ldK5OsFZ5pCKPoeBoj\niJjB\r\n=2EtU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICe6X5kJyt1Df3hUe5xAyKzY6AOWxtXLs3J+T8GCHvEAAiAaweGB1gCpJKFlGSrJ8Z2rW7WLqbqHTYfiEpycorkXgA=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_4.0.1_1561873779060_0.9753477686024938"},"_hasShrinkwrap":false},"4.0.2":{"name":"destructible","version":"4.0.2","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"8.0.x","prospective":"0.0.x"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"4a2365e405645cf9d82f0fb00af9a9b947d893d6","_id":"destructible@4.0.2","_nodeVersion":"12.3.1","_npmVersion":"6.9.0","dist":{"integrity":"sha512-Cr1LZBMdS0gxk4oCM1awym6NBIjiMPyzsUasWHQPmjIfL0t3OPlVFit4i3+1cd0NavPwaMMNLiMwjJoA9jqnFg==","shasum":"700da556ebe8532cc5005223140d20a97a60a701","tarball":"https://registry.npmjs.org/destructible/-/destructible-4.0.2.tgz","fileCount":4,"unpackedSize":16041,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdKsBrCRA9TVsSAnZWagAAU38P/RKdYPDBAellhg3q4duN\nNHS00YxEPGtY+f4gEiSbrY67HOr/e4Rt9D38h4TO017ArmX9WoTa+BnE85S6\nsvP5hJcoe95wYJhGLl+pvpJJHEXzvQNCqp+tlURy7IFdz6PC9E2tDSxnrtPi\nAIq6L6RTMeWx6gDfdRZ0rlDSHlp6AFp0wd1OIh+bqKDeOfoOXwRl7Si1N+lb\nypAADHB7+M/ouN5KRwkVsR/XZ4keaxdx49dXr2tVgbfpGSuPz2wbU56dSiCB\nURwf7E4ir+7+dwF0CESJGbncaz94GqLiEcZAFD2iD2kMvE0Y06xn9Ubsb5Je\nTuSGrCbr2V2QfFpZ4ulF7oeO09IV8dBnZaf9ettLaGcgVsGzQCmqrjHAAoox\nusAx098/cnjTJZ0m0icEUn8EQdic3TDtKbmD91Y/Fn3OpMrtIwj1FO4o9s+s\nh7cq2S1Xb/pTbGcbHfx925GPzf1Ob0RqWeiuvX15bIBhK0tL4CVLSGcuHyCC\nCjEvkZ1cT6hpFo22hJgfwCgF3U8F2OYRVKlOsqaAJ7m0sCxY5wi+Mutzp9ou\ncteDHEQ6Zl9jZMtbmNNpYwJPaDgwi+v8qRU7VcD0p24L+PxetNqrjUp2WoiI\ne47YtIWrynjzPn7mV4RywSwikUaWQbzRgFReT1Q44xgvJne+Zq/lpHTT7QnD\nQinW\r\n=n+Cm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCf6OFwhcCtcz+6lIL2wNuzkdN6U9G6bESG4IszsCoEHQIgVV4OWrKthAmg4lKT4ejX2iJMNw7Htcb7bod4KTZR4jg="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_4.0.2_1563082858271_0.525857230668286"},"_hasShrinkwrap":false},"4.0.3":{"name":"destructible","version":"4.0.3","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"8.0.x","prospective":"0.0.x"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"5e01e624ce7847cb54c02b92ff8e9ddea25a6230","_id":"destructible@4.0.3","_nodeVersion":"12.5.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-ALAUtKhWq5ni6P7kmSgjVN80jHIOzW0mjjvHxzpSH44qzsfv8IEUVb+pS5iWmL69eZq0Topwsc/N03aV/+47gQ==","shasum":"60204749f42de18e53744256d3aabe0af6e1993a","tarball":"https://registry.npmjs.org/destructible/-/destructible-4.0.3.tgz","fileCount":4,"unpackedSize":16079,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdLRbwCRA9TVsSAnZWagAAAPcP/RtrfHT6m3ot4qud4Ezb\nrq5ELJxiiphw8oJYIWuTcnBjC1e1FPX3A+CgH5UzwInfGNv26aYHvTkGI+vT\n5054MAskSQtt/MicOGCPhWOgszb0V/zVx9UbSgBBdAIis8HBFLEdkMIRHfVA\n+r95FUJzpe+nso3WB4N9jLFpEnylnssujEG3EbRspCnAWPWQn+TaZ0umFOJZ\nRyKNaKa8peEQfv7sRYN15LWtx99RhXQ/SGzRcdKkL/PNDytZnGu+rKsesjf/\nuK5T7jy6lWXmTuefFY3eCnpdJ18An7D/doccgiFdLKelP/6n898eZVN4YCC0\nRo181yc4ZcxRQeD2fSNg8dKu8c19Ha3tvIZq3D+cOErwBdmFvfRkY8KIdRdT\n0uLDIYU8148/5ZYdzMG+GDSUQI2pjUAw2P+OBZ01J52Vlvi/hV//Op6MFIWk\nDUidwIQvRCenNE8KzTq/aQVC9WIUtv1QIQFX3P8OuNM1USsLB08KiTILuJXM\nRDIgbI1Jx7EbFGgijGOSqC7G7HwCUnX8Tm6zbYKve+r36eq5c3pbtmh9a5oJ\nlO27qrhRDY9ArhsCC/waPGMybwZf50HE+JrHEwgbflzqM6QuIo9G3xFiYa02\nJsAIRFujKwe6NhHnOwY2vOpyXJGfidgI0Gr08Pl90BMBhKHSbJ3+zikNrXXu\nAcbP\r\n=mbtU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCCboOAXET/lJ8ZTGLAK9Tjpmr4Yb+10ph6UR5CdAJoTAIhAKqaL5dDwwqb437zgdVKfHZCTQ3DZeW3DU1ioCHWH73Y"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_4.0.3_1563236079744_0.23618667477908528"},"_hasShrinkwrap":false},"4.0.4":{"name":"destructible","version":"4.0.4","description":"Controlled demolition of complex objects.","keywords":["cadence","evented"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"8.0.x","prospective":"0.0.x"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"f55b962af921e791b60b7f15fbfeea7d152fb9e5","_id":"destructible@4.0.4","_nodeVersion":"12.5.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-/17tlsg+FnPaVZoxX7cNXmRqlQZlnwwmELp38lLnS2Myu13dcEeEh1lKejvY3osoAZxwkwx13vRjwZZMb3Pc5Q==","shasum":"5a7e37aeb6b2948fe1a29bf516a6e69c8d5f27b1","tarball":"https://registry.npmjs.org/destructible/-/destructible-4.0.4.tgz","fileCount":4,"unpackedSize":15473,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdLYzKCRA9TVsSAnZWagAANNYP/3zRk6wtQP5tEf6wSb8f\nD4nq1jEmNAvJQv/yqnAAO0AF/3f13LdE/laV/r+8wCj8heHHtHlunFG7SZZc\nI5P3ooT6KnMTVM7jC8NktuNa6XC3gbWQIqAaZPuoJrXvr6bK749v6IW8ures\nLlZDg8wB+2KoJ9AexJFJHQIqT29aaDQFrKrZpdtoroxxlESnz4xFEJtxZk4J\nNn5xgaa+1gXPWFyZ2UJP4dQbwARk/797+dgVjIi0hjGjhkCz0Kv2UyFe2NzB\n0gPn1wdeu1EDrtqf7N1Gnkj8avrsAfZdLa/pG+QwRNh9PRT9oaTlTzAINgI1\nDBCUdJTiYbRVsgE2FX0MDtB5FlRhCGYMo0X8sx27Oxfl/ZkQFcabl0Mw/EKC\nVcJGuzowK9Rt+7r/b4uHldMBIK+8OWIJKTqUJZtODofoUqVgJaOq8PahTmoZ\nXxeBbIlSiotgOJSFxFKRQxCw67teycOgyjGjGjhKB+QzgdOcc5WAzwCKlEQL\nDgbd1lpHCro5C5giP03iH0pq7G6DdnVpvUkAuf++7xqPtppXaOtGXP9i16Cq\nZx8FNNGvKFKZyQb3lR28ouiJNbOjMN5pP4js3wg3ZdjvZ9Y9TtD1sk4oq7UP\nTk14Lb9Vf37gjR3yKHnctshMAI24R78Rjz3QJlAXVhpotmaQJXHSv6d7Kxg0\n24bB\r\n=5hTr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGzjEpFZBI+mCAFU0verocD5KFsmeg62Smp3AzXFD2VeAiEAr4HCBZqiEhoOC+dL40ZYdvj64H/5gWg1/ZV7q2NNz1o="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_4.0.4_1563266250200_0.847576819900651"},"_hasShrinkwrap":false},"4.0.5":{"name":"destructible","version":"4.0.5","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"8.0.x","prospective":"0.0.x","signal":"8.0.x"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"b382fe98c4dd8fbf6421b32fee11d4f16aea0cd5","_id":"destructible@4.0.5","_nodeVersion":"12.5.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-CXw/+Wg+8cxsmGV1leki1LInr/rnxv5f2rVKA2G7Mhvsgqonz68nDinhtEeUdKgFumEjABE3VuA/jbpmNtCiUg==","shasum":"ada721a59d93d0dc7b09d7a84c408ca5854cc3a5","tarball":"https://registry.npmjs.org/destructible/-/destructible-4.0.5.tgz","fileCount":4,"unpackedSize":17179,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdNJxtCRA9TVsSAnZWagAAcB8P/0mqwhFWGIrYWyH0/2Pn\n6sNy3LZQ6HX7kcirejvV4BpK5zEwzqqTqV1y9xTNv8UkTIYeABScUw6SK01H\nkLHafrS46crm1fdK1zayKjx4VS+cyZZ8xAFE/5PSK+X2IPQNS5wbzMqdRhIl\nRnnH9YsR9CGpOl894RVZ86bOaW4aUBjjlQ83F//TK1X8+0BY8GT0dcFWGUUp\nbse3mejX/JXapKZ0Uik/LP8dTfUSg7gdGSZ+cjR63EvOEBF0xRj3FMa45OkY\ne0hXb5Am27+AY8QMs9zd6gEF5a4CdNYeaNbMcSgKMV5fnlxb35oHM1R7yWwF\n570GQzZg57GhOoXFIaz19DXl/TH3monHzqwdJL4LjARXIDl6X3RqievjEHq1\ntTYIodwlE2ETZhbi4K1pF5GdecdyPG+4cWQth5ZDnZD/1uC+8BApaPxDoVSZ\nibuAMmGluFv5bqs48NipEnx5QXhuatuoMVGQqGaRUOIr2qZ2xgbV78lsGePG\nQ2fCSy5hlRT7cnGyaZg81HvkHjnDyDQPPIcUw2pKJ+5MbFpkC6KzrDxMLoNV\nInVpz7xWJ9KQ+wmQ4hJToWXLNbGrHp+0kVelQhWssHQ+5xwyDWUSp1QLCW89\nb7BgwbNeE82EMzepdOJAvNa2zSZIWNLxBy1zyjWUZuLkTtrkgDJdzhj/W6PE\nBQdf\r\n=h4pi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDk/ANRzX08p8MavM+MjhCLevzJ2dY1tlBOx/Zm87/QwAiBLVxHhoKUVayiPeLEVxdYfCBa4PpGsDe8X2v4ZJZpIGw=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_4.0.5_1563729005118_0.07519533556784497"},"_hasShrinkwrap":false},"4.0.6":{"name":"destructible","version":"4.0.6","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"8.0.x","prospective":"0.0.x","signal":"8.0.x"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"5fab45c6553ec8e09aace7e9f3b94ac1d6172878","_id":"destructible@4.0.6","_nodeVersion":"12.6.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-4Svum0amVy8DpaSzpwXqqLDfJvl6QPo7h+bKSJkbz7NFL4fNoMUy4d1VMl1IQNoyz9iqcooHIMzftdtT0ZsceQ==","shasum":"b1dfb92a38fa0ac674cd8d0dc624b6459e7c500c","tarball":"https://registry.npmjs.org/destructible/-/destructible-4.0.6.tgz","fileCount":4,"unpackedSize":16965,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdXLyqCRA9TVsSAnZWagAAJmMP/RaL+5ljsC27OiX0Xh34\nVYjw7pumgwIWKTPyw0TuzGgqZLSS/nxxhqD9ms3J5BzBQ8up47xagO/fqJty\nLakkqOQ+0siwVTUH+ishIZub4F1lFhgyVCYuJXyAcb1NmgMhbYcsoL+r6dxO\nVLBjpT6fRbdqiMqUC1uxqDfasPciANx3eX45plHyOKKemvP5ELe5XaqRouxK\nOqfLGsZDjc/ZEQIRADG7gnvKh55WgZb7SRyH6vslU0crOWZWM15GHOwnuUiY\nTC3NkQ4R67/x9iA+SfzKaswmh5hXalZ8c99eLwjsTcGpdXiu4oTFF4lhww+n\nnkIFoZAdcO9EHt9xluPuytO2IXub04EnQCWXA08WxbMbzghc6ksBWlu4Thsn\nDdvf6joZ61KJDE7ZDVW2yb48tBXGFd2UEwRqq1CLJLQ22z974iw3xWGOxhWr\nrEB9ReiUn0hmAnV1zOy8XjQR2azKu+iY/aHBRyAuHKWuOPixGU3XxMMF40Gy\nUqJ3BZPk6r+NRgexj3g3Yo62Ddc3HjIt5vf+Ftly2rS0OcsF7HjyShsi76gG\nFRtQQD0U2f/tKRwLoo3o0HZFin069+fWDODViEEtQtnxHPZljgYRvizFDfPQ\nKGgzAlGR8SytAq6sLeC6mHFI2RX+5M2fp0shOImuzVpAO2IOdOy40StpJRw8\n+ipL\r\n=udDH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBpSeTQFsR+ts5g3DFiNVjfPBxMTPCKbJu29N1rC4AIXAiAp6jA6WQUZz2fZwYCNZdoVHKSyVHQFe51sNEKG5EhOIQ=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_4.0.6_1566358698350_0.7125279076331852"},"_hasShrinkwrap":false},"4.0.7":{"name":"destructible","version":"4.0.7","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"8.0.x","prospective":"0.0.x","signal":"8.0.x"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"01ec62cd17f109f65b4a0d322234b449aed9cd16","_id":"destructible@4.0.7","_nodeVersion":"12.6.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-04aEHm/O7KCbDTDuqFApbvhuX0q27AGw22p8sYGCjuo62bpNKfN7I2vXdpkHXuzhfrDlGHKsf3jpz2phhChi2g==","shasum":"da505019593edb103acc1d8dd5f87556e379ec2e","tarball":"https://registry.npmjs.org/destructible/-/destructible-4.0.7.tgz","fileCount":4,"unpackedSize":21058,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdXz//CRA9TVsSAnZWagAAwmIP/iAF01qCzvCyTC++HbNP\naBlQjeFeFZTMo7aPwp8jXvTUc1SGSskvxhtcNLZWjlaE76Z0yc0vfM3Xnb+/\nGzplW89KQf6fzN1UsTjhl7K6aGhv86bkVqTWuYjM2h66FWOGTbWE6W9vG3Sw\nDj2l9kTljckkrd+2K2zOlxQFSHfohYT8LY2pAek909je/b30dNh7z8NnmnzY\nr+vQ0848TRbYrZCBK/qLCEtQqI5fBpQxCR19q6V3oJwkYYeR+i/bleSAFBb/\n2NJa5iMLYDhJTdHRzlsrdAnjKbDY7BqhHtCAbWRzL5+CKVPtG8herKf5vX0L\nPkki2pCuZJn4rt/xZJzi1iHZx+5zWc/xFidX39WoJS6to3nhv3vwxDZhCdUU\nmRgchUKxE+Jh4LHk61O8VeAVHuZwtxC8LN//c7pI4jT72QyX2haVfnEeuC3i\nXoS6PpE01AzSu4MWqbbDxRUn1eB3TpcpGuhi3xuku0lAhw8vQW/jUclKYKBJ\nBKqqoyHmx2sScIqlonQP2bJNPT8nbj2xU2rEaVWbtUxSxbzzbCOvRI/Jn/ZU\nqMdZImf5QoptU9VE4yIfDGw4fB+na8jdpB+NslOsJLkoP3XZXNvJGm4SxCTe\nphuy3Zh9BBV6N0o3qElj+/j6NZUzm2803JaX+Ie7HOekWN2RywzaPUdAC6qh\nO2KP\r\n=mJ6b\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDaVVof+Tz2ZqaZCVcIp2OKxGp6ljSeTNdXCInIJiEC8gIgG8nc5BdWNcyuc95w5vMrKU2pilBfdOttL5js52LAvw4="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_4.0.7_1566523390962_0.27521913016619726"},"_hasShrinkwrap":false},"4.0.8":{"name":"destructible","version":"4.0.8","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"8.0.x","prospective":"0.0.x","signal":"8.0.x"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"2bc130f0f0edc03af6410fa6f8a360b1c954019e","_id":"destructible@4.0.8","_nodeVersion":"12.6.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-gaYnApws0THvDwCNGxo/F4JjVKQNJ3BMESEYZL7RgQ32mFvRzAd+s6OOyD+1aeZkXOsic7QDqjNwbROISABUGg==","shasum":"92a9b08f8f0254f23d9cd356ac3ec562a8ec9703","tarball":"https://registry.npmjs.org/destructible/-/destructible-4.0.8.tgz","fileCount":4,"unpackedSize":21643,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdX5wDCRA9TVsSAnZWagAAhqMQAJGQVXOnl/JwChLNujym\nuwbGdoAf52nuDowILeC8DKcj6VaBiOc87kfUHxXKyPvuymx3LLblh0/tUFAL\naDMu7jyspr2Us+PICX3QqnFBd1Po3ccOvHCFQv1YmVWcqgXt6NTWCEcndtck\nmMGMA/Y5OrppAtxQRLKDrGnr9FQs3TSk9Nwg+W/Ar8oaN6Jq8P8tFDegc6+P\nI2kLwc2s2LnKb1mJ1wTrjWd2NhaOtcEIbG0spg6KFgCP+OKHA5Ngt+ug7EqZ\nzwEzQxq7jQ8s8P66m4gdMnncitE1hGKC2VOYwtNpPP4fEKiCfYdbHqPOmu4p\nqaGAkTvowXdoorR4Y9DNVVhxMVrn+t1K5RwSpZxalyVnHtAkrgiZVEUGH1j7\nP3lNgi7Rvz41gLHffW7/VzkxuPj9wB4VI0Tps8Ioup9iu/v5eMv3nRNLc+q6\nHsaVWN5HU5xpaBCPXJU/1W5mx0DJwabW4EH6Znu8zOD4OQLHUTa6lQC9DlOR\nNqGxOcxEEqisejN6SBrz401FZpVjD3cIfhnlAQvAfXB53hes86924nWOEoTC\nTx2/HdSYONgSAX3iMaRSDmsWdUQ0W7sVgR+e4pNd25KMjuBMx8rcjbylKTr9\nQyrlbIUb3T2fvr09gM1uFG0lQoU4oREZpu2EcWaJ9DM6S7Trxc/eZwsskTtz\nQ4vd\r\n=GkH9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFRb4sBsqDhC6aZ5Nob8uBHk7ZzttUtMEfUlQhvBDeGMAiEAwFJ2/b31vnj6G7mwsy17QBW2CfHwua6SF+FqvTWPhYA="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_4.0.8_1566546946400_0.059294903865195314"},"_hasShrinkwrap":false},"4.0.9":{"name":"destructible","version":"4.0.9","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"8.0.x","prospective":"0.0.x","signal":"8.0.x"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"485b4ae35dcbc0ac74b1b6ccec1135d93eae1f66","_id":"destructible@4.0.9","_nodeVersion":"12.6.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-Pjn61Q+U2j7Kbc1hhDCu2cCl99yAhYlPFJvr3mP3+sqlak9zfS7srEYDlvkedNcrVDZHF8aIGCfVCghNtQlm+Q==","shasum":"886a826d57b385dd365d63f9131fbf7a19901ff1","tarball":"https://registry.npmjs.org/destructible/-/destructible-4.0.9.tgz","fileCount":4,"unpackedSize":21646,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdYBLZCRA9TVsSAnZWagAAl3cP/2QkAhrLQbqhP8uBheaU\nQuh/HBTPhpN0nIXU5FESfPPWjWtghP2+d4iuBDlyGu4eMTrUF1IVpgPJm8Av\nas3deuf6xnks6M49OgozWUavs/kJd5w1UiFEeE0X3WueKf6HpocE1bH4DtJQ\nBbhIbk0/l31493q3rnP3lI7mYO1woPdklNBT2KJcmK9g40UcaE40SWA6towH\nKdPWSh/RJqpdgsicftWO9ZS5K1v3D4yaUFmytesgLUHypXpZNor6mQk0NVfJ\nXc4EwfU7xfiqKiYqQk51wlF2koUDBnRC1DyH8wLcQbWFibgbvTD9H0r90vZb\nb7nGAea0KONLMuDHkUNP4iWw7SIqr2ocoNWqZdRVZykvuaoLLKOs9aWTjL+r\nlm8xkQuNh/FfTP1zibLolwklbjuJ+TQoSUE4ZhfKeiKnCpcxSN8wJ+dVxR19\nrCHRb+bBtP2e5lI+asABBio6uGu8nw7RvqCAp37aIopAeLKxNwL3wrfZuBLR\nzu1oC1nRUhUh/SZV03TNUR4zOVKQtpzKAKt22L9s8vbRtbnSYIBloGcehoGG\nayE31dYcnn1G4JJZRmmcAXod7KDnQnAQx5+hGZSOoyC/BkvxO0nhWNyEZnqw\naV0jDMCPZUggLqO7hrfUtW+nQVq6+oXEcW5HatsUfV+qNPLgjyZva4wRjTuS\ne7/r\r\n=FIcy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDxExiQOskwvbb89mHPwuNXOvhJ+L9VQqfxL7mu85dgwQIgQl3heWBkjohHwaXba2QcVn8nT52ccm2QzwPdISfLfAc="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_4.0.9_1566577368335_0.8621737452527112"},"_hasShrinkwrap":false},"4.0.10":{"name":"destructible","version":"4.0.10","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"8.0.x","prospective":"0.0.x","signal":"8.0.x"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"7c8325cb8c109f81c8d64b3f09399728a3725335","_id":"destructible@4.0.10","_nodeVersion":"12.6.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-VJytDkPPGhYV0IWiaeK+wgoKjeOJ2+tIiVSJWYX8eZosxxdQwgU7X+o9PEWlPvVLx92YZgBh45+TdDYDquDXvg==","shasum":"90f20186bfa4921967ebc15d10d68cd6d6e7f415","tarball":"https://registry.npmjs.org/destructible/-/destructible-4.0.10.tgz","fileCount":4,"unpackedSize":21747,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdaJ7gCRA9TVsSAnZWagAAZZ0P/jRcRpHT4pE+Xo9+CWsn\ns5dQbfoARIN/3zazXZXFpVjkcuHArVV3AtMH/qIlBU4T0JQ3TzqDmCEnia9j\nZGNjhrLdXWCX1b6iIv4YV9HknBEeQtuR8Qiuk4C3FiQ3oiWR1JmkyX9QFAas\nwemG+0OYHirGaM05D2F69eVpathUXbxWn4WwKsJj4hdR81s2d7FuTGrg9VSp\nAu646wDGfvACnstaSHzOwBM3c67uGoM0Fyax0VMBXqVXyIEO5FjDtRiIEk2q\nLZ/QC6rm6J+wip64IO9q1mBSEMZlI2ReHk5z8zjBFnTYtEPvZffgZaliM+cD\n+tqNGJ41IZkrKkZT6cMzItJ6n5X/UQV6ycmW/9e8yO0XJdWH2oKRP9P//sTS\n5IHALiKJOwSRaO1+T4Hr8Vd2Kvinm6Yd5D1uvExH53ZXT/kzgMIoC/ZRkEgU\n4ew/d6p62jBYscYUhpZmm68QIpiFstJDXTE9r9A06tQI5sFmRpIPtGuzYciM\nIm1WYIkHCuqauQQ9MU7LUtr0PeSZVi5ifWNe4/NiBG65g4Jk96f7T62vzezo\nXsq7O7DSdS1t2JtKnvvFjGK4IuJF4rZOxzab8bGelRCgARewBHV1KoiFGgza\nh34xZJPI+zSzmmdwLp9u6MpZbgzeZ7Cvgs1hUM64Ff+Jxy1G8Tua1QbHaB8j\n3Uf5\r\n=OwLK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC76z8mQmOB8Qpy2vE7UK7NdV33axYHIMmrfuUBbTIA9wIgVVkL+p7GwRZtK6mpzv5//BE0kA7IEyXn23sMHrC8wII="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_4.0.10_1567137503598_0.5345502335598364"},"_hasShrinkwrap":false},"5.0.0-alpha.0":{"name":"destructible","version":"5.0.0-alpha.0","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"8.0.x","prospective":"^0.1.0-alpha.1","signal":"8.0.x"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"e46c8a46a4300d3967d6460a765ae819fab8fb12","_id":"destructible@5.0.0-alpha.0","_nodeVersion":"12.6.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-z6n+nmr7d0dni0yWMmo/YRgxLqQsy2BnhdNV1oB4uNSLLMAJay+uFtDTZRTLph5pclLMaSpYdN2KyP4FusTAyw==","shasum":"9cd171802e1b3c9fac0c4323ed3d0f96023d2fe8","tarball":"https://registry.npmjs.org/destructible/-/destructible-5.0.0-alpha.0.tgz","fileCount":4,"unpackedSize":22152,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdd1nICRA9TVsSAnZWagAALFMP/2MTkL5PkvuesyFXCTiL\nvFBMIMNWT0R/56j+/l9RjZ+jvDT95krXI9kzUHTmo1vQDTMFQ4BARZAG11ti\nj+mjQGYTrJu4i6fifeQsuEdARJjQV0Iz/iumk71B3sgkR1eNMJCZu7pUiGzM\nB3Rlqq/OdSTwSg2q09UgxKat6WkggVThbw2BG4346ugTeOyidL55REj6SLoa\nCy++J/Jfc/UrzCyPzbOeK1b+GVTish3JABmKh/3xWpSeTtiwqUomRLKtd9iI\nTSMpHjm+QdCmp0SheQhy6bzXn9ErBWOasDWHf+QUyxPgs5LhuVYRapB0U9pQ\nHjsy3EkMbK9d6vyhshC12Pn4QsU3FzIIZF7PjmeboLNU3Q/37/i9enprS+L8\n3kxFkze2lNe3n6R//lt3eKlf0a89XfKwPdlFMT19po/x6uvUgUZftb4ZNIgt\nunw1dGKUGXrWtoQm/7EKTMyMYjGWXN00AyBb50S9D6eW2me0geHJa9agndD/\nPDfPgR+nsuuBALYk3Nfj9SEmAWk9t4vBsGZ6dOaRr6Dei4QP3tidYvOwc0q0\nCxjesAUCp/+Gn22xSAtCLrI2qrZV+D3j29B9WRu2ejJR5KhauLPMKi7/I8q+\nz/HGF7cGBrhEBl0h9XTzOW0FYvlbLF7zsavI+YVfaocJ8r51PlMRfiiV2B62\nQUG7\r\n=B9T9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBDpmycnwj0rxiFWOA4sLliNwanO7uUg4ytfZ4zjulJSAiEAtWgoct9f4pF8+EyQAS7qY5GLd9yYwUx63DCqjgBglRo="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_5.0.0-alpha.0_1568102855510_0.8062420935979135"},"_hasShrinkwrap":false},"5.1.0-alpha.0":{"name":"destructible","version":"5.1.0-alpha.0","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"8.0.x","prospective":"^0.1.0-alpha.1"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"0321ebd790f5addb7489ce9473dcfc3a0a18c311","_id":"destructible@5.1.0-alpha.0","_nodeVersion":"12.6.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-iuESSSpOU32R57k1Bpdqy90EaKs+C8NU0u3FcZNMbwdK2I3sEtdPg88vgkFYTq5Z9BVJvDXQnXTPo4Qqr5QdDw==","shasum":"b690cd9799e68a812bf86c1423a19539844e0552","tarball":"https://registry.npmjs.org/destructible/-/destructible-5.1.0-alpha.0.tgz","fileCount":4,"unpackedSize":22972,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdfdcICRA9TVsSAnZWagAAamwP/j/JKTzc5RTKZR7Jb4dp\npLz285DwxYpbDnsCxXeQ6QjeccLLLW+olKXgd5MLb9ulzmnlzFi3PnLHSgtm\nCUXtQg4MeEIfCY6aapTgL9wA3nsih4Z8+oP3rNSJjFH+oUN4DBlwLOMm0tuZ\n3heNXHHaiGw7E/GWrZmBGpRzDEM9SDXtCCKgspSVD1PN0hC9NUrmYXjN5r0o\njnXo2DQwl+uE/kifWA6/lULu1Mex4MSO6yHWj+5soah62jUvHFXywZTIWHyq\n0ib2yd72hW6/zEY3BDZOsDwQ7GDChuvC185SvXa7VbhADijtBpGLwO1DkFPl\nRZTIQhS4jpFtKpOcmBHofZwrDlMYd4bdMypoX4ifaVL+MKaGzRINrhU7Jlua\n1LoKAI6XluhhIn+ThIEiXssTQ2DXrvIAL68GObyXzzYn0W92DCfRKWUdKS8o\ntqOS49rc+DxARkVG3woUDMbj75Qi2AdKEDSBkLdyDM7ueO4jAvybarw/Ab+U\nfYGbq4uHnLSAXaf1XsT1jVLA+t86+H1qHyIM+BBmP9S6r68GzyzdnW5rvJgA\nn7K1WXdIhOVRVyjNdHZ/p4PlyXrQEUj7NP+8trEEOBNGDRCOcIG/PVIaBmq1\n0zXo7+ZEzrb2iOlFCv3T+GZPjGUI5b71lUeuhFUPgqbr10Y3aLRI3dH8MYGd\nSHIs\r\n=Zx8N\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGm65lBKgxBT8XhOGuaVWPqHyn/2yaodb5AoWWUBc3hiAiBLh7k100ALHVhYWjxPFBaNpM01i8TDSzqv0G2wicUWUg=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_5.1.0-alpha.0_1568528135382_0.7773703598002444"},"_hasShrinkwrap":false},"5.1.0-alpha.1":{"name":"destructible","version":"5.1.0-alpha.1","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"9.0.0-alpha.0","prospective":"^0.1.0-alpha.1"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"bd09797d8758925f0931385e7d4c745fa49cf43f","_id":"destructible@5.1.0-alpha.1","_nodeVersion":"12.6.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-fneDKV3Hc8yqrJVyThSQ1n/k4bM+wtTZQBGDKmjf8MuL+Lac3hEq/yatwDIM5jQEUoF8JuNvEzYgioAT2LinJg==","shasum":"2a8a2fffb715b7e0862d3fc6eff9c3ef5403fff3","tarball":"https://registry.npmjs.org/destructible/-/destructible-5.1.0-alpha.1.tgz","fileCount":4,"unpackedSize":22980,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdfgY0CRA9TVsSAnZWagAAoi0P/0eO+heSz7uEQYKFUx7r\nQj2lVXhoiVh9EdMyA77+oFC5yEsqsmEk7Tmb0BLENCUOhLfR2OZJqJbNaO1N\nzthlUOuoGFI1jf4eXCEWRg7/AvDGDeVPN5iSi+bbAZ5ca6oFXJv+53LtHi30\n3qxqysVZ77fRIjY+cdEe3zPiexA71POLmQbi6bq+tlrdyT5tQk/ePgP7nhMG\nzc6mqBC9nf7wpLxQW9jSzndkLpDKicuO31B/HhD0c/uuw6lr63m08nNcpm1M\nftoa37xF0FFUHB2EVlKPTgEpTD5kwPL9RGOMgmKdH5M+FI7dt7eA0tY5efn/\n+fSt+D6JFKO0kAv04gP190DAXflhrOkALDfIjZ7kORNP9w4MBt5VqeZHQRmV\nio9Nk5BJsWTp3ojV163EEsYimAh3bL0Q8MQH7spRiTF9Xr0XFHybLaxzD96M\nvPKxVmcqeWLxLsqWvH/ihwLNVlQS+I3w/0nQWYfpfkhPgk8yVMoe2PDTZDzz\nE+d0sCIOfl3TVnl44EEN4K5AUEnIQsmwNOld/BkqRTYQNO3yfrrYVnZgz4qE\nb9u6rFLOLksmscICty7Mmxlr+LeK/36udYX/MDMc+Qr6OeNLWp7/CAAx9wgF\n2GRQopxg3c8/Q+XYoenKIcNgzgKAChhzLB2ElI86N5l44t1GsRIFZL6y4Zyz\nWAoF\r\n=IzFN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGTyO9YA76jXVr3qYI7OZIha5cAI+DKxsKwUZDqEo4f+AiBhlRbrRxpQMUV2NOcB5QL1gZRN+Ssih4uTLsXIzkt9Kw=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_5.1.0-alpha.1_1568540211153_0.09713021799943089"},"_hasShrinkwrap":false},"5.1.0-alpha.2":{"name":"destructible","version":"5.1.0-alpha.2","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"9.0.0-alpha.0","prospective":"^0.1.0-alpha.1"},"devDependencies":{},"main":"destructible","scripts":{"test":"mocha"},"readme":"Destructible\n\nCreate a cancelable series of error-first callback function invocations.\n\n    Discussion:     https://github.com/bigeasy/destructible/issues/1\n\n    Documentation:  https://bigeasy.github.io/destructible\n    Source:         https://github.com/bigeasy/destructible\n    Issues:         https://github.com/bigeasy/destructible/issues\n    CI:             https://travis-ci.org/bigeasy/destructible\n    Coverage:       https://coveralls.io/github/bigeasy/destructible\n\n    Install:        `npm install destructible`\n\n    License:        MIT\n\nTo learn everything you want to know about Destructible start here:\n\n    http://bigeasy.github.io/destructible\n","readmeFilename":"README","gitHead":"20ea4726d0ccfcca67f66390b513619f89e9c0b2","_id":"destructible@5.1.0-alpha.2","_nodeVersion":"12.6.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-DzcIRZgBlQzVfTYaKpEd4VXegSNlxXcqqlbRxtOdtewoP+ELPlt8J5v5NWCycgQ18fFWtQaqO3JHQV3J0wGvTQ==","shasum":"f15c118f1353bbb4a83d191d50b132be68e14f31","tarball":"https://registry.npmjs.org/destructible/-/destructible-5.1.0-alpha.2.tgz","fileCount":4,"unpackedSize":22940,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdfg3HCRA9TVsSAnZWagAAl2oP/jcer/qWpp/QY8K0p8xD\nqYfRJfXjrNp7fNwqUAirsXHdPcZOg19ffJ9ZRuUKxhACSetrJ6R5ULCGDBWb\nL95HTZGuqkbeDxv8zd0NFTz3mxoplE07Hhv0sKQ6u7B0xkfnv9BGv+xFJoE0\n+ZAwTY7sWfP8NW/5oTmW/kNSLu06vc3SuDm9QSPt8JQVf2/PEoWhGX8laN5u\nJWGByOzxhhPHPVKGh06ofKAQwen3tmxZrQuhDHGzh/tqZZNsFvV05rDOrWv2\nIJHmLGlvtcU7aRjeUKDF23yE+DltXnJuAIYrrV9T02VpYL+fm7+ereW6ZjiP\nP8IYf2AMjqbSAshlZCKkItqH91wJqnuNajOR1kP8o4Uzj2iOyYXvyrH90Qj5\ncn/oPGMLCN82t2fcRdCGkvItC23ZbwEwBTAtVGdfKOxamANTJqA2VsZ5tYl2\nkPi9Y7RQAK+51F4pgghrins0UodfmSacU8qJmKa4G0lBAbzLGOlXjuwBfloA\ni55FoS6EyENVn5KPMUkGuCuf5KQsu2Uy5b+vzJPb8jToyyp8Z84bapK3etfN\nJNIMMVj5U87QtkPQjTSqPm94CQDHRyH4H8WKe95zMSvpbGNeipZG+AikzRnf\nd9TNDLPDmuGW/Q14/7UkLGb7T1d86l939j4GF2xHaKL7Cq0+4oDjpfjNW0cK\nKMKc\r\n=jSDC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD1cnw9gyAPNG58oScBvOfakAiCqrbMRkxia5Firmpz5QIhAN0ANudbxSzdJneax6Dbpk1z+kLCLWKlRx29RcM0anhQ"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_5.1.0-alpha.2_1568542150080_0.9172490743416142"},"_hasShrinkwrap":false},"5.1.0-alpha.3":{"name":"destructible","version":"5.1.0-alpha.3","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"9.0.0-alpha.0","prospective":"^0.1.0-alpha.1"},"devDependencies":{"proof":"^8.0.0-alpha.7"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA comparator function builder.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n","readmeFilename":"README.md","gitHead":"205f729bc1b83febb9de6a013caf86c274a7c034","_id":"destructible@5.1.0-alpha.3","_nodeVersion":"12.6.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-GuBnBNsCYvL4Hhqx8+q9LfQe81MMxcx9JhPo6Zc4eQVxFd1OwJUHQOhh7sS8uNr2WuIqMXyB31fmLnq6b1qlsA==","shasum":"aa4debfd87b0b74e09c955057c20f2706eba5ac7","tarball":"https://registry.npmjs.org/destructible/-/destructible-5.1.0-alpha.3.tgz","fileCount":4,"unpackedSize":23508,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdmH4sCRA9TVsSAnZWagAAtqsP/iWtNVcSxUf638goMJG6\nQ5PKGgVtItNfdLh3Y8SHdHz9XA2DUFWzVonERST65BHdLVw9O+39l0lUBGgZ\nU07o+GqhB/utr6zbwE3FYlOmhxdni5cS5D8noIfaiSux9pfG35He0fOBskp/\nt1+uA54Lt8SRHcETZvZ7YSkXjsEhupbu8t6a9fgrNw+7vGlQDJaeiuztHpiw\n9GV80iPorUXWnj+STM6lvlTS2INrGrz88x14FYVYqELN5KMcOYN9oDMg2Ku1\nVTFLKWk9d0iuWaALRohLCHaF7SQnFOEZVRKUQLOpS70lejdn7yT4O2NyXKGF\n7aHzoH2oC9yLTu2yjR5m+5MpSMJJrD+d5dyxAc1b9dqc1IG9Vz1ka7zGbD7O\nld2PFEMetldZEh+JcrkzL9mi4dkbKj7NNonA9EORYboquzSjIOTiXTH3BLAn\nMXJfyrWF0gqsbtP4gkbVRyk2fLBo2rMx3tiyehh4He5zaHidk/7KqRQxfJBz\n6YzfZs38Dp4i4jzNTjYS1q5jSi5x0u4pkhH2ThJ/NF4QKk9euCf8ezwtQ2gt\n03fy+naLQuA6gGpMkDbBOiOYHeBYh2fTPwrwpz11e9yTtGeP3+OTjHFXjlvj\n1J77quZMxXfyEb8ZUPoAwLF6AeVRsbVb6jkGROLAwD+BckpCvT936Vaqkbi/\nDSr4\r\n=MMLQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD8+yzJeDNUSXbVZidQYwkX4E6jdD7bP8De72flOB68HQIhAPbauao/DHJa7OtnH9LXzS3Tbv1myHMAIwQVAFo8ZY1Z"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_5.1.0-alpha.3_1570274859746_0.9912435632513628"},"_hasShrinkwrap":false},"5.2.0-alpha.0":{"name":"destructible","version":"5.2.0-alpha.0","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"9.0.0-alpha.0","prospective":"^0.1.0-alpha.1"},"devDependencies":{"proof":"^8.0.0-alpha.7"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA comparator function builder.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n","readmeFilename":"README.md","gitHead":"c7c8d6ac61880bba067991d3aae542f47c3f4a9b","_id":"destructible@5.2.0-alpha.0","_nodeVersion":"12.11.1","_npmVersion":"6.11.3","dist":{"integrity":"sha512-EJRKhGor1yrV07T9iX0SMOwm4XTdCd/T+6u1pTqTpfxxUigmDLFEZDgl+MJKe5Q2AvblJMEcUZu3H0Du1EOAYA==","shasum":"a8cf36c1dae836635782f3e5bb3647f63b927471","tarball":"https://registry.npmjs.org/destructible/-/destructible-5.2.0-alpha.0.tgz","fileCount":4,"unpackedSize":23477,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdmYYACRA9TVsSAnZWagAAK0gP/jKPPihND9vlQwy515I2\nMnuivtZc1vJ7Y7eQjR9tbHaFuJKMi/OxL6z1692zz+pL3ibMn9QkHJkJ/cjW\n+eJT5s4WCbWMW0yS3Nbl1BjsSa3Po7V6F4+mwM+GLQFgSWtNn8TNhNfEyqAD\nqhBa8+Vs8lCBqtgIWGwN6y26V4JgVCWoaAEauMgeLszttvIvRlEqKKqg6qnz\nMxAoTi5IeDPfW6tAD5aYSugpwda3ao5nsiPAHKHCmTKLZojau1CAHfnFigX6\nyWTvitEwGyOcS4A1EK5tGuSqfkvsfn1jABU+R0+TGJv7JBk2F8Wq7wSVQggm\nHiW4ykeFCU4r+jhLWfyYgmg8NwEa9yRKYma2N2xUJjQooFgDQDsVOADybYig\n21lFrFfnbAmHTJgvYhB274PNkPrNyeqvwXItPw49g2jA3+l4ihly8I+C164c\njV3GxIf/ssXMS9o0KnS1yARDlmYRXTPpmRmeAuUc4obFQ67hgt8/PraOuLOK\nKg7JJ4GvsmaAGOuZ3OzivgPp5osmkDmcY0wIXwA2NUm47MO3PLFHWQdkfPRv\nHOL50y0qs0ogvc8g5jJWJ99z8/VnWPr4GoSGAVUjLbsirDr94KpZix4Qvq0n\nHXUfn2EVh4ANh2rDXXHF8WrfDrEu0njSgR8n/pfRUdFESSD8ghn5E1YwGs70\nMt9n\r\n=YuEe\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDA/xmbpwB34EoHOjIZsy+8qSixzPzhZVkiUoRNPHvmKwIhAMxGUPqX29RuTNqfRX8zJ0WBy5rYgebxiJBmjMpU7vVi"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_5.2.0-alpha.0_1570342399923_0.8496165476483619"},"_hasShrinkwrap":false},"5.2.0-alpha.1":{"name":"destructible","version":"5.2.0-alpha.1","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"9.0.0-alpha.0","prospective":"^0.1.0-alpha.1"},"devDependencies":{"proof":"^8.0.0-alpha.7"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA comparator function builder.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n","readmeFilename":"README.md","gitHead":"8c2631c4735833c3f19598edc0993a83e6f260c3","_id":"destructible@5.2.0-alpha.1","_nodeVersion":"12.11.1","_npmVersion":"6.11.3","dist":{"integrity":"sha512-IaPIPd3DMrAz5gYLbcI58PEuHVGQtOZ05dMRocux4AGBqNx/6ZIkC7fIE5QBqXHr6cz/iTzSCOZ3hD1JqF/dMA==","shasum":"fe243693eeea8ce5626d7e63b5a18635b5d6347b","tarball":"https://registry.npmjs.org/destructible/-/destructible-5.2.0-alpha.1.tgz","fileCount":4,"unpackedSize":23569,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdmbOECRA9TVsSAnZWagAAOZ8QAJvQpj1ABegzelFZG7ju\n+q6ENm7Wylc5DZLYt4fUWOFyCOapghgHCDL4qqX1lett6wbhjynw72sz+xPH\ngTBU4FdCSLR4WOYM6qcvLFpq98FaIROx0NmSNe9VzjTVjmDu3lFBB4PkgZXK\nVJP1+VLdhhDDudApLE4B3DNwiY7XaL+gWRMDAiAWn4xx/anFN9r/URV6fVrm\nX4dsGcHJmNJZhbiq0Oz2b6Qkos29dQV+S3OxYVRsBqk+OjuwJsIzJe3zrkSk\nmKffu7gXgfISGhxdq3Bemymf1J5r7aCGZ9GxMtFNKG+T3/OtY4YRnX8kEkmL\nPkcoBDDW9hvEe8qgAye+2ejePM7SS4GuHc5+mhMXMYx8GmUGSxZppeT2zqiS\nfuri1orPYtkCYwqwvvRKaQGZy5mmMpk2eOaJqdimp93S1l4Krq5S2d6ctYA0\nhuTog47GYevciNe+2wIS04YQmPxccOT53OaJavhX2vuzb8S8vWtpt/TB53DM\nFQevmWEebAyeo/KIkaSdqlWgcSMWKDLbY8UhPy9bOzPeznmDrou90/hbZbJL\nNrRTW9HtYW2d2mO6R94ziWqfjafA5LNFYLLDGPZVeYe2BXSriRI/CdujA1ab\n389neuaUvbLZLGhamCql7ZznLGKkGNCwqM+BYW8L2hcE6owB2O+0pEhVvkQl\nZuu7\r\n=oDIa\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCMVQNaj2kdlRq88ZlWWyiJdPPhT8kUAey02NBqAQxO9AIhAMQ3WVC4lO8PngMY+nEdyH83yAyczrnV/oucPwYP/+3e"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_5.2.0-alpha.1_1570354051661_0.9347166037576431"},"_hasShrinkwrap":false},"5.2.0-alpha.2":{"name":"destructible","version":"5.2.0-alpha.2","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"^9.0.0-alpha.1","prospective":"^0.1.0-alpha.1"},"devDependencies":{"proof":"^8.0.0-alpha.7"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA comparator function builder.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n","readmeFilename":"README.md","gitHead":"abae09e0bae5433fd275e697265c28da925b4fb0","_id":"destructible@5.2.0-alpha.2","_nodeVersion":"12.11.1","_npmVersion":"6.11.3","dist":{"integrity":"sha512-C0FBctXlrwij9jPBCnnOfq5xSug2ZT6/RqmauK2fmroo79XsKFoAbmCAZMehuKq58KVxLO3uLuJmGstrM+xv/Q==","shasum":"f7d6068af7cfb53210fc2562f399ea4cbaeac4e7","tarball":"https://registry.npmjs.org/destructible/-/destructible-5.2.0-alpha.2.tgz","fileCount":4,"unpackedSize":23570,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdoToCCRA9TVsSAnZWagAA3xsP/Auxo4tkDcrE5cxTsecJ\nm6IXIk0nd7iEmNsOjE2V84PQ8cTopXOCp+4zmbjeyKhyZLu/0y82/DNVzlN+\ndKT9pkV82n6NK/KDzW+ccxsJMZkMm1veHt8iFT9eiZTc/brJU6PGUc5Y05ZV\nd+gnW1ree92NFJDJubNNmKkKjkCKhIEROjKt8dg+etmNoC7SYAxibvKlnAhD\nNK47ftwVIjOMeMFFcqHYQVNiTdy4MxdLuDBtnQX/+Ge36rj4yhsmO1B49Nq9\ngrz++WxjNbA2gcq40RKiIZWCvNRs2C5uO4pds7UWdSKv4RTK5sPELCtjKT+p\nXndHD/rGSwi7GaIr46XHcSrvQnaPF6+m04LKAISxqavwK5/3AWJFd6SBCH6V\ntUM+XOjj3jOMsEVkH7JL5IXda+DiO1/e+q2F3O+hY6dURvy/23WAFhJ+Nkro\nDc6KrJ9wR5P36TGniRJuY4AT0JmMQJfhpuwIXlVcbHk1cFfJw1fpIFCeBvMG\nw/JswPnk94KbngsNzZXPby6KaDjLBB7ZRLKlMXcybsIJbX50YC0pml967FkS\nfeUuZzXwHW1cQrok6KCE5wqln28FGhfbT8G7Iv/Tro1eKEE1mvUAXh0DHA8a\nVoXeG0hH2gT6XynZLUnR1Oq+xwS3Wt2CaVR81C14s02y5IwaKhUEvt0YfBHk\nFxpY\r\n=C+yw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE9Ox48Kkrtkcw+TMxgThWYsmQgvacZrF9kw5I0xod8UAiEAt75qrdNcRhvxcqpwJwXijUOXIzSfi2IRQ2hQvkd39RU="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_5.2.0-alpha.2_1570847234048_0.9989916028197208"},"_hasShrinkwrap":false},"5.2.0-alpha.3":{"name":"destructible","version":"5.2.0-alpha.3","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"^9.0.0-alpha.1","prospective":"^0.1.0-alpha.1"},"devDependencies":{"proof":"^8.0.0-alpha.7"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA comparator function builder.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n","readmeFilename":"README.md","gitHead":"c91c5a07093bcd7f3a7fbb25847dbf99abee55ec","_id":"destructible@5.2.0-alpha.3","_nodeVersion":"12.11.1","_npmVersion":"6.11.3","dist":{"integrity":"sha512-AhRvgBgjHvaFq7CS39Go6cJGssLiToKqRRKBzZD4GPjDZsVsMbQP60UIkjckahns4s0ai4IbdDBG69kGevJ8Bg==","shasum":"61a5167b174393995f86d916844b221f3a6b15d1","tarball":"https://registry.npmjs.org/destructible/-/destructible-5.2.0-alpha.3.tgz","fileCount":4,"unpackedSize":23615,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdqFZ+CRA9TVsSAnZWagAAZ8wP/2UjVqoPF4AN1w5RpQ2u\n5NQyY5o7jqNDV76pDEXoGsobIfjWgFqXSXlOEvlqGiV1MFtTqTezLbjVc8+H\nY+NtwsLeK+OTabTxZCiz5C18FSOzu1ZR8LUZBgvnOfYuXF+JFWSxD2f8hABy\nc8zHwRAbaxoHljI8xSD+CE/Od8zFAc3MyH3Gz6sIYOS6SqTUy8/m2qrvi/V9\nE3neLXmGPEIFZWeiIzlgoQPyMiWu88oHrPDAjE1Py3ba0P1dqFIRddou1kYe\nULBIV9U5YssvPSd1h2Rys43eq5mShOI9KNIstTJVon2Xo12DJhXq5HKF4d8B\nd/2bnYXji+aCdc24FS7lvwZoxEVecBuUFnrsiLmN5Nmld0JNPdJ/FxNDEJ97\nDgXdNXraSxsyya0iyZ47WZBHy+rnqSVrtAXAutyfGxgplgYFXvCFubf8+lTl\n5agUaIR6rr01NP+S0u8DdarJbq763tmVQFufvqCoGmZlz+7m4gyk2gDEo+A1\nhAVCxIN+C22fyQHrUWL9GtmJOtaHnJg47kpaFxDiWN6NaBN7k1Y7ntsDFalD\nRqmmqJTX6QJOyqjEvaa/SlEGBa3AZpkjh//DmoaOsApflPRTOymLhXmEWLGg\npKLQepowaYNQAcBgVH7xPIiESMWq4MXE7hi0oPuuxlb1GldvMdJdYM+Y9OZ5\nZzP6\r\n=i/MT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFJD7efMo24anpPTMuK96CcZ2gtXvVzV5I0fRMmp8zFaAiEA5fTkz1+NZ6qtwWuIeiN/YR4qRSDSAm3aiL5cvsp22cE="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_5.2.0-alpha.3_1571313277703_0.29786461132639674"},"_hasShrinkwrap":false},"5.2.0-alpha.4":{"name":"destructible","version":"5.2.0-alpha.4","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"^9.0.0-alpha.1","prospective":"^0.1.0-alpha.1"},"devDependencies":{"proof":"^8.0.0-alpha.7"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA comparator function builder.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n","readmeFilename":"README.md","gitHead":"b9336212b7fe7bf3b46362809e28ed1857ae81be","_id":"destructible@5.2.0-alpha.4","_nodeVersion":"12.12.0","_npmVersion":"6.11.3","dist":{"integrity":"sha512-vvnGkslTsDelzw/Rag2YAkn94zaV+DJI2BxSILG8iHu0W2/eiQolmt3Rcd61CbVb9EtJVyZv7wwXlXktJL6V1g==","shasum":"5a1aabca1c2c1af0f85ac912731ffdf25e1b2459","tarball":"https://registry.npmjs.org/destructible/-/destructible-5.2.0-alpha.4.tgz","fileCount":4,"unpackedSize":23615,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdrs4iCRA9TVsSAnZWagAAxUUP/RtIXf3l6X0XpFC1wOBG\n6gp9UsV4rMFpK793/ur50ldXmmvIgnr2kbmXrq9RWtmhsXxix3cHbVzwipvy\nb0SV24XDP3QdHIk5mxCWkKhBFx1fzTg1qj1BuUO7o8ISdg5vXbMV7/CRlotL\n1+BQukbk9Eoa+3MAmqngaTGZZQ/DK4wtoVymDoAIrxR0/gW3yzpkW3cr0JCa\n+mGud6K240oPLRxk+egj2rEgleHXHHHoexc+HwolD50/s6UXHWZpPfXP/GM4\nnC6Pqw/gYIZvuqIwQGIj25qCioy8RoMeOkLPF1oUHke6iq7PUqS8PtSuAiB3\nmp71RrwnnAt+1Nyqta5WC95E8hHrFwXVXBJn+yUNLaMKkM+bS/4/a5BKCq+7\nJnRy54vwpWkg6TzeYiYzXgd7xoDydP7MaccjhcKMGTSiS3LrWWSVzU1+5v2m\nVRDJSyvt4jC6R2wBeH1xW2ZLgsKzYRpW2cQWDZXYZLcMp77tQrdgNik+IAdM\nV4KxyPk3Vhr01nSJf2vjL9c/S4s7KF/fX3hqy9VWFFc1tl59mxuBiUe0CDvn\n1EsTnJ8KgfXqFftGEiAOAgDXnLMLWn6WPphAG13JE4zEEHYTN8TfJsi/NvKC\nYacOvu6uommz7YOLUCkQHKmfiCoxCzkcd4IWI9oR9lKmcJ3iubM7XVul6Fo5\n55+R\r\n=oPbD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCID4OnySXJRtYu/wZabLAonqTOkmO9FZK5+mQ7JLsRsi2AiAcHtyhuxY9oK/1T9NUu7FYy5OqVb2R4T+AEfKyQAXJuA=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_5.2.0-alpha.4_1571737122038_0.17305506336241727"},"_hasShrinkwrap":false},"5.2.0-alpha.5":{"name":"destructible","version":"5.2.0-alpha.5","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"delay":"4.3.0","interrupt":"^9.0.0-alpha.1","prospective":"^0.1.0-alpha.1"},"devDependencies":{"proof":"^8.0.0-alpha.7"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA comparator function builder.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n","readmeFilename":"README.md","gitHead":"76f02c5955ceb310021186b7acfaf80680a87137","_id":"destructible@5.2.0-alpha.5","_nodeVersion":"12.12.0","_npmVersion":"6.11.3","dist":{"integrity":"sha512-JQZZWRibqwNkPBcMM1HzfWm999P2p+V1qnWzWAChyjdEhDeA2bAD5TqLI447mqnfhqe1UQ5A1RJYizqFI6eTYg==","shasum":"9f0af4b89ecfb8fe11bc43ac09bab7cfc6f9271b","tarball":"https://registry.npmjs.org/destructible/-/destructible-5.2.0-alpha.5.tgz","fileCount":4,"unpackedSize":23503,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeLUoGCRA9TVsSAnZWagAAtxgP/15YHs5pZbw5q4x0lv3c\nSvf5PwbP53FDmEm00IdgP6cASmelr4sdNwGx/V/A0De7Gp7nuDqpRXy0+JLq\nLYeNk+xTIXP0dPzikaWYWnOxICVfluw/gg8bjrFryixNAcXNLWlmPMvgjOe8\nszHoHOPLwy4nzZR9Kx7VIYQF0La8O4CEVyUK+EYmkXiSni6XWFzJIa9pHBKb\n7fZ22ugZmwfHpwAV9bJTwlRGuN/Hg22S6hAinwXtJihCTMJMgULSxYcdE7gf\nYnL/CsRAU3H2Q4azNfGmJyJInWqvHhsYS2o+GyTZEdljnxclehrdUM6p/puG\nurBGG8o3ZiKUzr9pWCM2/qDMgaeZXB3Qk16aJRHCLnLyuzSRIgvo1SGBWKxo\ni8MT41oXq9L4BtSlFfNGXi6lIQwr4hCJ6vBpXk/PRVmbLMzdnstqBkB88vMk\nIOWUj+fMsmlv4HoKoJHCcCC6c2uaeA4GKImg/wypdVHabC+tvbWzJDZLRRzA\n5axilALriVxUIFkrwgh5A9CPt20EbyGD2zyDGfIn+64Gww0IlQmnmD1Nf48T\nImtSOF5Xfko4s2rKRP8kJ6iBcjR4Y1v9W8dUcgzNNxdOji9K4s54FgaliDwL\nnCCUcmkVu274kiG/x8klR4zU1GxUeZxj7/vFv9Y4OU7LgFSht+D6qJk10J/r\nNp4v\r\n=C00l\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH8m5czkcMLzgWBi8I+3rZvhklCe44n22Ewl7qrTaWD0AiBppIMwKCE7dp3WZQ9StAukf/+3tq1r2TlN/6e/rR/eeQ=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_5.2.0-alpha.5_1580026374018_0.1547551445293347"},"_hasShrinkwrap":false},"5.2.0-alpha.6":{"name":"destructible","version":"5.2.0-alpha.6","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^9.0.0-alpha.1","prospective":"^0.1.0-alpha.1"},"devDependencies":{"proof":"^8.0.0-alpha.7"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA comparator function builder.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n","readmeFilename":"README.md","gitHead":"4ab7fc8642b301720f891a00442b120b6c6688bd","_id":"destructible@5.2.0-alpha.6","_nodeVersion":"12.12.0","_npmVersion":"6.11.3","dist":{"integrity":"sha512-Px6a3BpyhhS4+4hxAiV6VjxtRAXy6ptm12jvBE9Mf3yAuypCogRcvn+o9prP2awjiVfE3/7HlkA1erD9cn17xA==","shasum":"0b1f8af6feac6bc86992010bd543cafd781ad6b4","tarball":"https://registry.npmjs.org/destructible/-/destructible-5.2.0-alpha.6.tgz","fileCount":4,"unpackedSize":25766,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeePlXCRA9TVsSAnZWagAAAsAP/2JGNOiiQvZGKeqxzhko\n9ZJ2VWaNJ2xgEi88aSeHuik1iw02vJuy76M4IioqRUmijjFqHE9n7dlm6yHH\nl/pPISuGAKMidY7d3KN1QsuTXThyaJTHOqI0qx3yltm5rQSH4qI5YcM36Dlt\n9ow1BItMvOK/aiFPwA9eq6aKF+y1/h7unUsPaxAQ8NMhTKpt7U37WfwKTNjR\nblsxrpGXF+z/zE3gsA8kcro4Dk3k8EH0OcflURa6ZY/n9gqJhAoli1Y71RvK\nJsF7dXLjO8Q/hYoxeY+Kyk1tefJ10phximGkCXK8oXBRRqKnJE5gjGnA1A9j\nh2+ybKc2Eromgfau2bwLEtMdtUXzAnOJb+G9/Bn9r59RC4LSF1VBfNizVfKV\n5AcsG2cTZEP6wAfxp/HIrDMZ37pA6CFe0bJZ7I6JUU5l2b33f/G8cGZJeQbW\nblT6GRpyPm3DDC+GdI6w7tS5cf4vRQ+fsufxSbWU9u3LjxwUxW2ywOaXH1dm\nP1o9RBT/HawlnI1Ic63rGzaqnhQBg+HihDnU0rQ3+wz2xQrR5w3BY7wMj+fG\nmcP4q35k751gWFhyRHceHpRVUg/plBpNaR1Q6njWCxtN6GjaxnmmtVPexjCj\ncWTA4/9liJLtrcOsmO2z+oCcTnFdhovJwyOjEQBxVH43RFdJPeOEea6/So0d\nvztu\r\n=pkUW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFlwhkKssQvnilklSyVMdTUHZbnQ1Qtz01dy20s87/8AAiA9o++bRxxUtbE75C0WyO9LcJacuhLLZHcaYSkp7Fwkaw=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_5.2.0-alpha.6_1584986454804_0.6321882682994389"},"_hasShrinkwrap":false},"6.0.0":{"name":"destructible","version":"6.0.0","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.0.1","prospective":"^0.2.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"gitHead":"25641f3c872c10b85c8e753d76266dfacaad3fd7","_id":"destructible@6.0.0","_nodeVersion":"12.12.0","_npmVersion":"6.11.3","dist":{"integrity":"sha512-JFWg8ia47cszbFnsKuXSsY7fzf8aveaViOG2uOqX+2th92fjuKRHH6tOWjxpd4O4AItwH5Y/L1hElWSMAQ4JoQ==","shasum":"240beb9cd3a1f90020df3bc4eb22cf7471206c44","tarball":"https://registry.npmjs.org/destructible/-/destructible-6.0.0.tgz","fileCount":4,"unpackedSize":25735,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJesLlnCRA9TVsSAnZWagAAyrEP/0pl6Ci0ewFtOe5ScTkc\nPhK29+9T0M3q/j7fWjR/KIQZ0djmE9KYcybbQycEgIdrtXbJGK1vrAiXEFi8\n5Mz6Vbj1Dw+RL/zDGxxsK+LKR0M5SwcK+/xIFY1zHDEFjmcKa1eY23gwSblq\nqBDt8s4sd5img8s6j/MixceZwVrQnfB2nLZ/vP7VU8eglWhYAHSEww2qe4nc\nv3U59GaYpvD833p5Mk3tt/sjq66dqasUx9kDI31uUju5Eg05V5KXr/Nnqp9/\ncYU+7ESMwYKTp6Q/apqd7bjQg6Zj6M3/vx5dgr4OPMsndVtrslX44Ys4PQtG\ncmPbdgs7FKWS7rE5yEojrklQ30eAy3JsZ/utSAt4VQuHu8m0ynwqN16GJbX/\nUEynq9Zn8nnm7nxoJDaMCl3iGIgkcyaer14eTTBcwDO5TKWdPW/3UwHCMRZc\nZfvFNDChCzsS7F5Jzjv/qnqIpn1p/Cz7MoBsDabDnAyaZ2prRetvmcFL1BYa\noEDATDQp9xePF99ZuXLTqaCgynRs9FF6xIKa2Lwif7HGfIXVsKgrwAUng9gs\nGSVohgjeyaYnxhUZOjq4UTFsTcU/C1aMNnqZ/rw455Kj2/5eqDj60ypexTeP\nOHr8iFst6tgqZ2aGUuMsE9ZVulv+ScgOkICCK6HeJW719eDg1i6FUcltlBdz\n8sfi\r\n=Vdth\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCYkzyVgSWV7anI2NUVGWPg5XRsVFfncBow1pXTkbQkvQIhAMVyV7IQw+dgwpJj1DDG6UOSvTQxeiS1B2Rv6fVg1OzW"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_6.0.0_1588640102607_0.751357240124001"},"_hasShrinkwrap":false},"6.1.0":{"name":"destructible","version":"6.1.0","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.0.1","prospective":"^0.2.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"gitHead":"9f9d58e5a5b4b7b91bec333c420a2cf871f3b97e","_id":"destructible@6.1.0","_nodeVersion":"12.12.0","_npmVersion":"6.11.3","dist":{"integrity":"sha512-/1S1oQE/P+Aa65usyTsmU7FePP3Bf44PMAgJKKigPZ5QaRtbHXudvZbRo47ovYGHI4Y4ESUPM+BWuU00K0ZGFQ==","shasum":"8ccf0a940c3c06df47fed00c6a26d2980607a9f0","tarball":"https://registry.npmjs.org/destructible/-/destructible-6.1.0.tgz","fileCount":4,"unpackedSize":26565,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJes9sWCRA9TVsSAnZWagAAZ8MP/3NPV6uZTej9gl3L7VIo\n04qWJVJnQwdd6VHNaYnH1jYmSvt5ZnxcA1PuORA73fHAl7qZsKsB4lky33sX\nOErfknIcA8/hNIKQvrgYsbBAKlDjssiAF/x0BnDHJDRM6frhitkwd9O4n/0+\n/Ya4vOrXEO+3zF5yxLTwc84bjutCyuJKIZkEhcuLNM1uf/iH6iqD6bJ0/U4f\nYwuS2pVL8DS8k1hSjQ/eIp28tLwGCSY9FS9fhtegAPDVl7+9QAVdtkAZ28TX\nuGydfmx9o6NSM7TDkdfiQZFe+vDPPuVPY4Rw2kY94zmTeY/47NWelAanV/JO\nDSMbxtTkabwjlpH+6vBceDj+w5dUJYPB2cUgaBFEgXquPqXWcQobYC63HXTn\nWYse0C+nxE3A0wU5uxWll1yjtkqi7/SXqeFWxRMcfYjyz0GhVNUXm+pTTcGK\nNHMkfcQDUvCFdDrpNRLK0/zyS4QOWMUOAVzhcsD1beVRp9F+pjj+eJokjcDS\nAWMx3LzIFM+BA8PXGIKFOrfbKw1tdW2SgsPp+s+qcRxh9A4GMlB7eafu51fN\nVT5KAupNfuHhO7RfzUyiUFMEmCh3tlZbNm41HxYQ3EJsL+DpZPizgZWadOnw\nUwg6bgc2FTRPyiORnJ94nYxkmAoYlMxHMMo7lNPsnC5jK9Z0Vdanhp2Cc7xZ\niUFx\r\n=iC4i\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCUCQOyMLqPP8Dr3iySD+x5cbG5/BtJdnLw2eKW2wtxDgIhAKHWlSc9OiX8P0K+AkCO8rEiD75kf4Nsq62z80VyHpBA"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_6.1.0_1588845333351_0.47736250849549866"},"_hasShrinkwrap":false},"6.2.0":{"name":"destructible","version":"6.2.0","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.0.1","prospective":"^0.2.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"gitHead":"1e886a80c47cf5d37a8c20a85fe88537e52aa752","_id":"destructible@6.2.0","_nodeVersion":"12.12.0","_npmVersion":"6.11.3","dist":{"integrity":"sha512-UI8cdLfIOAmjVuiv9awBXMDW+x/Y4z4/Ihp5qifVo6pGwuzQ63cYGMhDYz4l4eaq848JXNSolU6bVhlVeXKHIQ==","shasum":"a5b1c67de79ca42f28b4e792959e0f17f5d2ab58","tarball":"https://registry.npmjs.org/destructible/-/destructible-6.2.0.tgz","fileCount":4,"unpackedSize":26603,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJetnQ2CRA9TVsSAnZWagAAqcgP/RmNISEvsyqFM9NlulGI\nPbE265acKrHeFQsRbL4HHDe1ENorrpNwIId7XYbAJoPC6j22/QbFZrGX45V8\nNio3zMkfxyYKDncaCLHXmDeo69g0ynIsgeuqsRFbKWScaZssusfUwiDPPeam\nP+qa9NqRrR98FC3hx1mBSBtSbXUwg5fPIkr4wghsTcz68QUh+IdiOGHADX6a\nfNkhaN0Kf+N0/TbE9YMGgQCFMLH6Ujy4qHc7OqflhgB5RrxnnoE3+8L/Z856\nhxREaMw6b9J+1QPxhBsrHex6k/tNvWa7QBS+QzJHpYaIWdwbZaPCOmti98uE\nxjqeCR1iGNaofySgi09vZyRFSvR0tPUZwsgB+5AnS4MDDvnOk02zTO/6fUKV\nVspFkTvHfvbCpteD05rqCp0e/jd+IHpZy62jBPj0JsxVyckULGK9O8ECLKda\n0KJgEbV+ENXkW+6xmVeil1NXRAy/lIjoHb+U5ir58rOjKarRdfd+RJOB/rHt\np7NjRdfZWzAkiQLVbtOoLr8PzhNp9uMM9HMUSejmFzAPy1KFJRY5DTaBB4oP\nKYM5Olti8dx7KC65nn4lRq/FzdidQUvlPyoTMAZFGYWX40oX7ycQX0dHcWxv\nm4L81TY907Q1M6Sg6+8Ck4o/zhSZs1N4br6L3i8Q+eSP+aq+a/sZ2Ra683IV\nhVOl\r\n=lK2T\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHlFhPrObxq39h98kzVRLz4y4h62blClgdNbGL30s1pyAiB/8o795Z1zokSxB3qrEG9KcMfzMQj/xInSdz9mo5FVbg=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_6.2.0_1589015605772_0.2630382003053906"},"_hasShrinkwrap":false},"6.2.1":{"name":"destructible","version":"6.2.1","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.0.1","prospective":"^0.2.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"gitHead":"d7406c6e65b24ee6d7be967b071d6e14adfed88f","_id":"destructible@6.2.1","_nodeVersion":"14.2.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-dRiK4Em748V4Efpi1uyG+LfEZhB2zU8bFJ2ld7ISJ6uI7lruS3+m6z3h1FOp3pHXzzLeaIuQbKmhZ+7Yl2fQQA==","shasum":"9de629f3ca4932e1b1e424e4dee55de934c26781","tarball":"https://registry.npmjs.org/destructible/-/destructible-6.2.1.tgz","fileCount":4,"unpackedSize":26641,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeuZANCRA9TVsSAnZWagAAsOMP/RgzYbZFqBlQdsTQjXbf\nmhJjA/z3PDshuW3JiTpPFaEWwhGgHFkRdsCC6NMc+Knfkd/Hj/U3fxhTCRRZ\nZotsj4Gol1T4vNoFIZ4hC25Fn2+I/7yPBUeNmTAo5WROMwhzQzHGbKISHK6g\niW9lYmttT2NWxycKW9RkHAGpJuoplK74qd5Zu+iLg0TIbSISLUAQRaBCA58u\n45HeQ90l714iGRNu3IuMUdPjBUYkDcRvxDVvgYGApeyT2zPn37gNHFuO8apj\n08INHT6T6CGXE6AkziEGv0Dj4Rs+hGFERmlrdPM6hio5lhd3T7r4iuNozxlq\nfFW68QRouHeYaIC03vSKtrH+Pm/ZuXKQEiSGrSnt8zjaaqikDHJQj513m23W\nXpF9aMStHWMAhT/1k6ivno4Hy2AY9gXWt6Dd9gK4TdlHJustK5Pd2a1VWQAf\n7l54VhD4dLG9mSwGYxWH2dzsXsYH8AVdSMsy2o6S74ujVNpeHHcO4rBnN3HB\ny+2eX3kMgKMpuXlJRj1EjzTXzt++EeKgyfzGsKKcKG2EKp1UDaGw2iFaJHEH\nYKE/1rKusgzFxmyS8m0+byWZhZNLIH9pbaCSfOYlvxHLer6Xxk90EjMjq3VL\nPUKoCbDhnFEI4cOgt7rylRcwdYmw3V09ZX3sqS2or0fCpaYR2Vdel2xEfYp7\nIYNE\r\n=sO5A\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC7xKaAkvDMpGa0vV3pPsBVZzCI5Bnf7vdm7IaNFCA0jwIhAKRkWdPud6epQoG+ZPsUXrQSqm5suq/T/mTcIVaw7tZ1"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_6.2.1_1589219340939_0.2636460820275197"},"_hasShrinkwrap":false},"6.2.2":{"name":"destructible","version":"6.2.2","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.0.1","prospective":"^0.2.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"gitHead":"e46fbc2e4f79805526792c9cc55dadadf5c1c7c3","_id":"destructible@6.2.2","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-jK6/E7h7ij7LP5mtuXIGDru7l1BM+fHpLWd8TQO+UL6xLYrqmzEGa0itR42pOp+3Oosv5Jph513QqJo9KzVViQ==","shasum":"2700fef2856f8e64dc33e90dc0a480c79530df38","tarball":"https://registry.npmjs.org/destructible/-/destructible-6.2.2.tgz","fileCount":4,"unpackedSize":26689,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfOAi+CRA9TVsSAnZWagAANKoP/iR4c0FZNmw2A8fPkWSA\nE6kMJelR04lS86bKvg4bEBs1rRJU43TFaInpGMMDoevV5JEiNusJOVnpInRF\nID1blyChSeKzJjSXEsEnB0GpZAJvSwKJtc0sKtr8CKuSiY3IjhacqXEOyEpn\ncmF32azIM7eptz448aJK5cRKbnGuX5AqfRwBrcVyxyMQ5BK17IV4rfpgBhLu\niLhrN+2A7B/HWqmf2Z7NCQrKjStCQHmvCUlakyhpSlnsbNO2KqyX0fDvl6EF\neYNNBzPyEGz8KCAP8fd7hDZYA0OIaRH53ebaf8RoC3L7Hjrg2mZVEid2fpTq\noXiQ6EI1V3B6Fs4KvsBCjiocb1q+Fj1y25Tq2FcERpWv3sEsuF0NmASLNTkl\nkvg+paRHVuPrYdGhfqAHl79hVsiMbm8JiLJnRDCYp+uGojIvbEfLUbwq1axM\nqYML3VLIXrdefyOiK8Nk75gkfY+QS1YilhfesFhnER4YQGKZcgVP0UD+UEED\nMigxsmZF3Fg1TkDZ5T35xA0G8TOa2qpGIFiscgRCfiGyzAt7m/wlR3FY27k9\nUiu7jZslRM3AfbOX9G6ceIWuHVwuLqAtbRVLqcTac9OPxas54Uv965UJq0fH\nXyJqw62lrW1zji79gAuZc1QjzPtaDDCOg2MxzpNfMfdVvWISZw5y+4rHfzIX\nO1qn\r\n=d9WV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC2ktBZWMPn+D9dqg6inM402NMaQbfjmbBmHSP2XqCOZgIhAJdXDwX/HQMO8rlfAXe0ufhe66MBzOZ2Q9HQ33BGgEZ8"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_6.2.2_1597507773552_0.12942320358594261"},"_hasShrinkwrap":false},"6.2.3":{"name":"destructible","version":"6.2.3","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.0.1","prospective":"^0.2.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"gitHead":"90a2f77cf72400473b6aaace82a5ba2954f1c6cf","_id":"destructible@6.2.3","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-Z1PrZezFehmzXU5s+4XHsQf7tRpp5NLzQq/cm8jdgZo6Kxp+RrRrVqzmld4oyFXV3wzPVe4PZcpDt3Zu3cQJ0g==","shasum":"2df36e66a3bd6c9c4a9c772f83d3bbc4017281e7","tarball":"https://registry.npmjs.org/destructible/-/destructible-6.2.3.tgz","fileCount":4,"unpackedSize":26650,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfOAlfCRA9TVsSAnZWagAA4+cP/04OONUy5w7FJKMPVECQ\nu9ODdMLge3PK0EyYF1aevtO60O3oTepPFDU3+nF3a1IyLc9zNbtuw3UCrXOl\n6bjcDc92klaIeOggEFtdX45N8Xl6zvUHKB1gfJSGR0qQckXVv1MQ5yDH9x/J\nu/pM2CQKT1gxHrUjAxqbKyT75RvQwpPMbTTd9HV4D0gbl7jqv5jG9APtAVYQ\n8bJirVPcAEgltdPC0VBW3T4FLn0Cw7bq7/8b6FuSVsQoCPXEXggGQiWwJFfi\nIY8vnAVd5C6I7++8rvkf990bok6xI5ulNv2L45AhsGbGeIWZh/FO2NF14R16\n18MGexzGY81JMQ1IBskWhraO4WUFZ+i7Pk8uGwMOWcRCdrPN209Ao8sB7NgC\nUGaJDrr51l3zRtlKREcS5qccbEUhM+qBe0NstjA9cxcxv2eCpQMT37MS5zFr\nhBuF94Iw3Vvk4SGFj/SmAokK1EvtwOGZwNXlany4J7IVFdllTxzuWuwQURGp\n72hre06YAAaAOmvvGGVkeV6xKY1Vmk/YH92Z5A8tS85uTGimNsBqPLxur8Aj\nX+X8QbwRNyApdxOghXwhHT40PADFnyvDjfraruS2bQXxBqi2JSjsNxvJ9P2R\nvDQyqeFylr/gvDSMkZZesX1ygL4n/qcnBptHMcUDgVM3oVRpWj8y8bJgFq2C\nBmvG\r\n=fTOn\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHlVgXJndidJfjr90usTnYFxgsI4PulXXtrRYkP06upEAiEAroXRa+o8HKjgvG29Ymrkzp+F57m4SrwTODND0AtvxF0="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_6.2.3_1597507935276_0.8069317667673488"},"_hasShrinkwrap":false},"6.2.4":{"name":"destructible","version":"6.2.4","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.0.1","prospective":"^0.2.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"gitHead":"eb72e60cce51c95c68f152cd3d92cc37e4070801","_id":"destructible@6.2.4","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-6kQoHUTAv2skJVBRkB4n0nvcMMOJgYiZKiWFd9hcl8uZYawbZn/N+1s6il2mrY1VlVz7xc+SpU7MuGDhAH0HuQ==","shasum":"00c328de40d33bfe54116713ee6725d55624ffd8","tarball":"https://registry.npmjs.org/destructible/-/destructible-6.2.4.tgz","fileCount":4,"unpackedSize":26675,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfOAqoCRA9TVsSAnZWagAAlJ8P/iGv9r4dUWp9cQdnxxy+\nn/YotxeU4aAGROI4mbQWY6GilpMjJwLjhiGr7q0N5jPQP9VR39+TR0zydpPJ\nqLDtq/M45BRKFeoV6LPHWln16ejjnZzEUKtHlyZpqy5DyHPty+/acf0Xo3Kj\ntNPTEw2PRBKEev5bwdEX9jzHEw5KlqQIYqfz2jiz6tkZOjwez+rASEiykBYD\n4W3BjJFoTw0SH1FLShc+NrFsbVv9CUECVSb+ZP8BAAxM/5ktiXyLfTJc7z12\nnNAu5Y3YowxhP5Kg+a/K10iPTOiitmG6uGPI8haq6XMc27WYEBYKlfYfcpBm\nok7/YWhlRI+34KnS40nKkzv165/KfzE9We8BQ4yPlApAZnP99zamEKGneDXY\nzOvr0TIzzmGMwPq0+6chuV8Kh2TvxNKvX1lV8my3IxpILrmg+KJ7ORTK9uOc\nKS7bzWFF/dHjHI8bRzJAfIUOXcM+2LvO/6iRKhjWG9pp45bEj/p1NjwOaHpP\nz1Xnv0uimPXTpk0JVMl6WdoYefK1vAAgRci0GdjXLrYQo9Fyu+pPhoSRyxXv\nx09c2jAJ6AfrxHGP4tC8SG8nD53RwIIozTYZjbv66eI/R0D06kUAVJ7lYcDJ\n5Oj0Itn0PXecGH6Rz1x6/U4iKsPFJsj69d2p36uwUm7FPA8fvC3lPuityJmu\n8RPv\r\n=dDdg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIG+59Dkl7G7QQ162VN0kj9fk2Y+tsqEOT3shAjLmGKuwAiEA00s6SdGZIDB5Vi0innSAvNM6t/HkH3QWQiFYGBlcR3Y="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_6.2.4_1597508263608_0.8800828635368505"},"_hasShrinkwrap":false},"6.2.5":{"name":"destructible","version":"6.2.5","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.0.1","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"gitHead":"b8f38959e8123491ff5268260f02413dd2b83e3f","_id":"destructible@6.2.5","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-F+CfqipveHZJCHTUFZouf/cWnmAEQ2e1eVwyZF1dsPPI0putWjWp1G3Y5xYCv61yHsMAAQ0FMRoOYYu0Q+yksA==","shasum":"f382f4605b6dab3af4341d607ccf0c87e31e8256","tarball":"https://registry.npmjs.org/destructible/-/destructible-6.2.5.tgz","fileCount":4,"unpackedSize":26675,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSPS1CRA9TVsSAnZWagAAdBgQAKB9tW05dMRX3D2ujjvH\nhxQ1bbrtGzb0syf2mMRJhFrZrKVSF7Kkn8zWBMLTnR5nZQY6w35PelyTgLK5\n0GNujG/wRjbFXDBAu5xE9yDxYFuKKEH45pKgqh9YtnkMFbIVk546Z54+LU+8\nX6H0A+WjIRyE9XM3ImcBbfMel2GjdJ7cgYN8UlJrtwVG90MEMVnq3vK6bD+j\nmD8rb1t/JBz9MQRMSd7qzB6z5lIMgaxVA+YUe1O+wy6Row5nKPyIyICfzdhq\n7ZNC1GDd8FgKSZ5Osd69eHDZXFXdceZ9VZud3eT5yplU7PRQSN26FCCRLpAj\nbDjI8zVR62VjmgukB63LshNcOcnekTDQCd8aW23IXIL+NrkvNn1pmGly8AI3\ntHBJmcCL75dQINcKifCql8d27GehCvpoFDm07AmpCvzoES5UyvBs9XFJUo+9\nZCqxkEVpBF4+EE7mGhXuFiUvUgDysf2o+RH+UAi376QUUiUt/GVjhsYqcljL\nLpOo42rZMgveOMNp6uEoEXEtNiD9fcwz62l79K00iVUyVvcXJfiST59T0xED\npLbddcsq3YVyZx3+uNOhUzdQrDYibyVeayAi3kgEC1xaVbm2TuKJEPbJRFo1\nbph/WzOEmoCtSz/QaFr/UWG8KGNWOF8SCGhrSNTGfcqI9c35G4aOuoQR9GEb\nG+XK\r\n=2swI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCsce0D0EJkjGC6qxPjYMEv7YM+mGKa8ntdVJSmd9LTQQIgfPO801Vwup+E0qNU1V0EsuGhIHp3wCV50R/7jpUryaA="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_6.2.5_1598616757301_0.6368960351721022"},"_hasShrinkwrap":false},"7.0.0-alpha.0":{"name":"destructible","version":"7.0.0-alpha.0","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.0.1","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nEither monitors a sub-strand that lasts for the duration of the lifetime of the\n`Destructible`. When the sub-strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed. All exceptions\nraised by all sub-strands will be reported from the `Destructible.destructed`\nproperty.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nEither monitors a sub-strand that will not last for the duration of the lifetime\nof the `Destructible`. When the sub-strand returns the `Destructible` is\ndestroyed if it is not already destroyed. Only if the sub-strand raises and\nexception will the parent destructible be destoryed. All exceptions raised by\nall sub-strands will be reported from the `Destructible.destructed` property.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `destructible.attemptable(key, function)`\n\nWhen you have many separate stands in your application, getting them all up and\nrunning can present problems. You may have an error during setup and\nconfiguration that causes to halt your setup and configuration and return early.\n\nWouldn't it be nice if all the exceptions for your application where funneled\nthrough `Destructible`, even those that occurred while you where getting\n`Destructible` set up?\n\nThis feature is provided because I personally enjoy test coverage, and will\ngladly accept the coverage of a dependency instead of repeating the unit tests\nin dependent projects. With this feature you can simply program the happy path\nand trust that it will get captured.\n\n```javascript\ndestructible.attemptable('main', function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = destructible.attempt('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n\n```javascript\ndestructible.ephemeral('search', async function () {\n    const cursor = await strata.search('a')\n}, Application.Error)\n```\n\n### `destructible.working()`\n\n**TODO** \"sub-strand\"? Why? Why not just \"strand\"?\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n","readmeFilename":"README.md","gitHead":"be6ab8b321c90ea9ea9c24665108cc38f5f7e6d1","_id":"destructible@7.0.0-alpha.0","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-UhdhJoMJP7cQApxf9MFBajlXUqN08eRJUwZYQpNKlIDLNNQUMJ7EsiNb33LQ/62258ZUJ+AW0JqvNHTs/yLJ0Q==","shasum":"f3d5ded206094fb64b48f756c6f7e6f11f2740c1","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.0.tgz","fileCount":5,"unpackedSize":37495,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfUdJOCRA9TVsSAnZWagAAQ6gQAJ0ET7lXZQ1CBqHjJt8W\nv1/yMyU8oSIcrshEfM9qq69QcYqxulKP1RRSIT7MMVgT2elirrGEhNst6bxg\nNoT+48JsEJOCwtR9XyZcW6VdifDbumDBduXG5noTWx6QHDcCtDWK0+wCz4wC\nryUKqf31beyUMS0nMw0y/EC2dx3PjiNX4EQPjEwoavH7oGvMzpcISRmkaK+x\ni/WzchI9fv1OBAZ4RgRvoyQ+q7iZCV8Sua45ao0PTBlaoFdcvojIoYYMDZrf\n3HrjHlgZO4PErlYyOMRSgvbwFuYPf9Rcgv4C54S3fl6a2zz9kj7tv/ErxQI4\n3YBC1Lx0aN0dI5xua6vc8Pph/izdescYBpbi/+8dXHqM/vyNxST9ZZ06/28J\nx/kRFeG3wCFlIGZXoSFDEoCMhpZrFMYhhez4IT0T9TUMdfNn8U2u7NhuEXD+\n7ouDtUSoKXOv8mtAzklbJcWKZC9faM8JsgGEZiwFH3vxT654FClgSTtyVcpF\npPNfbfdbg8qcAk8eIoLWnngh+yBfyqI8Za0AYw3W+YBio+9Sw9hTAIQwAoBY\nobFbeaTJ+XLQe3D7bNDKYz67basDp7tQIH6hAgTIpHPudSFPhRto9iHy7OV/\ntOkQ61XOpnlpRfIdV+wPwyNIJvMIEE+lR1cMFlDWIg0B7YsaBMimdVzaiphL\nKZjV\r\n=0UUA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFHf+KcwgiGx7oGTHF81SrzF0rF7rIymr10pR/w0NpEhAiEA3hemIRDg8Pn7+mZEaVjuQB4w2Qfinpee+Oo0UU2Tv9E="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.0_1599197773621_0.1891669696674596"},"_hasShrinkwrap":false},"7.0.0-alpha.1":{"name":"destructible","version":"7.0.0-alpha.1","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.0.1","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nEither monitors a sub-strand that lasts for the duration of the lifetime of the\n`Destructible`. When the sub-strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed. All exceptions\nraised by all sub-strands will be reported from the `Destructible.destructed`\nproperty.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nEither monitors a sub-strand that will not last for the duration of the lifetime\nof the `Destructible`. When the sub-strand returns the `Destructible` is\ndestroyed if it is not already destroyed. Only if the sub-strand raises and\nexception will the parent destructible be destoryed. All exceptions raised by\nall sub-strands will be reported from the `Destructible.destructed` property.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `destructible.attemptable(key, function)`\n\nWhen you have many separate stands in your application, getting them all up and\nrunning can present problems. You may have an error during setup and\nconfiguration that causes to halt your setup and configuration and return early.\n\nWouldn't it be nice if all the exceptions for your application where funneled\nthrough `Destructible`, even those that occurred while you where getting\n`Destructible` set up?\n\nThis feature is provided because I personally enjoy test coverage, and will\ngladly accept the coverage of a dependency instead of repeating the unit tests\nin dependent projects. With this feature you can simply program the happy path\nand trust that it will get captured.\n\n```javascript\ndestructible.attemptable('main', function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = destructible.attempt('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n\n```javascript\ndestructible.ephemeral('search', async function () {\n    const cursor = await strata.search('a')\n}, Application.Error)\n```\n\n### `destructible.working()`\n\n**TODO** \"sub-strand\"? Why? Why not just \"strand\"?\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n","readmeFilename":"README.md","gitHead":"55c33b12cf2517d64cf0b3520f7c0d9b028b53f8","_id":"destructible@7.0.0-alpha.1","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-PF0Uxb/6T4PWRGIlnZTNKUuAr/o1CE59P3BrCQGHH9c1IynVKDaAqbxEzExHQrsu9Y5XRSZpWOuuNBIjWflOaw==","shasum":"620e36ba9406875eb967bc1bc37965f20d48ada8","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.1.tgz","fileCount":5,"unpackedSize":37276,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfUefVCRA9TVsSAnZWagAA7ZoQAJXJv0F53lzLIY3mNhpC\nODZWe5/eJVumore6EsqFCbFwy1ftp7NGUzHMJYOBMucqoTHzUxwaxgrFjfCN\nMTcDij32rZNAMhsjcSCOAJPR4gxAeCMpXfrKCf19J3HgujYlb0nPr/8zlChM\nojafrurh+CRo3P7Tc3OgabsJGif7yHDGI6sMrwwr0FnkVdMvpCtf/298++0W\nG+Iuc02jFiMWXtccogIqgWKtNmUA0I1s/vDrwO3hO1b9M0saD0yiTtX1GLxb\nQ08BQqq+nWvEneI8DQTMueuS97r/rPR/xJILWN6bcd4TxUlSinPiAst6fP6j\np1bF1MkP1lPn5mm4knCWF8EsjDyD1gboNvDXYgyxxbIgvaB6mPNJGTLfoycJ\nltbDNHOz4xSVwACank7HX/VGx8KaCpWyCirINkC4SB8hlkEwnpzR29qbSL2T\nDAynlPHh+cTujqnsMOTT7k1L+2PgqDX4+mvrtCiNfivRC6VkjXAzPAYSR9BQ\nStFaD/FKwr2JPXF+TNOOZhK/YCZONI/vCYFhk6VRQcp4qdI2XDEyvfi3/Q5I\nyqrpIruFqWTZLO4p4wRizBPg96YgK4BUMbr06oqQmxvKr6Mfg0O83Hru73CV\n/dAw542R8h3OOCloVsO+8oGW0JdhTygnnNGmrt4jK190kRRvJA3QoDLKAVUb\nuGLF\r\n=R/rD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCLEzeL3owsOaTgGNHJGtptH5yZg1Omuzi65TLSaJ/9aQIhALYwu5kP9cbSNqPvUls77CRrpJA3Q87GHMc3HhyUWlSx"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.1_1599203285365_0.581331045496448"},"_hasShrinkwrap":false},"7.0.0-alpha.2":{"name":"destructible","version":"7.0.0-alpha.2","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.1.0","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nEither monitors a sub-strand that lasts for the duration of the lifetime of the\n`Destructible`. When the sub-strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed. All exceptions\nraised by all sub-strands will be reported from the `Destructible.destructed`\nproperty.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nEither monitors a sub-strand that will not last for the duration of the lifetime\nof the `Destructible`. When the sub-strand returns the `Destructible` is\ndestroyed if it is not already destroyed. Only if the sub-strand raises and\nexception will the parent destructible be destoryed. All exceptions raised by\nall sub-strands will be reported from the `Destructible.destructed` property.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `destructible.attemptable(key, function)`\n\nWhen you have many separate stands in your application, getting them all up and\nrunning can present problems. You may have an error during setup and\nconfiguration that causes to halt your setup and configuration and return early.\n\nWouldn't it be nice if all the exceptions for your application where funneled\nthrough `Destructible`, even those that occurred while you where getting\n`Destructible` set up?\n\nThis feature is provided because I personally enjoy test coverage, and will\ngladly accept the coverage of a dependency instead of repeating the unit tests\nin dependent projects. With this feature you can simply program the happy path\nand trust that it will get captured.\n\n```javascript\ndestructible.attemptable('main', function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = destructible.attempt('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n\n```javascript\ndestructible.ephemeral('search', async function () {\n    const cursor = await strata.search('a')\n}, Application.Error)\n```\n\n### `destructible.working()`\n\n**TODO** \"sub-strand\"? Why? Why not just \"strand\"?\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n","readmeFilename":"README.md","gitHead":"36c726a41e85a6463317c042eb25863a72f03701","_id":"destructible@7.0.0-alpha.2","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-miMoUGgqXJyQrmfjacLMs13BxR4hIibuK2gd7FjWvzPTylQfB1rXUQKgowVAsKJhtpUEzxqWwwZnBNTPlrZDoA==","shasum":"4cdd1f70e63f257ac0ce5d7ced099bf59f585d95","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.2.tgz","fileCount":5,"unpackedSize":37276,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfUehsCRA9TVsSAnZWagAAmnAP+wdgwJ8mrCyZ8aLf1Kq+\nN0DO5u3XBkYIHOfQuytkWjIH/Ju5/a8d2wqAqj4jeHY0R/Z03TIDiOH6R+U7\nV4Cv2SBMh4abW3Msd+kr3nvOtPECQc3EL/FxmK+L5gPG6LvOIkBUZABnZ82Z\nQHEkCvVx2yNrOHE1NCQM2WLtGcF4wXbw4GzxBrP8231IkZOaJHiavpxa1J/n\n9grpv9BQ0vH7j9cpR3m5OTNZa9lQC8S6cgzATj0+Ky/Stmm1cE5Ac83qLpDh\nPmXshjMwkD+k4lBSjFMIGy/wJUcSM/unZFjcZEotBdiXRGa8S6V8S7tk13w2\nzZu24DYmNuip5Cd2LXL7Y8O1VwnVAMNzhk8v2L/dPexFH2qyAkr16TXkdb1a\n5cKJkVaBpaaEcZrYOJ3OxvC448zb5Qbn8N9BdL5e+BqtLb1ZkMN+yhegLW4c\nL/0Emoy+oRhNy9ub0weaAPPk+97djuGfjPickV8BehkjTGqktZGFrvW0LXeW\n06187CbQCu/W29K41TlE+m8lkPbhIpORyn2CZMmnfnGYkPApNrIEOJPy6F3s\nl4Bcx/VnP58WveBbJRC/VGwHpPlnP+4g1h0H8CN42nrz9VInqKCes2s9HkGU\n8dfRepKUH911kO3KxHzhl+WZT1TL0f1vl/3RjZOcyYUwKBL1+FZWyoB0oFDR\nNLvU\r\n=dC4k\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCDZ4e6SrHv3zOrTyqwBsStAwtXOIYw9R0qce0AHiAGxAIhAKlN44DMwlHhMKseKsInBcGDKCthfnszi+ebQeOjh8YQ"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.2_1599203435623_0.9656195470995226"},"_hasShrinkwrap":false},"7.0.0-alpha.3":{"name":"destructible","version":"7.0.0-alpha.3","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.1.0","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"c44fdb100120933b64ff07ce4a6d354064c2f935","_id":"destructible@7.0.0-alpha.3","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-0y6M99K51Tn6wz8SCJ8SidMJ69gTOBku3Z7RF9/ukXwSBTfqz9Njb+PO9tssx1B/WbM6AhEuHbbmxQEJ3zDHpw==","shasum":"ecd9585d273d100857f142ce4c5210913aa05764","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.3.tgz","fileCount":5,"unpackedSize":40322,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfU8miCRA9TVsSAnZWagAAo4MP/07Tnfocd4LwTKx74YrE\nQ9R7VzYw/c4CX7icSPdzb7KpfJ4JTwPKESSEjR6I2p57EyxGICL7KxveKopD\nsUdmSZTLEveDT4BUtwyU093l0h7F9P9zrq3vMBRNOsln6AC2U0kM1zMusjoW\nwxhy/C2u1AcMJK9ioVvNTj6S7Fjf15b1IkkUFWM9t2AmbzCFy4UzzrSHbSoZ\nyoBoW/57bQwGjDjTuxWug9cKNu+XgnhSPyNDDpJOwCEu5Yr3ZjdPdXlGZ6eb\nCssCaL4XbVshTyDaGBVi2593EMVFZlyZ3aYSp6VQYuknBF/nIq3jzC2FGROJ\ncnH/8msew8/j3UNwCzFX1PWilriDFQiWsLte++b2W8eX5EwqQHSgbMadQdA1\nfDBb5fxGCxuajlfyV00lmjxf+8lYXICV07oTHC2jh2gLagKwIBJSldPGVzBK\n/OhQXoX620w5B90u++0COM3aqfvLsqTLZGyp1QplyVsh28aSirtWtdX4LFmm\njBBmZARKcBYoJV2viygKK8kbIbO+V5AtNyOVZ4ipmzEcq6+BaA26nps9b8Hr\nSw77xpKtcKXVgtA365/5iaOMCeS6vXzNEAfKa88pRKd4eZGCrrM/W2vnfjrP\n+nbijuOuu3acl8vVllTX+ohUel/1vfZida+y4xcDg5Fdnp4QzrzuVQyQ92Ee\nSwRy\r\n=K+Lt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIE2Mq+j4Me8H/doZQl5CXUUj1qrXJj27IzhcmU6z9vlmAiBqsi5TedgGiTjCN7qETycs6WkE20Kj7n4z57qOXp+qMQ=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.3_1599326625894_0.02768465598703651"},"_hasShrinkwrap":false},"7.0.0-alpha.4":{"name":"destructible","version":"7.0.0-alpha.4","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.1.0","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"5eea18c2cfe03ae5201c7b68853b3378b98b6bee","_id":"destructible@7.0.0-alpha.4","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-gIDMnI/iNik8l9yzLqph4LXsXsLzRBXJ6co6ENZyTufAf3F+9qDLbpttuhENjuG5mBlz0nxKUn/ATxvTjAFO3g==","shasum":"c8e640a4c5d8131ef54d0dbaf4b03f1c2614c305","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.4.tgz","fileCount":5,"unpackedSize":40322,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfU8vwCRA9TVsSAnZWagAAglMP/0sdrYTEB1Y3zs7GWmuX\nXB6KhYfIUHRfYpkmzJJ/l/tqWYrFcKeBWEQcVLd0/7T5xHQxa0Q2gnxo+N6I\nnuZtqhhRqUEU9VOBPj5XS0OG4UrV5OxNg0FsLut22j3HhaYXBExsnxF4rbl7\nFS84tOcdvqr5koGVmhQQ3Qp9hJUoZ+5lIvoU0RLV7KjdsTE3C9S34Hvfdg6K\n4feN3F0GTzahyu6JjMD5ffsA7FO+9Yp/XXFb7HLGd8fDf1IaIJqYlQGDG5Kr\nBUlSkgJp3rKmBtQaUvpmJBdJ5MVzpN3/ZUFTp1Dl/tg2DpayYWCHBYhhtDcx\nEeErrbmCZAy4xcrxVBaYJQoi8tbn+gaf4F7pSlgZyvBryC5DpLDLhIowt97O\nBRoO9ycY55kGawv1cDPhXccBNGxZq3rJMJp5t4aBu47/YBo1N4YwIelz4rwq\nkjeurjlhWenG7N2gicNBveiZIIpLZiLvZZOxOQfwd3+9/O2qBzE5C6gkP7bs\nuVKGJ3t4dWrH5EvNgHJ9fviz/MaasS5UiXlqkRZmcdzTua72XY4YcBsGUYXS\nlTErg7MKkd2x7tVmA7kookV6+3bgpH44V/hjUU3qh55BdfARcvopDbGOM/LC\nd9LaLrS6JO98ooFyf5Qup5j3YKXn0ST8f40pkPzOPH4YO4bvPEi8fAI/+WB4\nNgL5\r\n=nEOB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDCMWd9bYPCEqntJyQTHPACxp9OvFaMsWEV/WYdC04sFAIhAKEVFdrwVuV3c/ZqKKcrN96u6G24RHJWFeXFkzmRG1Lw"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.4_1599327216435_0.47209571086648516"},"_hasShrinkwrap":false},"7.0.0-alpha.5":{"name":"destructible","version":"7.0.0-alpha.5","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.1.0","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"c83aab932b702b9d6a0ce85b7c86b8804b581768","_id":"destructible@7.0.0-alpha.5","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-32bi2axaWda7Yfs3lMeyr/A9cznygV3NSLeocP7FUEF2na5WLy/+s3IUBhZ4sp8IKBeeoFZWI1eEP9gawK6ZAA==","shasum":"618e01ad2c4a293d4f3c6ff0fdfd77ab98ccbb3a","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.5.tgz","fileCount":5,"unpackedSize":40347,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfVCmJCRA9TVsSAnZWagAAXDwP/j9HEeCbENkheNa/6vRe\nn0nxfSBNW68uC6harEzr6dkRcqy1Eat0/1/z1cRN9wEXFUkq+O2iRB2T9pa8\nR6ZcxMVAaXsUYMPQotoGwT0Wn1BiuVa9qzqvMymwKqGGNyROUg6C2SCmpSG7\nuF4JoRxy3W0j0gEPkfUv6ljSTy5VAYO+32HodCPtl/9r7MzGkZ9BH3v8Dy6A\nJPm4u/BYk5IWGZcwTo5GyIYxOX8q4+O60Tdd1uJri6frgFh2FK//7f5VtPFp\nqcDIAlR/NxGZpCrUK9VTLxwAnP9NCRrvAQcBTO1txb/rv0CA5Tlj7gHe14+A\nhLT0EfPiPWtAw7mWAxhy79H0ONc3pj8Itim/fjs7T0ovfhBN8lWnHZWHG8B8\nXMgKxrruv1PqqJHnGUTGaGuCG1mgnlyIA4CQj0R3oirTMjJYkQ1snRBibhat\naap3z5luu0G2w/G6QF/dYQt+AwqDYJyLHZpDzjM1Ru5wcI9GhVuOvYs6cYY4\nIRNUPXvd4HPrX4VYB4CtiMY0A0F98InDUycFCKAmKaoh2RRfWev5nOtUTiBC\nZv9CASkBH8xzLDPr4/vHEVb17H/Pt3JcnJqikVSUZRjr57ThvzmY/6SHBcCe\ny1lFTVaQe30JXet2FY6YKyLbLGOHfcgpevSWbY0OBwPSeJ3pSKvZ3p4Rj7Uh\nqOgo\r\n=lvjk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD2oFTA8zmNS8pSOI8crdxVEu9VklRJ21hyMCug+Y/0zwIhAJkm2dFjY7x6v7ejOdaT5JBkNCLEAmlRlybpUXnjNmm7"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.5_1599351176962_0.1080912366247253"},"_hasShrinkwrap":false},"7.0.0-alpha.6":{"name":"destructible","version":"7.0.0-alpha.6","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.1.0","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"9f1056c594ca690ab415149016a7d92f24ec0154","_id":"destructible@7.0.0-alpha.6","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-szXPDJyLfML7+XbEHe8PhRZ7xmzPbt0XghvBJcurTjnWbOehy76k/ymN7oQBkrWDqDpwMAnEDV3fmdnCVvpHxw==","shasum":"d08652f69cb4b30e7edcbad04589f6f407597b70","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.6.tgz","fileCount":5,"unpackedSize":40204,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfVJwgCRA9TVsSAnZWagAAJY8P+QGeNwhT+W71ZZW0goCR\n7pjP22KaTVlU7cpnwLm23SXOMsNNSTJ5h6IZnOFaS1rV539w2ak96JMXKGFA\np32bIoxbaqlIwUvzzcyHb26mM+YGNVXl5kwVii5bs1vx2VbF6ogIGmGzaoZ2\nnQ7wxqp0ZvKz1RfSGzdxFyBcWT2t9eNIfquvm9ZIWn2tZ6puhc9Q/3nzHROz\nPJDsoFinSfAhfxZ+eblNkh4RfW18FjzA/ZmrAErzFb7iRsqRYJx1WCAQhqy3\nW2qJM28oxl0IlBUmqYq7T1t0ahvLCNC4SyUnxYmNkUXfNjOmdDDj37jItmIn\nZ8xc8RZCbwdEw3qBSL9b4Vl+oOj2NS9te7z2FCdGiK/3qfBZyqWVGEVJw8by\nkfR6f0CdtVhv123uW3urdrJ3ierfUFHFTrnEtvvX+qTg+yHWxwhl9TuyLwjP\np/sbrH0hQng+T+DROI3qqYtAWXCBo1eUynOi7ZDGqg/HBfGdZEIKCPw8jZug\nKmAGcYXAkhAhukXB6OeKk5rJqg8eWU2zWS+xnkOYoVteOMY8h4vkEsFTbQPh\n/DOlUomikPCmSPHCvixk+I2axdIgsGNu03S44zJ3wlu9cYy2tIfVdqU9vEu0\nX9eflnUtcmO/RGa+nzLlV2r1ZjobeZ8Or5/N8/xd9NtlYzAmZrx0TR0HP9MK\nwwrI\r\n=+XFk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH/V2j7KEESasbTbWSrs/My7MM4MayhS1i220RYZd7LeAiAJCBNHEyr44NMiKko1yrCZq3rK8NZ6quFvI0o3FzqNog=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.6_1599380512170_0.4403016306851919"},"_hasShrinkwrap":false},"7.0.0-alpha.7":{"name":"destructible","version":"7.0.0-alpha.7","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.1.0","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"ee0a052a06c9006e806d7b12eb3622ef1327c0cf","_id":"destructible@7.0.0-alpha.7","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-ufdKjDNJGzNv6zARFlSf6/Ri5TWiAzpMV6JV9272PTJQTC+hq/tUJzccTVzRYsWcTUjfUtqDHT3bo6F9YWcTog==","shasum":"9bd79376dbfdb48e3cc5135a59a0f788a04c1a77","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.7.tgz","fileCount":5,"unpackedSize":40344,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfVirSCRA9TVsSAnZWagAAjeIP/28WKyDxsHjj/YiTr2TH\ndaWUWWyl/lbSf944r4k+M8bax4WM1LcLgJsFcgX3+wWfVuCGdSExge2jj8IY\nqWGb+5z6AIeuEC7WGXMG38/XHXBiO4ZmIHPenZJfgSTWLudnERIf39x+QnuG\n1XEFkYsa1bMLYeCYfjeU7t/1wIsuGm57ikVHHAtTrkUj/9N9KMTt/tAanu0T\nGyIavVunwX5gEzMfYO/3tNt30KutyK7UbWmOcn1h7yEdKlU6N+P+CTy9yHbk\n9bDbhapsTmnKayhaC9D6cBDI8syz8mB0bEvGqwR2oOuh1JPVn0Mfi0Ox+ybE\nvNB2ezQd64z63yOUPtGVDoXItCxa041a1W34DgPpuyfMjMlQZGn6qkOxVTxH\nHbn6k+mYV68t7KzJSVUteFcdR0UkeNHd+kFZp9NigsPTuEuwYUij+l1WuXKE\nLWDa95Pp4edV7VacVCslT2F0G9ueAVp+THDn+qyN/e6IKx/DSkm+XfOODa+V\n7DfDVANr1VK74s0PegCGlXbiMdOU0U7/FS1EpVvDayAHT7PfLy22Dyvi1Cmy\nC7OKIp/g41UiBVPNeC7CPmaTYLvR1QfECghI6SPbScfKqBbu5TOxgV3HIyWQ\nYx8f058qlaNUbkhy8aimPshOTL5xoWaUP7umnYP6jaRyFjcOs5BYwoM1ggdy\nGl2q\r\n=wUOu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDi4nO1ljvPpszfdu37N152CABauasxtzOePsrlcEThlAiEAlxoami0bP3d89rBPovHCFIsl2ONjZRThMo5WvQzEPhg="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.7_1599482578184_0.05066356756260593"},"_hasShrinkwrap":false},"7.0.0-alpha.8":{"name":"destructible","version":"7.0.0-alpha.8","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.1.0","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"765600eb77dac369235852c2a8cba3462c2f0b9c","_id":"destructible@7.0.0-alpha.8","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-nNyfdgHBNoR2elvArSR7AYFLoKfAPENbxDPkRBCLUIEMJ4mn5tdUwJq8vLj9wqVuA2+pZUAVPAyhTQhM97oZwg==","shasum":"33450d8e03a777f781b783f32f5c750a1451acc7","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.8.tgz","fileCount":5,"unpackedSize":40382,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfVm0FCRA9TVsSAnZWagAAR/IQAIauhBqtIVdLcI4qHaQ3\nDWwHgZGVgFHqQsFC7yz1tNduhXSDotURGpPcQdtOl2N4p6Nqylqz+gOIsPRP\nUh2gCu5py3eslFQregt1L1nJ5ivMX0PxkOIDwzt05ea98Eqs180iRBQuhSXv\nRaZz2NxYeCc6JJu0q3oW3khCpWXHLmkd3AsDoiaz63wLnaBrR+eQTblLI5b9\nf8lWG1uvVjX53gMCDwYQ0fpvIV5QjK7MYsiFIAOnjcsOANcC36I5lmOja9/C\nnFSNBKlPmeIt5sZ5pCiL6d+Wm1yabj9e3J3+md6pSKOVz2FCBvCwnJb24+0q\nUjvtvX2ugZD8G7YNvdU8ZFnl8Fbn3QGNOyW26mtMhwsd8Y62Ro2tKzeYoiFL\nujdLMbiFc126ErzKTsDCmAx/1ZOygyeJg0CC/EUXatyqhAEwV6kJPY7mz33x\n1xKjPaUE7UFXE509mgyzlJHfZ60wpF/qaVZJQCBveQtosjdiMzwIztapm2ZC\nG25UxW+oviDX9kzBSuAVnogIbuoJYo20UcRLAU5k2iujyjyKRqvhTWiVXAzJ\nlWOEvRL/8TCTa0kM4DSbTbbnhGzLcxU4fOTlmUdd35byFyhJGM1gCKEoCa+n\nIfxjYl1YGP1Mrj/1f5/8qBf4UhJYJQMZNtLWXiQ83HnBzUexNl+KHVYUgbZ+\n5MxL\r\n=8m1Q\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFKq5HSA+jt8zUjs5IcPOadaxna2IJJdhMMJNQDL2YQiAiEA4HxYqWoGxg3sAvha138XxuGQ7QBFFHe+nWHx9y8vZIQ="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.8_1599499524507_0.6269465392505014"},"_hasShrinkwrap":false},"7.0.0-alpha.9":{"name":"destructible","version":"7.0.0-alpha.9","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.1.0","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"2f66d524b57d522292b2a3b622f4cc76a82d30e2","_id":"destructible@7.0.0-alpha.9","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-g2NbT+DAmVNks9MHrgNWYiNFhGX45Zoh5MuofY7rEIlUflb1hErWaVG6P81IYlFfKX3stUXKrDuWYmAEbsl1ag==","shasum":"8fdb2c8ab24e01381649091a14c8ddc65f69a27d","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.9.tgz","fileCount":5,"unpackedSize":41542,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfXd5WCRA9TVsSAnZWagAAkwAP/RhZU1Sg+4nZziqCB+YK\nq+oF9PTVQpYyt2be8ywem1V2m2TpLSvsRDuLy0TOWNGAwibeyG8jdttDfIeH\nMovoDcycqMTfCY8b/5eT5YRHldIQweG78JJ67QYGCTqeI/AFyfGdFtuvwepV\nJKW3hPwG6jThNPaO+TF+j0+ZhdYFO95KfhnzqS9xUGvhhaNXDBUcRVKR73Yv\nIjSHTFoyJVXwWHU/VpAte7DUolhF0m+T/8TAWqi93m6xKpeFRn+eO+t7hVSs\nw5hfhN8odNPw1jzG814fyRK+IwECof80EdZmi2p37Xe+AQaxCH8A5rnocKzx\nD5HsUlcNPddFAgYMq/9j099THcOqIbO0dE4hZCwIwLEa6hlf6Bxz44+p2sgz\nov0Ta60LoGprU/1CJuDChqtH4a8U1yOxYSJ2eK1/2rEY3qbtWIhvgHiCzWja\nPpPclWf2AEp2yCbGGnFojZq8ALnaDQOEOCL/pb7qSyV9jB9apZtmWAXKOLZV\nicdfSwyhdMwYU046U0+8umSPQmDGS0Bl0S9NAVtD//b7V0jtKRxA2daAswma\n25WzpUGwI6NB1f9P3b8+0Sa4oB35R/dQ8DkRkYjulr9cdlEWiLs/e6zD6uM7\nv4LQUPZVgowZtlRIOsROFiF2r8++P/JOtb9IEpRIf3zdsGm9R5WK9oXhQS6F\nqq5R\r\n=AnvF\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCWZd1ehTE5P9cmPwDGIFhBtHi0ieh4pVeWjteKL2py/gIhAPupzfHA5oVWYM/dVhtVIZ5ctuOLLTVRuY2h0eTdZZBT"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.9_1599987285940_0.9794036491347129"},"_hasShrinkwrap":false},"7.0.0-alpha.10":{"name":"destructible","version":"7.0.0-alpha.10","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.1.0","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"56ab8eca7527d394ae3e50ba5787a67f5950134e","_id":"destructible@7.0.0-alpha.10","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-r+60eR1Uv06HXbPaMcECCPrrcMIFmVswmkdEqbONE5LigVSTAsu3aWk2lzxs+09G24L3GFwvdH+slVtgbcVREg==","shasum":"99daa7f9a86f22ccd53728c3ba97e2a1a5a49022","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.10.tgz","fileCount":5,"unpackedSize":43362,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfcEr4CRA9TVsSAnZWagAAPVUP/i/+bgMCs3yPEgnfmYRu\nvqrFzhTrnco/zpm5DwYsq4mC/yJAIYZWBt8hoDnkUhtQ0OjMQDURGFIL7Mv3\nWk2OfO3twZ+G5NLMDc+3zi0t0ZpevVh+icNyx85jCmfqY6k/Q6eBrP6S+FQ3\n1vZFnGUnJTaNwbk2lVcV5MrsOyb6C4fh+B3xCMikSswYj80WAgsdkTD8UJCe\nZMWhdwTQvEO9kZOoycCazGbsQORyexY+izy7TWZLaAwUd63kSoPVCKCraivu\nTUqZqxNGE9a6cRRLOo7ymTTVn6Zhu947tct2PdZWFdflL4rn80uS5Mr8qPvK\nUBTtCsstOLE+pl3EWKX4Dy9VmISJodk6mcpy/Bdv6BgaNSYYaUDKuhdi3Yg6\n7HtRyvqnbWUOcqPmi5ExUPJS2MI26SwacCT8nmYD7icbIkfFLVzPaUYZLFaL\nmMPUwJvMI77K1OmCjZdxbFZm0qQDLqZy+RLnTu9VSYkEuX8xKPkPd+hAg9MJ\nE1fvV61fDkcQJ+tPzEoMepvC2anSqIvbQitoN9oyz9hSn0Z92gSly0Jocmj3\nk4D3mUW/J5AEGyPX5HMhUI7bFTaQ2c8UCEtxW0UiTIFinb4gVry+JuL4lG4j\nojv/C+JUPe4icRgOb4i40MTpuQO5sbtepwVh1aiKUfHjkHCr7+hSZyg8W4PW\nzyOJ\r\n=QN0G\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDcGxJ2TfaCIvDkNepd03rHXiCANSp2HvueOy0b1EB9CQIhAJNfchrt4ipv+IZqz5iQK/hZr2UruILiNrjb6UFNdVx2"}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.10_1601194743501_0.2704911890660444"},"_hasShrinkwrap":false},"7.0.0-alpha.11":{"name":"destructible","version":"7.0.0-alpha.11","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.1.0","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"0928a16605903f563253816c4d90c962860ac5e2","_id":"destructible@7.0.0-alpha.11","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-/BuOGeHsZjq5LyEpPB/7qnk7tEc+wMyh4svvviPvEtdmPHBCCnguB//s93U3fKGv/DUtwyAYSNiCLJ3rKnpoVw==","shasum":"8a16a0029281a303cbe8e1788cc8bc20368ba923","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.11.tgz","fileCount":5,"unpackedSize":43383,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfcQp1CRA9TVsSAnZWagAA2c0P/ia0NR8W0MEzARx/U9Uf\nTnxlAHydDlA7qx7IdWHwxm9mSR7OlW3OVqQKDPEB3XnNxVHv5YzSwwala/zK\nkExg8pvQkyomkbzjdF/BogiK6MB3QOuuD00Cu/lojPbvjlJFtXUsAoJYxDgo\n1XXUrYPgyRkwzyTOQejVYropYWGyIxFeC0AlnsN4p0wX/itBdxDqxukvuTri\nfe0LTuwDBb4LTOrhBNy4dH/2qvNfA/G/tu8NDfxklaSFRa5N63g555pNwnCn\nw89Swt453WMiWON07XhZVs3PBVxWN3PsyPe5i9jCdgOeqx39DpKcgIsz7mmT\n2MxgGe/QYR/tterlbUQ3TwlOsJHQu7abdZwqOfb6JCWvWcjAu4ZR6tMIvZWC\nElYaj6LJXc50RE+2pWPZ2fJwgTFX+q/vlus471HoiotdyHUTquM4dlZAtCYd\nnQ/Ksf+UbEoK8+QafZ6aNfV5UeOzBxFAYLwHWutZUV1kaGCetC+MUHfFN2KO\nsipbrlMLgt5OAf+zdUEgYczduJAYgovC5AU0q2Yv+q21HkoEqI6JpBiL8OW2\ns8S4QmgvZ5sETf01lvPxSfJe05yAUTQUocRNRQHeyh/vlKSSFmsiFN010J8w\nWa7YRu6LsYBDxydCBhCxn9cn0k6EOlqP7uGtVMlHoRUtc1ohUCnuwx9h7dIt\nwWlA\r\n=YrZk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIG4wQ4yta2TS+PuaiN102RtLilbKTSV8A5mFMvp95ALhAiEAqpnyoFHa0rBqMwNo8cyXJ/suUScyCMo+UqVJvgj/x6M="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.11_1601243764740_0.6436634346370955"},"_hasShrinkwrap":false},"7.0.0-alpha.12":{"name":"destructible","version":"7.0.0-alpha.12","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"^10.1.0","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"ec781b6c752f6a41ca98ee98df053645a26b9dc7","_id":"destructible@7.0.0-alpha.12","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-56pV69IfikzPGyOHOmvnoK/lzqDrW2RClgUvKgMJuSdwr+xJs9cdtarKJsGjHAHral5FCtqdo5xDHd4lqKLSLQ==","shasum":"9635baeec91b29c7f96e9431318fb40bf1d4e84d","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.12.tgz","fileCount":5,"unpackedSize":43340,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiEJVCRA9TVsSAnZWagAAsZMP/jxSQKgVJ6YD5+rWWn2A\nIXh/OHze0QAh2lrrW4Zh90bq6Qy7zQsihjk7MF2DaymSM+OWKaK/oTUSXIuS\nEESRR3t0pZVn2zAYYaLFXFMdlNvawDv0Vc7tmKxXIvW8y9J1V9ufcPLQcF73\nar8SCvAKdFOCCh4kpbLWnTsxsLLCKPEWhMxaZzHDT5viArwh81XDyEn7GVpj\nJqGt3Huj7oCA9WNLXPPvkwaCVzyfrFPY+OxqBmg9eBLI6Bak2xa/hAy0JXr7\n68e9MMdg9RkyBRheBP7anwJv9ZEOwQO2CvQWfe+P62XhITPmQnNUg6nITgIf\njYGnOneJP6aRqBTcaSyegGgG5PlNSDPvwIgIYSHXrd0F5/LDBKaifZwqPILg\n79DAIWC7ks6tHFbsYZNDYKz/bbp+vG09osseFNYBujcslOhdqSYc0FFsNvvm\nDX4zH764lqQGYLonFy7/te1E0qqRfaNnYT0McLzLbUnOilpSe1+BT6KTxehD\nz9r6XbQCOYl+pb+mVrwIpgMaFQg2h6w1G+woWL42dkH3i9eLavX6rNWbHaf4\nnPXdUrMQkM+Vjmrgs269DKrw8dseqQeOZ88PTxWwhtPRGNTko2DBDFrYvMR7\nVPclOTRaDAfJpet0gVx9RVmEJsFCL1ruH37Ns8mLSUoUeDNkl2CEkkth9A4L\nfaLF\r\n=PPDG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICkhg5smz8uV8daLLYM/2gAXh6k9boSDeh6hImvvF/HjAiAjvO9QNQmF9aj20lbA/HlGXH0hTj0wpvP+43Hcf/bo5A=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.12_1602765396431_0.8459960306029248"},"_hasShrinkwrap":false},"7.0.0-alpha.13":{"name":"destructible","version":"7.0.0-alpha.13","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.1","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"2b761c69030ef54647f8f2f3d9be6e1577ffb5b2","_id":"destructible@7.0.0-alpha.13","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-Lj341jM4vjmd7tmkWi8fcV6hTRmDo5ENl/Qp5hIdbQANgFrNo5PbWCdrYXMkC/EQ4ep8T5/sMbfgGJkA8sOexg==","shasum":"0386bbba10af98d130fc375786f537c3da59b076","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.13.tgz","fileCount":5,"unpackedSize":49551,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfjmGrCRA9TVsSAnZWagAASEMP/i0VB3dKkuQ+BMzYg/69\nXHVILpbcyw9krvpDzE476eigM7+LSeXMZz4EhSsd+zeL8hZJ/gaZ98wVQeE0\n3Lk26YYkkhCkoyV/QUndIFel0jipF6SyTAZVb4bXfVquiQ6Lj5ftpu/D4uDG\ndsvMBZMd78ZLFtOXoab8qMA9dv9w1Fhx8Co73H40y50EDuDImcdLNbysXgvU\ndSDTTfMFJLaE/C93I91tezd+g40YbCKxL7jGp9fy9TT6MoHc0Z/UPtLWd0W2\nCPx3I49aMAhpZ1ZE+sPQbpjSaZ/TZMCAMgk1Q+9+il4lQPoL4QKY+Bs8vuek\nBEhuOZkvI9YLgr7pwGtRX+NEBCKBZh8HOi8jxRr4yrxVraO6zPRE+6Zg8SVk\n26BFMazw5iRJ3dsdcvCxG6zPPatr93DCVcVg4QyULYqWbciEwudLgbKX2eHn\nt97RYmnU8574lcKFDk9QOI2ygbJiuXC2y9w1RsHd+mNhW4mso4Bed3008vAp\ntxDKPDinRr8Z4t3mza+NSvcjn2j33FkJfpAAkWfn5rfm/7VPOa6wyd3hN/uX\nmSfcEDMeC8D/WllKZ3SWQfhCceJwHU7lz7q7uVEuXxiTiqZdlhP4z33YAHvK\nEBtRzW/FTn1MFem3+i3UiWrjBeEYOViMecx94POL+stDgYM6oqdnPND8+Duy\nEgVu\r\n=IPGy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGli2h/XiWHfKg25qW6wtyUpc7twfVOmZSSHkDUd4+WLAiEAzmjCLNhiw+LA0KtaKPN9f7hl1XCKrerB8yGp7jsDaVQ="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.13_1603166634728_0.538642056284174"},"_hasShrinkwrap":false},"7.0.0-alpha.14":{"name":"destructible","version":"7.0.0-alpha.14","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.1","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"7dc18e988fc94c59c1a9432ee18b86fea7c97e26","_id":"destructible@7.0.0-alpha.14","_nodeVersion":"12.18.1","_npmVersion":"6.14.5","dist":{"integrity":"sha512-FW55sbq4nMyChy1Fdtg5dgw+h5zhP1J7MXWspIxZrBn2HyktEQCsdHCCduINv3ymU9tf+1ufsoCy8bKd8p6Y7Q==","shasum":"41bb4bc3bee644f1af0bb0c6550a4a04b9703ec4","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.14.tgz","fileCount":5,"unpackedSize":49552,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfjpw9CRA9TVsSAnZWagAAwGAP/2LbNJLLtToj6CpltaoJ\n1/krIdoCkYIjN/QjyXPQj4TmXjMnf5eO/yguch2sYVdZQMamLWHnwvAY5Zwb\ns99gZA9Tn+hdJL2kqoq6L14jdL4gH2rNV4OyuNvG3h8pGpUem+tGQGcWOmpb\n6+tsAvksHXMIaZ7cBThQiFolHW9HMTK0VEOrcR3N8OPNI19iPR/eAU7AeGaL\nxr/9f0gD5PFL8whZcKzmM84GO9dk7I+7OratM8/Ss85McwZ9UcuebnC+gBGi\nSRU3QlHNWMaxAAShBAc508ABMdiXQQDiuzfi0+4QBhzFOuVkKc/JEigrCqrB\nKkZKzCbFP9LZPTjGL3zRmcJce8EU3nDg+k3qVfU4nP9G+D3DqYEe9/E/ub9v\ndncw9GBRG68McVscXVSXuPrW2t5z9pH/W/lMkWwKwawAFBeuL1cZxUPCXyY9\nf9G78/cbkCNpOX3uOa8CyJXIhArYmw5kXmmVF3bh4Ys1vKMJP0WzS/aGdCXJ\n4azqn8mtH55qF4UKkZzdbiaYQsm+6ZxYK9um4QR1CMoHGVPC15KTwZzGAhFd\nWwuGSM7XtqJE/SSKhapqO/rP6f4dFxWtpYle6Q5MIgQ5hYSXrSfRusuWU7Hw\ni72/95VEImavfNPnEuhlANU5BJEZFmWMSDnU07HrpGFiPtRr6xYe9DDlRLfs\nm96P\r\n=6RZy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB44rsocB1P+nDoKJkhKuIhr/Ywb5qPH5O97WQi6yJPRAiAA3kscuvWF+2DhlhS+yXVhppuOyKVyRaIMJAjBOP0FiA=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.14_1603181628904_0.17761721728338742"},"_hasShrinkwrap":false},"7.0.0-alpha.15":{"name":"destructible","version":"7.0.0-alpha.15","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.3","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"22bb5fd1a19c506735a68a96a42e1ee81fc5c155","_id":"destructible@7.0.0-alpha.15","_nodeVersion":"12.19.1","_npmVersion":"6.14.8","dist":{"integrity":"sha512-WwXPVBF4GJ+8uKUElkOSKzNlNkSrAlCKQiRjSo+wEMmXQyrvpbHc8qVtth9cP7NB+olr24et4l7ON0B+6ncr3w==","shasum":"cdca81223c8e0005e7d3299b1ff9ce8068a4a697","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.15.tgz","fileCount":5,"unpackedSize":50158,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0KU3CRA9TVsSAnZWagAA9hkP/0rf80tLJ/P56WlYRN+v\nYULkILJOwdsM8xVOGKY2wZkquQSQ3ZA+NAs1yVtFMtZ0NXuSZhwh08lJtzaH\nipqYB4Qs2wApaVIdliA6XbzeXY5cxVA+qxBYCKTbh9b9giNXetzG/n8DFVQa\na0pwu7FC0uiGUY5xETz1ZnUFoQ2RPmNbXDlBEchraA42TWPX6w12EcMm+3sV\n/+3HY/2j78tq8nNcDzV2bleVk2pfI7EtPrsrmftlfL49R/U60FW1MMfoKWKi\n/J+kMf+q5EGAhzDOR5KyjWFQWllTkmqd+gl3vLPQK3t4GZvoohr7y+VQuCm0\nvhxv4VpTR/niPH2byqGOaPSzeAMtdHO9oS6YVsOb9Y1CiZTsxXGqhma9FGtE\n1UYBuCYcUJUwMxsHtnwAliN/aFg/DZIYDjJTyKVBqAJzedxCuTyY7TJY8FOQ\nmVThx+l3o/RRiaPDgqO5KowI2i1SrIjQUxFlnX1fPnEvAeH3n7Ik0qRSWNni\ncZP8LcUO1y8bekiMna3SVapHkRtCyUbY1RsnXMfyNLlXefbQgzITLYuio7Y+\n5fXR9APOn9lLUt+SJfY+PJmABprN+Xier2/wymK98GgwleMhCVwg1/I/smZg\nPGerV9WOCs19HoSdP2oKcpJvq6gz8kXU7wPAKM3DHHr5xlDVm256XQp9d4Rq\npaFF\r\n=miq2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDUq0olRSur3iwfjNwymx2omCjr4bJ5UKJ6EqIkjuf6gwIhAPLxH/pIm302kDsIXZLtaJ3zwTYyHtFPnB/SNhu+pZf2"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.15_1607509302832_0.9404023782255349"},"_hasShrinkwrap":false},"7.0.0-alpha.16":{"name":"destructible","version":"7.0.0-alpha.16","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.11","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"c43602b4ec6fc5b2d747e9b5f8348b2d8aab7503","_id":"destructible@7.0.0-alpha.16","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-c+Pxo8PeDh5/lQ2MCxyIM1N0Defdwa8VUbHpvxO31lIwTeinDH7AGwuaN9Q92Stzo2mhsqd6GqLf89vhqCX/TQ==","shasum":"fde8a49e1ce55532c58d9f9bd9d4be5be053ad2c","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.16.tgz","fileCount":5,"unpackedSize":50543,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf18yWCRA9TVsSAnZWagAAwCEP/0YoCFUtranMot3Jx/jZ\n+cpltqUZFJ3Udf9Rg+QDsy4fXtpZZfN5Jpp15/qYRLQO+gkyBHIvhcWHU/5I\n/Hn/o0+mb8vb07UzerObYi1V1gl+e8MwfcxeI+mH3bcHqnGnyWI1+q1ShWh6\nzTsz+PcxEezJkL81pxLZO4ZF+U/x99+p7UPW9eo09NzHlIekaduEt/6JPsE/\nLaudCWaldJvzikTADzWw004pC7cCiS873FoGF0wvYVqq2xtpNCChk3paRvqH\nxrUsfWmJaW5JxhO6IT/axkIyeFdO3kmw+KWinloyof3j4BCoeww9rAOK40jG\nH0PcpeO8yXKCGpdMWQmmJG+qkJaB+ikk+1NEnuxf4O66NmBb8ggybBpHknVe\naZxJqTvQhDimXkjltSjh9MAarBsrDmQgmiNffo310jdR4SvAGz3NYGCsZm+L\nx8gGF8h7sHGvFGYA1bWbxUPXoC8szF7uqIUtMpBrut5kromF6Dho4UA3td4i\nXIRBazgrKNSWTg2h1C5+oCguijswtBKAmibWYEu0l/L5Pggvc9pHLsP+rZ8B\n1veNQvPM3gY71eA/3FQ+lTYhyNTvONDFS9s3mj0r+HxxsO7vscCNHmOjzGg0\n6PV1v2xmtznYQNnAuJBaJlG/VcAxMWfPPjLhH7cjFdgsYifVxoly9Zc5cyU9\nS1wn\r\n=uUzG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCgCowG8j3ny6mELhypc2bZV56T+m6xexNp2NGoiRhN2gIhANXFmLFJGUSoCMCuap0tiOA5aVkCyjft7ueMyzcYxDKB"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.16_1607978133493_0.9888644006788765"},"_hasShrinkwrap":false},"7.0.0-alpha.17":{"name":"destructible","version":"7.0.0-alpha.17","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.11","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"b0b92a3a43b8f710643da42be467660bb8459f2a","_id":"destructible@7.0.0-alpha.17","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-gtf/COM2xeZGTWe4hNG4J4GFIZZH6TWoXc9uh2BepIqU6B/ajElVCPDEt0aWdHzYfKkfKbtWgwMl986wjf17Ow==","shasum":"a7bca4dae18807fee6b45316316a6874faa24325","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.17.tgz","fileCount":5,"unpackedSize":50376,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf349pCRA9TVsSAnZWagAAIbgP/11wtmzR2b0JznWz5C6I\nlpBt0gePYWL8YeufGk6syFySD/pXsT6dGdrXGkjX3KrpOwyyfP1do8BiHmyt\nrWr2rPhYZNWavbORlUndLZ1JtYTjjk706hqHvSpeRnpjccQT7tzEuf7f4O7c\nGZokvwZFR7GbTyJXvKAN60p1X/+1cRfmRmeerpweOssrfTdZ79bkRWX16aHY\ns4TVq+DPygHj03i1bb8KO9Rs5m4+SCS9smbz9v8MIeQMrtNvQc12ykgeDR33\nV9cbcad4wmZKwG4lZJHOsI+UYFbafifBRXLqT4uKlBnFejT6RIk6hkuYpYVa\nPayK24q6eXtIqhhDgts9Pt1icl4Loh0yhuZ2MoSgw+YB8TmNEe52ztrirFwJ\nA+33RUMRVjtQeJPetScX3tQmYRk0UruY1B08PzVLsJvntrHT8csn0sxfoHLO\nkBJFA6OpwyadeTZFutG9DNrO24UyoMu4BD8P8NqnUsCwtZFcqwZPwsy1QMWv\nhKaDiynH7b7ab18HEL9Qz0fdfyDgJ5oI5TBzCrfrLygaghGNrbDmpOuaNJhJ\nRhR8ITEwHfqr4A+Mf0O9eWaHRQSEImQbNx1BFUEP8S2E2dA03M2B2eSbEExP\nEX2C7pHMrZRwN+A85Wo6l9lgjdG/bJA/LwfRnQePui7APeY5lOKR3GnFE44V\no+eM\r\n=eXHR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDTyzJtY0IZ7qfRT3Q1nL7QvmpKcjve+wlIuw9lwyT65AIhAKgyzCdsplttTaAFc0vr5ByrvhRd2bAGjjkXgd69GIUB"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.17_1608486761494_0.733382346787975"},"_hasShrinkwrap":false},"7.0.0-alpha.18":{"name":"destructible","version":"7.0.0-alpha.18","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.11","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"65f57a1ac0a28041bcd9a559acc8f98d7af43ec0","_id":"destructible@7.0.0-alpha.18","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-Hwt2a9nuuhK+Itxxxklsmzmk2Ltz87ODaC0kioP154Mot5uafHOO8Xvz7XHkpzlihKY25Z7jcKXkw1TsGASNJQ==","shasum":"e9720b0c5f0d7589408f1ca5447a248917683cdb","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.18.tgz","fileCount":5,"unpackedSize":50376,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf35CLCRA9TVsSAnZWagAARWsP+waakKYD5Tw2KwRCOGDS\nH88dw++vUkxWwVTV2cu5Lc3LA9vNZS6ZmY1yojp0ScTaF2wVZ8vyYd+MEpWw\nyPO20K8lmPhLxUQx9py4dHe9RA++WdUJBCTic4GOz4wLIzgNUiSv1m18fExG\nTjlX+SBLK/bawGRoPQmsg0zc4DRk8Qwd4ZeJyhrR2jYypEELfQFpcRTLg22l\nNCQ7PDbW6042RpNeGfyahKk151YbceAIsLMloWU22uuQY+VlEY35aS4GfppG\nH2Tg6KZ6iUdKAXt87mfrnLffiy5sodNmoZ8j8K4vPRlmUxvyKhKODOcys9S1\nPdWJWInNgPmiuvevYt3xVuR5ElkSy6jK+d0N5qhr90TphH7gxbTRanm2nYKM\nP7T4bSGJ566LO5jaZdH3Yg0fEK1KwU8TW6fr15BNF/nfpNj7kVtjRwiFXfGD\nyIxbbctHvgvc0Q4NDCYnl6bXiUY+IstDVnUKofKBhAD9FhTHsSz3kYmtwWlN\nTbJgTDSvrHdXKOF4rJ3IG/tLWpmMqMcf+DxIa429E1HNEP9MZZPQcWpfsEim\nNmFfLCThuZsVRNZ3tEmbdVOr+1k2BxNrvWgU3kVvxrihxG+DSwDngNv567Lf\n4E9+DgOzNdhPKiAUzQjmjIU/OZwIS0naiu8UDUqSFBAcISVpivdXj+yJCRDD\nCyyB\r\n=qKJa\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD/3jYB3NpMWsOu5QgEgb9ZX541l/9JQaQLJt/cBLfaaQIhANuS9uvR3/CLOnKvNvECcr+zFoF4OlJcMjPOqvgtbMYs"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.18_1608487051175_0.016390149516583685"},"_hasShrinkwrap":false},"7.0.0-alpha.19":{"name":"destructible","version":"7.0.0-alpha.19","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.11","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"fdda58a8383179705db61494e5be2d3cccce6ef4","_id":"destructible@7.0.0-alpha.19","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-pDBsmvsG+d5PZq891QNgLR53q1nhQIsSoqhV5GuhiqX/+ODV5QgNu499Nc1lB6jSut9XH2VKlMGUtSYxP8RmQQ==","shasum":"debfbcae9bd4bf19a1a49559a5b22ab2decd7dd2","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.19.tgz","fileCount":5,"unpackedSize":50853,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4CgBCRA9TVsSAnZWagAAYXcP/2Uv/qJsV1kjdIZsgwr5\nqtz0q6qGMTQ886mDJGSbgxvLotVUGVAxDuLTazHdQaO1TA0+cAEloFvjEN24\nDhDCNYupAlZL0juiwXuN8BzI/yOyF6vQW3cxU3V4ReEpCBmqgGkHtEfJ5NHn\nhHLVRuZw504RjzB/bNAf8BHZZs4rR6aN2L9+Kc9/5ki6Iimnlbuc+ysxMTu6\nPkFQ7DRFMquVWoQaxFOlitNFldJnOPW84IBGjKhLpj5lWM97kxOkPbQgBkX0\nH8+nHf2UTcFUmrVOM1llJedpdedUz6xo9Zk3oD0po7YZCg4KFL58oYMa7KID\nG20gMJO0WoBjteKrgx+rVXtf23uFLGuhayvPsI2NLq8B+NHWtOOx6U8RQYj6\nZ1nFt0oO8G/9nW0dRAOnS+uYAnqD1ZU0pIFogWl4vWSN/wJGcgeFkc9EAOfk\nFi2c+xPYqZ40ZeSTEVB1JdDVsjGaTGttZnul8lvZrNxjN/7PmD7ae494NbP+\nDqUlNuFFLFTShNrPOdcvy6yWJH9hXAYoNXfzpu0JyjdjIx50ENWINTW8VJCW\nMg5sJt4YFX5uf3jaG06BUSQi7titjKsd/I8kCEpG8yFFvj7Uz8eedJHN6gPp\noL/hZt2ig6chZiSwzzxeOsAMZxSe/vT86fhcOO1YhzoZwXb96TYLYw1+xMHx\nJp5e\r\n=UDoi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE3kw6d5gMGL8ajnvGCOtvvuT7p0YLjTao8djt7Qo+euAiEAgj4uzTC0Ly2KpQamJZc8JOZmMtO61CXU/iahB7IDC18="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.19_1608525824593_0.8424150379026389"},"_hasShrinkwrap":false},"7.0.0-alpha.20":{"name":"destructible","version":"7.0.0-alpha.20","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"empathy":"0.0.3","interrupt":"11.0.0-alpha.11","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.6"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"3c92ee05c4aa977203b6e3d45fc79552eed8a133","_id":"destructible@7.0.0-alpha.20","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-QWZxklkeGSegVRDUT0uzzywYEV59OouOuVLmGkRj0S/nf+XpYemvLhyVVp4YqP110L5oz+baGZQHVgkKHLjWlQ==","shasum":"d8c1842c788da31609d516316368e23895771b3b","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.20.tgz","fileCount":5,"unpackedSize":52923,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4kX8CRA9TVsSAnZWagAA0egP/1fotEb5BHv8qpt/tQM8\n0SGleR0Sy3t9KXwzkEfC1fVN32osEwHNIK8evOqlO2yRhtewQ6A4h8r4hPKY\nXwSWfKUtlghrO6NCTzVMK1CsJkb7jEABu+7NtAiOOIAGiGVlYUPErEsT90z7\nEG5SeghsniSJ+gDhzdO1nwWcsNbXn7YbYuLgYtnDpTgRMGjT2LG1sjjF4SaG\nCgTmJVVcnTWFEIOgAm7m+23wJD6UZ4QnbiwiFnhSFkp9CnRyhn0LJLpvnm3q\nYhbQ4I4zXfmc/youQcU4R8hm55uH6arrjTtuTnj6eWBJZX9et3pZ+PpS/tDk\nSNWDAWQZwk3nHKCLy0RPBS0vR7rc1yOcy44IW9/ynSPmtKs7k3G7t8RpQC1M\np6qCm9rkq4pBAHnzckjDfLHSaswBCzBGjatOyCG4HklyZD3/NCA/Ww1Yh3ff\nvh3WqPiWHPQ1o3xJMlJdAcL0yE7kpDmfBHURpCYlSaYoVfRWla3e8vHL4cV6\n2gN/0XabMpZxi7kQ/TvL4jo1ZO7NCxbWbUezs6J3KPlNdtc9KrglM/To56Ty\n4saD7B6wI2Ze7p/8XLzUAHzyPLaaB6tpPKSDD7hzOLLxu5e7AfRRtsMS+/4j\naN7TlbKhCVdb8HArQmlpluiJSFTTsqB81Z9s0pKCwflMr8xnAL3K1MgRFH/G\n4BFl\r\n=Hjfz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDHHatcsryuR3h1LotTHoFW+U8FGFPKt9TpckZFq/CxOwIhALp1tKjCGArnlMHldV1iep4Y1e/8IHG8INj9655YBojh"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.20_1608664571509_0.9631456423707938"},"_hasShrinkwrap":false},"7.0.0-alpha.21":{"name":"destructible","version":"7.0.0-alpha.21","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"empathy":"0.0.3","interrupt":"11.0.0-alpha.11","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.6"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"498f8324e0d17e4b7c5e3992fff1acc94bbdd367","_id":"destructible@7.0.0-alpha.21","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-h6Ud9bw3cGs3mNkwPRM1sXXRlyk91EzY34aTmFqWrRrfwW7z6jpjOO+3J47L7vjMgGqmHsuy2VUUwXR6uDk2WA==","shasum":"dc04c1719a19b4fa9e2cdbeb77747f51df6cb23d","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.21.tgz","fileCount":5,"unpackedSize":53096,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4lOrCRA9TVsSAnZWagAA1PUP/RW/ac+VuosvVLo2jwvQ\nXF9Bf33+RUNd+kS0B/RdIeUxvIQK67kncsQcP4DTMklwRlzPJ+044d6WZzl+\n7Nc+Ffg69dfZsnvTtC648xgQt/26FLXI3Er6XEpFItHgOMGJsCc78uP3aOOt\n4Mo+fPxi35JH/MlO3iya1mEKFio+x6NNHF8TOcjDv2oroH/rbUhe5FH5T9DH\nSYHwZ49s4OF1xJfVBJPJxuBl9XvcNnkiTywsNDtwpbhEIGne9D1rRcqpndvh\ne82UQPj4RpMQAeg41nyQ5Y7+/h7DmHBd0iWuCkwP8i2SmXEuuO6hs/gQDzT0\njAfX23uf6lgxoKwnyTXePB9BF6myFrrXXuvi7ETHZou9vdSxn82XgxNPftgg\nZOxydaB6exPAYkAQh4JbEdOshVNfHVoFc4SDvlgxU3F2eR5g3mX/ojBwMB61\nx/0OZJk2QIbyhc+ZuR3dz1xSbJnSbs2HxrGkTSxx9NCdMQkpYimAIsrH4bjW\neIdzIkqtptWyB9tVyypF9l7z9Z39bWgcfrksEPNGFEjSXg648VPBj7Fp9ch6\noVICRHTbuBVDri4N/cXrfGMYodFnKuPCDoaoGBYicYSf67n7f2dca0BwVJSg\nA534F789QRpWEkuU0pm/Jc0qbfsS83u84zgbcmG4ZG54G1Z8li/iZUwpT9+O\nDNvp\r\n=lxBn\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCHpl5x3/MoUaoyPbz/Aa+nCUc7+RZEqP3LTreM9n9KngIhAO18g4iTmhCdK6W8yNsTFCXW2B9j3pB00ZbfyZwQWkRT"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.21_1608668075237_0.40064243326231863"},"_hasShrinkwrap":false},"7.0.0-alpha.22":{"name":"destructible","version":"7.0.0-alpha.22","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.11","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.6"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"da0e6ac4876a0bb91adc639e22f200efbe66e97e","_id":"destructible@7.0.0-alpha.22","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-IBcEn41/TdZ1Dh6S53ydxnv2kDl0qbBb4E3/r/Xf7U4g092j8mLGBD6I0Tf3zjPJJ02qY1YIWCBvmHScWEUtZw==","shasum":"fca33f441ac8655967b6d0d9c0622b77bd0a149a","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.22.tgz","fileCount":5,"unpackedSize":52508,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4ocvCRA9TVsSAnZWagAAClQP/1Dbfi/DNLShGeXeoVQB\ny8bhN/splJCUrw4Y8lvhnobopmBSfAhlCl2jQ/9PVLf2xa+bpEc9dFwH40lW\nKmyaJVb01+IlILxlv3jxAEJhBluMAJCUzw9MF+vWfvs/81XT67gBd+EFk12Y\nW1lvKK9dDhcx7tFXq40Fgh+aYU1DPmG2kWmAPInVXcTtqDLehshC58+acsAs\nrRNP168oskZ+LhDmdLTs8iVvVWE8W4g960xzsRzdxERNRiWbnVlMXDVmzG8W\nbQHbXGktwUNcFRYQe3m/QK1iI++ar6Rcw8wDndbNqsb93z34/2LtSsLnjrny\ndrALjgWx56LMfUClh/mogsWTNlR6IRsiDhDf6WEih5t8fDeZskGaEWoi27LA\noKX5tR6f7EZ/W9ONd9rgoPd4yFYFPwytys3YQpFAQm3A4hWYWLQ3Yz63qvW3\nPtOrBJMy7LtbaG7pPPclziQRMJ3Cc3upf4gJ327Zpys/VzffOM/Y+lDxeHbd\ncKSrHvwHujNekBH4QOuyf0uFtl0yuJTHbXxqv5w7SS1k67Tx7gLVKhLzbxkf\nuKMLEwNW4GtJpIlq//c4jc93h/QzjUK2ZulLZwmZmFpAoyj1kXSbtXkMBDe9\n9G697Dtqh92FeHHXEmtO1A2yg3k8t6tZdYrZBrFIkJ2npngb4uS4f/P4CwPk\nByAH\r\n=/n7d\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCq19JC/C9L4t7ebXcor1vh8Rtf+Ar0xLdeRfaYT6OfDQIgO/EWZHwbwbmd9PtFEjFmChffMg14pKbM0QN3k4YBrJ8="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.22_1608681263286_0.561889015621915"},"_hasShrinkwrap":false},"7.0.0-alpha.23":{"name":"destructible","version":"7.0.0-alpha.23","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.11","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.6"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"d86d61741a669cb13379a74426be536584385458","_id":"destructible@7.0.0-alpha.23","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-/SwSexm/D56dRRM8EWYBRo4wkLg9bki+rkQoyhp9mBgjKupA4+cpQseXC1d6YwaU8h2fwby3EzcGL38Ho+Uykg==","shasum":"0af3cda8bf552e07e9c00ee8d0b370f1f28ae7ed","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.23.tgz","fileCount":5,"unpackedSize":54986,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf5Al+CRA9TVsSAnZWagAAdmkQAJqKnC8/bMnPeSZdCXIW\nIDdtGMZdV+7tM1T0sUPpMZ1uXwXY9bFGDqyLpIW1efRSxXNQVqnaHy5f19Bm\nrYBf2qThqe8m+J/jCBoJYkxMBKgYZUecjSLdMopQJH302Zo/23gkuz6RhSIc\nu+yzdCGqLKdztOYMsLhR/8BLIZKTWdtMNnqHJLL2yzuF2o9SlsvmBYmXtDVx\nptuMiRgdFEtC74KvVVEw9T80pR4mcE13ew+Q4nAF7ibRN0M6s4abFZ6H8F3l\nT5oqlrcJqUf2KuuJUyHnKoLviY6Ggkam12HK17AIeUns5b/5Ev14Wm0XuC3i\nl5nGVLl6a368X1Z+Ac19iHV9u2AgxtmkQyFIZ9jPHLncBU9GK8cHGywBX2/O\n4mYe2d0DXScsiwWmFdDxHrgle0/n84DxXnZwE97fNXbqSUSKMaIYxz+qMPxJ\nPvwiv/fffl5qyJ7dbr8mWoYJ/QpKQjGDWkCe5QqnkkwxIpCpMlGrBqvEroNY\nqCLJ6SCISy3ArpNRRIBj6/VqGGyqgwYbw9togvwLNVJFweHkc21+tlpVZJ5x\n6NmTtdLexBb0JeyrpJkDau4zSonZIB5c0yhPYDYxkYgyA4m6vTxHStuA0qf9\nonSJNbWGPK777DFJMgGOfaQ4AHgS0yesbTP+3yZcmtIe2pyr3hsnkNFyRzEL\nuRVb\r\n=oz46\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIE5HcqLxTCLob9iL5rieqJvPyo0vHbmzjej0axqA/Kk6AiAolYSTALIyomZw/FtIPpEw2D0p7sulLungc35bFWjW1Q=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.23_1608780157389_0.4858855316348245"},"_hasShrinkwrap":false},"7.0.0-alpha.24":{"name":"destructible","version":"7.0.0-alpha.24","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.13","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.6"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"9ed30e65db0a797944b837ac515374784fba4242","_id":"destructible@7.0.0-alpha.24","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-yzNzvBvOx2U3sRDvS/5nSS6O9PsgWSnAb4YihsQ4yuNCleXM4f/NsxvIwBdQxuibZkdtV5H2OEETKSvnzpE8bQ==","shasum":"f9c7219760d0490840cd4c0b395a4498398ede51","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.24.tgz","fileCount":5,"unpackedSize":54986,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf5B8DCRA9TVsSAnZWagAAsKAQAINF6W9UOYHtwgKLS55h\nrnoNt+cdg2PwdxTJUbkBXPHZKZtv69iMLrzAlOtYoVNFzR//UQlWiDlMaY2M\nQVMpdRF/Qn5mNPmd5RP8TT5mlkN6leaK/ggUAIODPMxogJq/nx3RJ/4Lyszu\ntiGRfn1OksP0U4YaA0ApE7TjqkGzZF0bZ7Vvx5b0pNzjSagF4cWrFyIxcsB9\nh9ziP3nb7HR55jeamXpImwH3FITPO7rVP12rt72YBwuL0uDQA8X+pWPZPdCS\n24BYYsNBi/Bmd4lQfYKylsx16mxbjPmycXPAm3AcvwTGVdX7wsXVQ16BYxU2\nThmYFXb/aHOub1pCszLJG3WtXz8SBeCJlpWSb8CS+8eETFf4EpC/Q/1VHEfJ\nRUxTA7++8lxY7/HhySlr6TOOge0XypdzyBgvrLU/wE+kwaFIz/hhdkWKoGrs\nXKNS93Klwy4r2pe1XkzmvFEj2tIBDxhXj7CoE/3WazIsWR+7OrVBMbG4mXvr\nwcOfPK8BgoB1A8ucNIjt1VFFFGO7sXonRG1tO2COiQMV4bcPldyZy9XWN8ll\nfAviDZZZjjYR/5ZUWZ5JShJksN8267HPEpYqxRS/xhsPN5bIx0xr+4Zicu4M\nz5hlhRZ9FVz1SX0M600bHuXvnNEGQe5dWp0vTjYU9rvsaLWM1SNT0wSD/XX2\nbMfC\r\n=4JBC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCw3qya/yCxUHKBaamb6TaDAB7Jisu8C4wJIbGRKCAP3AIgNZESmDdKiCljkZr5gUwqnKrEKIcpWrMV0yGay0mM/Hs="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.24_1608785667476_0.8655850803517064"},"_hasShrinkwrap":false},"7.0.0-alpha.25":{"name":"destructible","version":"7.0.0-alpha.25","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.13","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.7"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"227ca1e503b5e94cbeb5c9614f8ed974668ec2a4","_id":"destructible@7.0.0-alpha.25","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-/UdIXMp1HXi7Ezm3Gf3lAO7GRU4suV7lp35cXbNpllUAOVKgRQ/ClHKY4GfwD4cmvT7qt9PvBlQLFB7SEnz+Ww==","shasum":"7d461b93537acfb2e7d72ba3fd04cf943b72a1f0","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.25.tgz","fileCount":5,"unpackedSize":54986,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf5CYDCRA9TVsSAnZWagAA3KIP/2+t2i0SUvapNcF4yaHp\njIvRySjDUvRY9/fKZgO6VEzWOE5+rOlTOs6+htCDidWQnpattUiI0L4twQKv\ngKFPgB5zN1h9QgLNfAPumJ30Nzb9B2UJ1fr8E4CDDkJpSwq3EycuwV8Y2oNj\nmu6HjDIPl88+0tusUbxVngwQSxXuB5H3ioLKNvnXH91X34AUzwN9YKie6ka/\npgBUr7uyL/EaUQAx9vmX57PV+4PCYxv+qkKvJG2Vr25KcfEbO5qCzpElg9Q/\n4KTsH5tdDwjoP6axtIfMK2n6qGbxRmeudwC3bq6Ux5xbcW83WHf6LzNtZOqK\niHlL0eYOnwqfWpnV2nvLsIFDhYv0bjeqgiq0PU8zRGqQNnzWNWRpEhPK+4Ih\nUIeLMWKEorCN2WidqoSZH+H8Y8SWm6eUssQ7HDsYMCtA0uVRcp/ZU/Tocwfr\nYmCIPlTTDwFvYIxkqm7ZeioAB6q6MiXRfYJK1MXD9qGzYfFGNREpFRbLrl81\nXWt3xbaWbMNcjlabeuudkTdDmSKK5nByxDc5i5YJyaUMujOxGr2PTwdA80JJ\npSmLxVx/lopg8IFp4KTE2nrx1nbXD3X6EPOF9Xrnaa6CvViWDTgDr57a9+4n\nVFrNBscnFGfOQJQMwp4rMOmEYOXWr7DoFAilr61UGno0Is33RbiAOgbqbGxs\nOjeq\r\n=tQ3J\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFvJAd1lV3o2xj076ZRMrrU8EEZyh6k8QCeHIGwho/t7AiEAj69RXjwiYtHqcr7U+KGCDPFqDQIssossHKyMJA9xY28="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.25_1608787458766_0.9522092122837529"},"_hasShrinkwrap":false},"7.0.0-alpha.26":{"name":"destructible","version":"7.0.0-alpha.26","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.14","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.8"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"a6b4cae6300503bebb035427999aa39c69a49f48","_id":"destructible@7.0.0-alpha.26","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-9du/lVlHICl7+LiDu7tIMzwAahRt28fpYAByEkALUPb5dBNUA7BP/5ndOFhZgEeiB+uVBx42SmDvZnVL5HPZQA==","shasum":"4d12d7c7e96e1badb0ba6d0580c712d645704ec9","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.26.tgz","fileCount":5,"unpackedSize":54986,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf5V1ECRA9TVsSAnZWagAAAlMQAIjsuB8HH4XHDRu1/sjz\nT/40v0lMk6X73qS4tgb75X+2iVU7G6wlKfqmx9SyZti7L8XaYZZnlrfknFJg\n8+rQnu/jwx6f8NxQAm5JiyJuntLgUHygDguio5TEApMgPrWRTPjORhzPJ/vw\nYi1i2g+OvrFvtxrL8VLfAJAzb6uf3jSY70mQZiP0+eYBIyDAfWH5aOSc5bXM\no6jIp4XoTGIJqY2UBar6jFDdQj1MxxeaIpV27xKOBvtG/wpgSq6DFY8TLo7T\npvDMVD4Xk004g1Zq388QFsLNHgTMQn+w6WnD5dsGiBFlGvUz7mZp22bY7DTQ\nbptBIIzsDNbbCvfAmfohM4JKkPHeKfdL/ov/aqwrhfM/dorTPVzx3JLKb9Zx\nDmVj5QUTP0Ax0cxaVLwctT6vSFV02ZD9DnfpS4iiAeXKTa5woRcXTC4wvV79\n1Xgl3R+8oEesdb7T1+w1Hcxh+3e8ZjhWLKMYD73qOJgW38nZVA4NIjoSDZBK\nOelVJ7OYISC20u/u2FAiU9aYVoluMVzeL1KupaLgNjlD8epVH51Ugrkgyj0w\nKpqjSfxFvp2q9MxYI66CBg7/vE0W8bN4lkP3YvB0JAYG5Bxxk1V5mDEgdH57\nYPlbhYp73uysxYIfxbxmWsan/s5BtuoTvanfdl6gtqiWDmp18fAZBiUrKMH7\nOuio\r\n=O7lv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBn9dmEQMHkV3Wip6DyHAq7m0sKAhgE4lszeNxiIDIo3AiA0Eyz9enwX4r0PDhZo5SYKgrRLwSogyoXQDxuN13V9eQ=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.26_1608867139691_0.6541957832927383"},"_hasShrinkwrap":false},"7.0.0-alpha.27":{"name":"destructible","version":"7.0.0-alpha.27","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.14","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.8"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"149627d78a5fdac088ee048f52e3c5cce2dd45d9","_id":"destructible@7.0.0-alpha.27","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-ChkvagtiBhgiGL3luoUq1YPqPUL7e3F8bunu/o039kd3plfZaQsUjJnQdqp2aNSxe/rEhlP+alVrieiW/F2lNw==","shasum":"abfec0a28abfb592138d308fae973e5206ff62e4","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.27.tgz","fileCount":5,"unpackedSize":55487,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf5qtqCRA9TVsSAnZWagAA5S8QAID0ozpR4sSsFEY7VzwT\nwNhkIJzZrOvnELBCMvbTYZbSkeCuCPYd7zxLA3LoKxVVr6/Ni7vRMWU4ninz\nyvp54bNALrUz+xX4iTsSH9QapZD9dZRjvUsAWMYDnEitP/4T6TQCqTR7of9v\nIxVsznvnRMC1E/R6mip2xacQ4k80lMLVc27ZSbhd/U0pwvluK4K808LZnLNZ\nxSgG45RHrn9moXYSLAmz2M7Y9KgikZ7tC8PvoqHCrMs14+rIad3c2Xi5QOne\nd3E6kvyMFLPzfneygXY3aJo8ttZuFBA0Py+mFTRXGmnhsnOBoBrUe923J22a\nk4DnW1KFgzreJ3GzLemMpQSGcLXF3HmErlIgJPLBAS7TpRCbcZ49fSoDBo+u\nsXypF9nV9hs0Tsiga9QrYhv++QeBmllc7GFZKyQJWhPf+jJq37n5eYs17XDO\ntaNDak59zGPs4VuBytNp7wn+V7ymjcmO5M4nRTHz/7AXJiQXTf4feT96EDOF\n2vED/ctZkpxEDam2EVvZY3ZY5A3+l2wijwfyrHUYcjJdAW+XUVxVM/HrX0fc\nMh3JWFl2vQRaU6PkXQLgehcUr07kkqo8SQX3DHYkOenuGnF50cgLVSy364+/\n5s97U3mfT17T075XlHv2BuVjACyaWXMHlrFTTACcgzUqEf5iuO7AVz7FmZuJ\nQMnT\r\n=TFsT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBVG8L+Gr6FuEhNyGHEJ698OPqOo0F+6uw3xBmbzeo4WAiAdher4ofxU8LYbld1ZZV+ymlL8YzUt8icGi3sWPQx2Mg=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.27_1608952682265_0.1361240622931117"},"_hasShrinkwrap":false},"7.0.0-alpha.28":{"name":"destructible","version":"7.0.0-alpha.28","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.14","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.8"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"f1e3f49ffc4687f402c78eae4f93fb642d4ef748","_id":"destructible@7.0.0-alpha.28","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-/wuLsBvea56C0dC5khwpAC27wVMpm9ZeV4qF45/74RmhEu4Y9m2kUDfcau5FDzs64PPP8z3fMttjVGlWyjOTzg==","shasum":"1562a7f30e19b071bffbf2a0a7b22d45a13cbb82","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.28.tgz","fileCount":5,"unpackedSize":55587,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf7NfFCRA9TVsSAnZWagAAhykP/0Et+e9CwKEvtknbhteF\n34HzZT5H1O8i63IpCsrLsHoIpSg7bc3fdbEiJjwaAWyDi4b9+Uax88jZU9/l\nCZp8toOL18sd5ZKteNkr6t//mkUcaXlozlJxVZpE4XWcRQajYRYwRM56hRqr\nTXdn/81wEd538KqUt9L5ptmBLFGxEfbmLvfLO49GNwQ57rvftogFavZaD6v5\n9I5Rff9EW6Wxixe1lqhcPpuw6cnGDxCDO10C6vm9Bj56FiA99oV44Lz1Msl0\nXrQMnRV44KKo08anmw9WpAJ9NfWg4V3QJgFtiDNDNrSTA9YEHVWrIhkzlotz\n+HAcr5HTgRSh8eJTDPCbPclHkUHQ1yM3byMUK25Cig7qIBhlqj/pJ+Iud0aC\nuBlPWR7Ctzndc3sH2E/CJEAM0ubWS1epJ3NC8Bq7cq+FMpGPy+tLBXMmzRRX\nOHhRN0odwdq8UES4YLj+izz5v+clBvZfWaAtrx4X2AoNLy8vdenRhOObnGzy\nIIwpY+NsHnpD2GV4SKJ2YShJkW9uJoq6NvJgZYlP81K6KD/83hDB1QFY4nuH\nd6rjRjg9F6Lp23aNH5LAKZr/3AxGV9PsnqyseclkFHjL1lK/fhktqOZUAN2O\n/bQ8MBRNFO1niAg+Phcy74Nxh1HPTb9GOAjgBaagQxOevxW4G6AEQNOyuHvX\n+zOl\r\n=nJ8E\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD74GZrSfy28Ur4U+lcFpVAb1yup93XiTcifebxmIc3VwIhAJhVO+xmGDLJE0eEfPtAlPurenxcCCscZeEdQsnu2P0E"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.28_1609357252646_0.4656670868248505"},"_hasShrinkwrap":false},"7.0.0-alpha.29":{"name":"destructible","version":"7.0.0-alpha.29","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.14","prospective":"^0.3.0"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.8"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"5b38f66d87b288e91a8a445a517114820e895368","_id":"destructible@7.0.0-alpha.29","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-HmPFOgeOybuTDknpHIrkLCsVnpJfAzfERP54VqSYxOlRhC4N9zEEaLm01HaAm8u6wsdho2vfC+QbS7rgtx/PVw==","shasum":"ba911d794fc8a02841e9b365a4f63c66465beaf5","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.29.tgz","fileCount":5,"unpackedSize":55540,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf7NhsCRA9TVsSAnZWagAArUYP/1WeuGAQciLK8SG58xQf\niYKuMbV141xciLs3wqLcKPpryD8I2dLKHMOK5sBN93bhBA2cN6W+8U5Eqxs3\nIyOp0e8aPuh9iy1lKkcdLAm8OwSOzCwUgjk4Ohzg2+ccf0alFfBspvwEGrBV\ncy7J6e9xl8oB1LfY61ZnO3rHLKCIK84GyDKJUtzuLJybDbeGjaIcHnufcY+g\nyd+F0kUOy84C4kPtOxdspysF0iaLqIUILuNksLTfEzA1QLw1Uos5yBXxwUa6\nXQXAlxZk69MGncG1caGEjQ6nkeOr2DuWxEoUB70dopfguGROoOHkYEYOUH0V\n4pHLyrGq4iUT8iNLz81hdl+YNpe9ieGB/iVGjtoyP6PAd2KDvv2x1bXWbrpI\n3pvYiUEdnajRdPgSt5pwye5ZlOar3XR+j8K5cWlEyZWTB7pKoKRwIZOgOHQn\nMo4MrUOooCGy9PXbtTfjSL/VLKqaCZkJHP17GnOxwhgaS/MNzjK6AQp7aGIC\nxWuwCf5lgmcEzNstF9Z2VzGKG2Cz9ihl0igY8SeYKTZWhk9w1sgQzoNmSZ56\ngFoZsaMBjhFHNeNY43H46jde57YhgURWYyboFe67hmF7/Dzw+NIau8V1fxl0\n4btuWQRifq6zmeEUJBCc4bQUW8sgEynENiEW9pVdweLnVyWjG3Fc8S2enKno\nr4Pl\r\n=dJKL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD/9mdmMPChk6YFo8t9Y4MS0sI8dYelTE/XBKyyfmgjdwIgc+LlfTkTo77rOkaIM6U0MN70HgIGxeSa3hWxyXyHG8g="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.29_1609357419922_0.03785286489262507"},"_hasShrinkwrap":false},"7.0.0-alpha.30":{"name":"destructible","version":"7.0.0-alpha.30","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"e2c2dc84d6666ebb53bfc17201b7b341bd6725c0","_id":"destructible@7.0.0-alpha.30","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-IqdK2/XZXJO3KXD5dODwjdwN3p7rb7LJ2mor4UkNMrgXTOPVGk+SxGPPEgvTqi4cvyWmMdE5OiAADnIfeDOh1g==","shasum":"f34cd002c9739ae2f732daedeec65b2520bdbfe5","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.30.tgz","fileCount":5,"unpackedSize":55470,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf8AWLCRA9TVsSAnZWagAAvBwP/iW+7Rb4J9cujSrgSZ2t\nDxKSXLDfMVZ93V898xVxXc9nVCaI38/qYyXToxKa9YaVlrhbkQpMa82orLAo\njl00G0FpN3W+QBNzEFbv0Pzi7IvYn3b+nGOarGCNuSSHOghwSs9rfsAyJmt1\ndPqBEUKjgPoR8oEJvI/JeQvXXj5m3HvV/QjQLggs0KxEsw0hzRqCu8I9ta8b\n17HVxvwr8gjJjvBNcGDTiq9Tf69wkr/RTTdusqn58yNd5qn4dZhKntT/ucDx\nvBETNOwwmWB8R+oehMKyIWS8AkVXwWEYhU0TkCJ8hvr1D1L1kLfjwD0zdR5L\nlt6/K4cUuLltjqUpE8UtYq9fm4JuEgEYNW6OxWT6eEJDKV/EOPr/KkouvVbe\n9aYgW7goUdvVNkGW84h5Z3rI60F6OuR5obbq4dMcq4TOPXtJDyV6U4A3nA2B\nolEfmaLUvJ21IDGHLb7zYEeKuNqwooia/2eTCz3HXmwQ1roSebgdDrOrucOY\nk95THcBSC7K2ANhfkUoqlpu5HAKqnyVg2ic+tHffao6eodSys7eIbRw94VRk\nXhAqO7DW0RzIboJzsRhOLLedVvnwVs7XvBa+WxGtUc+QvjqbCZ+KcbJz8/eR\nx3DwGajfAaOqeOijGF4WsNYmo6S6YmFL3+YR1135Z+/tENQfWsanQ2mvp4qW\n1xNj\r\n=pfCG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD4xVz7T8r3FpIYffpUMJ/EY5QHMy7Tq8ZEtd6KsgWtogIgbmRRpRLZfNZSUuv4RY416GM6adeuFxL0cRP6dVi20IU="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.30_1609565579066_0.738873455658879"},"_hasShrinkwrap":false},"7.0.0-alpha.31":{"name":"destructible","version":"7.0.0-alpha.31","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.4"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"be1127b3cb5a9ab847aad33d041cfa5188c1c7b5","_id":"destructible@7.0.0-alpha.31","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-SJzpN3jtFjsRYO9JKloHsFtRoSNbLctEMQR1DRHpWeB6Qj7kSX4z4/EQVu9NGSYrkx7Z8cyvlv7hiNVA4ppx4g==","shasum":"c766593550adb100335368b84aa7d909472334be","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.31.tgz","fileCount":5,"unpackedSize":55741,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf8t86CRA9TVsSAnZWagAAAcIP/iq3R5mrX8BzeNS3Z700\nreIpvDp6y2r1HkROPuDe11Ry/uOkc41zij8k0uze6PA2bnvIkiFRf6erzmv8\nSY9e3nvh9C1ZIpu/ab047YBDRPjJL6THJ/pjODVvVkKBkTBL2ymxZrc0LyzN\nmYIROXv0gylLIM7ehAPjuK+R2hle0BhxBVkhp+D7bo5KS9WEmLyHLekbm/NB\nyynjpA4F3k/PV88+8Wt9UDZ6uMH2TikksfOyJjmF1UWmA//JECFns31FxpIq\nSlzTunlRWCqcVGS26F109ovEXzmG3x+W56zyHxsRcSog3/gZQuMphtyLMSWR\nhWzuasHOBxP1gVWlgKkJc3hyGYm3aWL6z2AmwZS5/LCgbaQfyrt99oKvkAUe\n26EEh77CrWFZWBm8ywZHnrfg6u2dFmx1ppytonXxEKqdv7PqUJIff3J9mAQV\nJ3IN07oIPe/OEmrC+JdQPmnPUOqETVuadttOZpH62yCHC33f/KGxpD2fAIgq\nZO4NUVGJW93aqqMrqXYVm1inzxbOI5hgbpGeS2Ob3cGWR7nB4G/iMRXH+hVc\nZcO7CtSq3JLQeHSTHkz+8CmBZScKRUDIPFpusolS1El2Cbv+btGF08VpE+Cl\nV37iXoDKm3hJRbittQFBOTuaECx+z6sZW9kZvZRw0NB9GVJuG4O6qZ/shJwk\nS3q2\r\n=zhis\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGK+q7eEGRz2P6H1JRq1/KVzK/jxjKHFDnK6jkUX+pf4AiEAwmF52P8xqBTxzRFKwJbABbBQJcIg67QAJDSMKXAFLKM="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.31_1609752378433_0.7450821853855047"},"_hasShrinkwrap":false},"7.0.0-alpha.32":{"name":"destructible","version":"7.0.0-alpha.32","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.4"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"de90c69db3b3cee69e151ba3a662586d595d8094","_id":"destructible@7.0.0-alpha.32","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-Sh+GzrOEvzTo4MqwOQU+D7amEUk1KHtd3a8egJqm4S1m+utlhfpchQNr22+VOSgqvrSi+LQxs+k0HikhMtiUTg==","shasum":"edc6f7f0edf33db6616e64463d12cb570cef7e40","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.32.tgz","fileCount":5,"unpackedSize":55362,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf9C0iCRA9TVsSAnZWagAA+oEQAJ3Ef1cgxjqVaFLBV49F\n4M2yYU3ODrvVecuXoqpbQJlIMsKhTG0GbzaN+gqUo4SAHcS4HMf1n5xqQQGL\nsQIQPY4QT5ifup0W691Aj4SdctQ2ZOgcMB8CoG9duJ1CzMBPG+ShbWuozgHr\nBy/f1YxZ0TUEEThUUmrMgiFCqZpPx1UaB8zA74Reeo+xZNI4IQKS6T46Grmh\nYoprf27HaXTfVy3+M56UM3mOUV486OC06nR2e+5uqZJ0VIixiidMlAWpcbbt\n6LdB2F1yWXZ8xzGU9v/bO30ObVhQ8kpsQ1mI2+RubAi/bF6CAERzhf44I0et\nOWU+bT+kZM7UO8iTqIPeXJusPy8FIXA6eTEPAi9+3OovplS8qyxisVmWFlYe\nRB/v0wmLlzOYae9TcfsijeRDYHW080Y1FY9D1/dZjylctu85/qHY6M9cVIWy\nSJcbBRtE0zlOIag02Q2Tp6XEPc98oPVqqfK/sKG1r/hlVatfOzfkIiWq6g04\nmYDSRZIBiy6qS7xmkh4MUEGIcBhUWBlqO/ZWVCU7Y76iSo2nq0dK/09OTFnJ\nhl/Q6L0AGHHdFFPaiqzAndUzpS5dDL/N18QIst2m2nePjeQfRNum4g4vKZ3e\n8ln7hgDdhoDCyqtNzlDpmtAb5VRObh6V03cwR+GpjJ9pRyOplS5hdMk/SX52\nSD1e\r\n=Klq7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDOuVflMd1dt5VbY5F048cVf7DoPUMdYXXhxBxxiB1/6QIgYseLeq4X8uO13Ni6C4BoYmyJI5YeceFao8e3I4xdNTY="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.32_1609837858407_0.14227045465148636"},"_hasShrinkwrap":false},"7.0.0-alpha.33":{"name":"destructible","version":"7.0.0-alpha.33","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.4"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\nnpm install destructible\n```\n\nDestructible provides a way of managing the shutdown of asynchronous operations\nin an `async`/`await based Node.js application. Any significat Node.js\napplication will end up running `async` functiions in parallel. Utilities for\nwaiting on multiple promises such as `Promise.all` provide no mechanism for\ncancellation. How do you ensure that all the `Promise`s resolve and what do you\ndo if they do not? I mean besides `kill -9`.\n\nThe documentation is thin, but I use this library everwhere. These examples are\njust notes on how to use it, but without examples it might be difficult to\nunderstand the utility.\n\n### `new Destructible([timeout]?, key, ...context)`\n\nConstruct a root destructible. `timeout` is the amount of time to wait for all\nstrands to exit, the default is one second. If there are strands that have not\nreturned after one second `Destructible` will scram and report an exception that\nlists all the lingering stands. If you have work to do at shutdown time, you can\nincrease the timeout or else you can use the `destructible.working()` function\nto tell `Destructible` you're making progress, but need more time.\n\nThe `key` is a string or array of strings that helps identify the `Destructible`\nin the event of an exception. The `key` will be displayed in the elaborate\nexeption message that Destructible generates on error.\n\nNote that there is no concept of hard shutdown versus soft shutdown. You can\ncreate this in your application by setting a flag, or by simply scurring through\nwork if `destructible.destroyed` is true. You may decide that all your open HTTP\nrequests should just immediately return `503`, instead of processing the\nrequest.\n\n**TODO** `context` is dubious, key should be enough.\n\n### `destructible.durable(key, [Promise | async function]?)`\n\nMonitors a strand that lasts for the duration of the lifetime of the\n`Destructible`. When the strand returns or raises an exception the\n`Destructible` is destroyed if it is not already destroyed, triggering all\ndestructors and setting a scram timer. Any exception raised by the strand will\nbe reported from an exception thrown awaiting the `Destructible.destructed`\nproperty.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\n**TODO** `key` becomes `context`.\n\nThe `key` identifies the strand among the strands of this `Destructible`. If\ngiven a `Promise`, `durable` will await the resolution of the promise. If given\nan async function, `durable` will invoke the function and await for the returned\n`Promise`. If called with only the `key` argument `durable` will return child\n`Destructible` and await the resolution of its `Destructible.destructed`\nproperty.\n\n### `destructible.ephemeral(key, [Promise | async function]?)`\n\nMonitors a strand that will not last for the duration of the lifetime of the\n`Destructible`. Only if the sub-strand raises and exception will the parent\ndestructible be destroyed. Any exception raised by the strands will be reported\nfrom the `Destructible.destructed` property.\n\nIf given a `Promise` or function `durable` will return a `Promise` that resolves\nto the value of the `Promise` or function. If the `Promise` rejects or the\nfunction throws an exception, `durable` will reject with a `Destructible.Error`\nwith a `code` property set to `\"destroyed\"`. The actual rejected or thrown\nexception is obtained through the `Destructible.destructed` property.\n\nIf called without a `Promise` or function, `ephemeral` returns an instance of\n`Destructible`. The parent will await the `Destructible.destructed` method of\nthe this `Destructable`. When the parent is destroyed, the child `Destructible`\nis also destroyed. If the child `Destructible` does not complete before before\nthe scram timeout, the exception rejected by `Destructible.destructed` will\ninclude the specific `Promise`s or functions within the child that failed to\nresolve or reject.\n\n**TODO** `key` becomes `context` and this gets rewritten.\n\nThe `key` uniquely identifies the sub-strand among the sub-strands of this\n`Destructible`. If given a `Promise`, `durable` will await the resolution of the\npromise. If given an async function, `durable` will invoke the function and\nawait for the returned `Promise`. If called with only the `key` argument\n`durable` will return child `Destructible` and await the resolution of its\n`Destructible.destructed` property.\n\n### `handle = destructible.destruct(function)`\n\nRegisters a destructor function that is called when the `Destructible` is\ndestroyed. The `destructor` function must be synchronous and should not be an\n`async` function nor return a `Promise`.\n\nIf you need to perform asynchronous operations during shutdown you can start an\nephemeral strand by calling the `Destructible.ephemeral` on the destructing\n`Destructible`. You are allowed to call `ephemeral` from within a destructor\neven though the `Destructible` if officially destroyed. It will be monitored\nlike any other strand with exceptions reported through the\n`Destructible.destructed` method and scramed if it fails to complete or make\nprogress within the timeout.\n\n### `Destructible.rescue(function)`\n\nOnce your `Destructible` tree is build all of your exceptions will be reported\nby a root `Destructible.destructed`, but until then you have exceptions that may\noccur preventing you from getting your `Destructible` tree build. It creates a\nsituation where you need to create `try/finally` blocks that will finally\ndestroy the root `destructible` when ideally the exit of a durable or wiring\n`Destructible.destroy()` to `SIGTERM` should bring down the tree.\n\nFurthermore, if your application throws the configuration file error, what about\nany exceptions that are in `Destructible.destructed`? Do you log one throw the\nother out? Log both? `Destructible.destructed` is supposed to be your tree of\nall exceptions and now you have an exception that snuck out.\n\n`Destructible.rescue()` provides an idiom for setup. If you need to perform\nasynchronous function calls to get setup materials (we're talking configuration\nfiles here) you can perform then in an ephemeral strand. If there is an\nexception it will be reported through the exception rejected by\n`Destructible.destructed`. The immediate exception will be `Destructible.Error`\nwith a `.code = \"destroyed\"`. (You know, so much easier to document if you would\njust create a `Destructible.Destroyed` exception, really just, please.)\n`Destructible.rescue()` will swallow that exception on the assumtion that you'll\nbe awaiting on `Destructible.destructed` shorly after `Destructible.rescue()`\nreturns.\n\n```javascript\nconst destructible = new Destructible('main')\nprocess.on('SIGTERM', destructible.destroy.bind(destructible))\nawait Destructible.rescue(async function () {\n    const server = new Server(destructible.durable('server'), function (request) {\n        responder.respond(request)\n    })\n    const configuration = await destructible.ephemeral('configure', async function () {\n        return JSON.parse(fs.readFile(path.join(__dirname, 'config.json'), 'utf8'))\n    })\n    const responder = new Responder(destructible.durable('responder'), configuration)\n})\nawait destructible.destructed\n```\n\n### `destructible.working()`\n\nThe `timeout` property of the `Destructible` is the amount of time to wait\nbefore giving up on the return of a strand and\n\n### `destructible.operational()`\n\nThrows a `Destructible.Destroyed` exception if the destructible has been\ndestroyed. You can call this from your application if a method depends on a\n`Destructible` but does not always call `ephemeral` or `durable` directly to\ncreate a new strand and thereby raise the `Destructible.Destroyed` exception.\n\n### `destructible.clear(handle)`\n\nClear a destructor so that it will not be run at destruction.\n\n### `DestructorSet = destructible.destructor()`\n\nReturns an object used to build a collection of destructors that can be cleared\nall at once. Not going to document this because its dubious and I forgot why I\nmade it or where I use it. Couldn't `destructible.clear()` just take an\niterable so you could create an array or Set? Oh, I like that. Let's do that\ninstead.\n","readmeFilename":"README.md","gitHead":"5baa4e055441c0da7d4929b1d2b1b14cf2741c25","_id":"destructible@7.0.0-alpha.33","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-B9KQC2ozgpZEXj0qTu3HHK9Mipyy7BQ0dY0KfRsvXLF8BzDk6F4Hwn763ZzmDaDeJS2U+/HJbztKzWJMqZwn+A==","shasum":"967eab631706e842c2484757edb1618d44d3dcf8","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.33.tgz","fileCount":5,"unpackedSize":58064,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf+Jg6CRA9TVsSAnZWagAAX3UP/1xewl9sz9jZ/FLTcu0P\nqtf+4ZkCbahvUHN/RrmPgYnw6ODxEPXMh+el3hCREnbQn8mhmRLVwrBiS7OA\n8a+UvMgZps8Zbk8GeyhIPuFozjAgLTiuLhQq/X97Glg2XMQXBTz6Ek7grn1k\nvPZniSa5HxNUkwU3SYZgX3rh2f2OELoBXP/VeEY+Wjd7PUYkdO5Gq+YsWGB7\niiVUAAcLxn1xUGNLXT9iY9MoXbRUsVgljuN0vx/B8JgICLZGmR4rjPYAAcgh\n5usECKGCzCnXLxj1jkeuLtBYrOMJTdr9p69/DD0//d5pgcZ9cVoCJbqQIKHj\n3vp5FHrGpqgQfcihB4EuSxu8vmo1jEV9+QU2EfeSzM2duUDbKiC9UrDUFHlG\nm+lA+91Zzww8/BYNiUMJ3k0FJlRSKy17QjrSSokzBWxWXglzde9NgyKNk/Sv\nr5rcastGrGQJuYz3gfeQM0/EHmvsiqrV+/by1fdBwIagPBbz5mYJbQpkvo0R\nNWv4Ko6IzIep1EWPTxz0Elwv3AtAXsbsEk7DiA9INfG/Z5IuFkV/Lgo5jbGs\n+HagnwdhsX6xbRx7hwT1uoYXyZsGavuUtYsnNolGMBj/H5SND7xMvvSHR47n\nNHR0nJ1vcyFfnCalT8unZQm6VR2q1GB9lwnaviROCTEo6F21z9pNg0iIk2Lt\nRr9a\r\n=ZwkM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEnbR+vIsrV7G03erjj4K5RjbOvaHTkk/ensV5NRrCKuAiA9Eo2tfQJ5+Lm7mx3zWDnaJmWu9FFTkit5iRXLmjNzuQ=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.33_1610127417735_0.3084010153970158"},"_hasShrinkwrap":false},"7.0.0-alpha.34":{"name":"destructible","version":"7.0.0-alpha.34","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that your services can\ndetect when the failure of other services so that they don't attempt to perform\nan orderly shutdown when the services they depend upon are in an unstable state.\n\nIf you have a database service fails a single write for some reason, it should\nprobably not perform its ordinary database shutdown procedure when stacks are\nunwinding and the program is headed for oblivion. It would be better to perform\na recovery procedure after the system administrator investigates the fault and\nrestarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable('group', { isolated: true })\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable('group', { isolated: true })\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"83f2777f5ff50f32096a8db469c847a0329c11db","_id":"destructible@7.0.0-alpha.34","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-JhhZ+1C5IjGAEiI1ktqIxjoMQk99A7dO1J/TUE3CN2/kwdQyL8HWF2aAVr44khf27GrE3zw0tf1pLoluaUVPJA==","shasum":"fdc7dfb0abc11a4953dd22c437aeb047f51f8f54","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.34.tgz","fileCount":7,"unpackedSize":71704,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf+zKACRA9TVsSAnZWagAAtDkP/A6gpNIvKyfpjVOXrjga\nIyQFoklyf/AgkwYNSIVK18RW4jhkWH8nNSsTQKNAfRAuDpsoYOl7h6QQvWrf\nN4bzPtJPQ0NtZVF4LJ/BbpbogghgRKs/0WzazC/prz2ASoAWDerX0/7TmVBc\nhNZrs4DsgM+SfnOTzBvxOhT4wxcPOPHcgo6WJIarGCyBAb9ei22ammrcsD9I\njb+NICYCC+j/i/yHKzp6yQ3PMrZry9E+D7Z4IGjPGMQRpVsGTOQi80BPD0qy\nLvAgTOyA8nZxC3j1b06RilrExi/7SD4P06wLESSwvLzMd5Y4FxqZMIZafHol\nijviWOZ+gwpWA3Dv7hX5WXGawNrhkU/cKei9+5p77qc7IRi7Nl1o6d8tc2yX\niSTAqaVdYMlbUbeyCC95BDEgx11xfV6z8lvnrtzUlFujpdKmmsdF2iinuy5Q\n7VWVvISwV/SdR+BIKTLgr3zej8LFWYaTFdIOjzII09K3oqjmst2UeWUnD9i1\nHREFGSqxKmRNfnncgzdLpAl1U3dhXL9KCxrqt2etywJ+Q7j+sVx/PTHSj+hx\n/xtfego86Iz7FwRlN0yehbNa/Jsq6VacwlPNpRynhNJkaL2zKMdV93vDnIzA\nxobbDntd101UYPCt0FjwirF4kfaSpUeuOHW03SjngYsCCtvfvjm1bkCmNctw\nBORW\r\n=qJcr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICAWxzVLDUv/xXnxhN657booPZ0BxwgWLCm/mnXR6/S9AiBJUXy19jnOOUee2jdNYpA3tRQ6XshflJZEnl8CmWoAMw=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.34_1610297984239_0.024854816724730444"},"_hasShrinkwrap":false},"7.0.0-alpha.35":{"name":"destructible","version":"7.0.0-alpha.35","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that your services can\ndetect when the failure of other services so that they don't attempt to perform\nan orderly shutdown when the services they depend upon are in an unstable state.\n\nIf you have a database service fails a single write for some reason, it should\nprobably not perform its ordinary database shutdown procedure when stacks are\nunwinding and the program is headed for oblivion. It would be better to perform\na recovery procedure after the system administrator investigates the fault and\nrestarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable('group', { isolated: true })\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable('group', { isolated: true })\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"20915d35757e8a0935230cfd3924329c757c8c87","_id":"destructible@7.0.0-alpha.35","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-bRWhwVa2OJSEQFBTTzPlSvlDFUaAs1ibhKR89x6oSnD2AmTgxh7vniQ4WG1iPAvQjfusIjhdOtsKXOV6iGCuUw==","shasum":"0a97275150d3e27993ae8b96295e273af936ea94","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.35.tgz","fileCount":7,"unpackedSize":71748,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf+z7SCRA9TVsSAnZWagAAd8EP/1PI1iVRSwxM2ucZshFq\n4dpOz3d40X5UkM5JrM2HgRGNWkonvWLPRkD1tBE5icXuM3fKtCs9w5Gnpohk\nASxS6qHexiSn7zLa4tkORqUCDAMd01gtUQANJ9BGRJSOtpH2hP6ZIyOx2b8e\nLMM6lWrnMlnuoFZLzS6SX0qfPtC3AR8KWEUweqNvM3vLBK0vn9C81+BZlzl7\nUnjtjiondNeZLmV6LjVvibKjQDANd96aeggJSlqdipGSx9MPnZrxdXpU//Ug\ndQfwZ1p27KpaqoT2niMuH4k5MDC0lCMgudCIOSyRHWJXWoXGi5REqFWqqJp0\nnadpZT/lkP0qWJjd3Fu3CEUZ47VQGNIRiKOPy3uvccCFlMso01z5QmUIqcRG\nUSd4FjtOubnttFJ4FPBQ/HERIb8wJw10RZLKog8TseE9BJP+hoOwcPc6fv3E\nosv9IjCsSwI9VK3kDsfpsvEPopBq2DPfIP08g/k8+a8oa2RhX+2eV6FNWm3F\ndC/AHP3UGt50vmzkC7CQKKH6xg2AxRUjn4ZXStcYzf7Fy0J3n95ngmSSfMYV\nwRoHNRB4OKT+ZJ/MFAtgfd94z+M30GrBHGJuIiEayHj+Dx87Um1GO1Ys6iaA\nJL+VkuFCBOAs4Md3lwUeslQbKOyiQQJkUzuoYppZSOjy3oBwK2K0HWqTCrP0\ntSKW\r\n=/a8V\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG2lGbWZv5SYyhaZlJPwsmkjvOv3GPa6+oZcOnoe16B2AiBfW9dVOK8Q/OHSLN8vn4YdIantj3sbcxcSc6Jb+QaK2Q=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.35_1610301137915_0.47227661585542746"},"_hasShrinkwrap":false},"7.0.0-alpha.36":{"name":"destructible","version":"7.0.0-alpha.36","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that your services can\ndetect when the failure of other services so that they don't attempt to perform\nan orderly shutdown when the services they depend upon are in an unstable state.\n\nIf you have a database service fails a single write for some reason, it should\nprobably not perform its ordinary database shutdown procedure when stacks are\nunwinding and the program is headed for oblivion. It would be better to perform\na recovery procedure after the system administrator investigates the fault and\nrestarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable('group', { isolated: true })\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable('group', { isolated: true })\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"689aae0ad5a3cf70aabce03602b2755c48d9a1e5","_id":"destructible@7.0.0-alpha.36","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-4QBp+1eoE6KcGXu9vGhQP3Eb2q78GuPGnDUiQc1OoOvI189swyLv6W0HRiRBipnanntC/t9Mawq8OO0pJC9I0g==","shasum":"3dac29d2f3b0db4ac24a1ad145c0913b6a74274c","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.36.tgz","fileCount":7,"unpackedSize":71850,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf+0xACRA9TVsSAnZWagAAsCcP/2L4xHCk+DyRK4YE5WWA\niA6QtFH6yzd6RsTddkYQZ9RrFVl2g8KKmmD7C9ffhnLCa4Wawv7hoWqw6EnT\n5K1iwVCpbpOHMrcn68fPo6nn0dILm2SAq/bSWgiBMmQ2mKepOm65OscEycWO\n8yWXRtQW3Zg6Db6ykw5n5wAd75wTM53QVFLAD8oa/I/2k6taYEWb3HQscCE2\nFxCOmPIoOt7JdasIkDg74dbhOOcLlQ09w2M18oM7Q9i5OAFX8tz4uMR+oVlW\n7n3Otkn9qW2Rxcqn3HQr4jH3/wOnHaajRJB7ownv01Aa7sME2CCanFGkCncN\nfDycSKoYY3wvk3dI5JvyGHkQFT5Jn7+VDDrHhbZ0NQg9+LOaJsvNipk1mabL\n8XvywJcMqqwddbM1QosBw2G4SBJJql36w3xZzuZkUDYAqhwFzWgEStbgOVbM\nSh9tHS0nGWL2l6QRZ14aXhx4ZYSzMJfKB4fT9JFctocpSKGNARcjWKJqr14W\nLJ9gTJPL4DMuwCVq8sYB9rTL3X2yAQkHQiCzQ1jSgCYobD0J0uBGFfc/Fa1f\nmNTBQTYYL3voI6gc8hNHQHz6HpfNhKr1Mnx/9qQR3ifYKGMkuSrk8qzFgXOT\nwkd4ossmoPhDBPUH/ttvKuCj3mZXDE779vdZovnipwEeWUOQl5GdAlq65bC5\n7EpJ\r\n=H9aU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG8tWlocJUl0BZndd/xYBvfBTVsI0Mt9ctUkTqsod+2bAiB/qA+gUYcY1XK8BKjfw/Pq//1pxHujZS4y2QU8pQvbMQ=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.36_1610304575639_0.1610605498352935"},"_hasShrinkwrap":false},"7.0.0-alpha.37":{"name":"destructible","version":"7.0.0-alpha.37","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that your services can\ndetect when the failure of other services so that they don't attempt to perform\nan orderly shutdown when the services they depend upon are in an unstable state.\n\nIf you have a database service fails a single write for some reason, it should\nprobably not perform its ordinary database shutdown procedure when stacks are\nunwinding and the program is headed for oblivion. It would be better to perform\na recovery procedure after the system administrator investigates the fault and\nrestarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"69a47f48d4b83107b3962d1fa67e3a8171244c72","_id":"destructible@7.0.0-alpha.37","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-6slQ9cn0mrMM77e2WlaAmw0U5c1RwO+gcB1eY17AF18HK4+SX6j+zd6aa6tNF70zt0WrxSido2mSdeBf7Kk76Q==","shasum":"b3b49321d72beb2b2966b8216ab75a938638c752","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.37.tgz","fileCount":7,"unpackedSize":66098,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf/B1mCRA9TVsSAnZWagAAo9QQAIe9016YCNRdpk4J7MEy\nn00WT7PKxWBd0vJ0v+Aq9GAdu2pKM+0Si83F7AHrBt0PqFqy46k5fJrKkJuc\n/7bLX/5mi6G6aVTMB8xvV7BdIjrONmT59iv9DY6kcva0Xs5d1kG7nD1GfHAc\nTNkXJGuHLNfyoNVKOan4f1HA3j5v5A76CdkrDVWJpPpDnbT+bQCUji3OUL70\nlSZ+n3z48EwSqlmOXtiHRpo48cIhVXGsj5gRKfDNyvAhQtVazYk1OJtmQnCv\nHg2WfR/b8cYFOJ5esrMDjMeArm2y9+fS/l9wVtzcKYcSa8LZFj+Znr5XD7sl\nk8iGJvvYdAG/FzK2d1A4ojU6hu5T1XhKpvK0P77OnblSlWmhZ9PTOeoMqB+J\nJpzjTHdbR9+iKfpqR72L/mpOAqquQISxqsRNzY6Ol6gZ2PLuc3+H5kApRoFu\nA/yHbtxsjAKlkesajAyO3fo1jLVKKXhADSLp+UzlusDyQqkuzhvnCTewLWPp\nhmMA7QbDIS28crJvgEN3tyFw2NVr5dSYaaiYS81lHBijiwZRGGr+vs3Ed1xq\nErotDaINjYBkPctAg3YxQ6QlwPZOyyd5fgjqHP5Zzh8cQZOUTljWiys3w/+K\n2RQab6j3yi1P2Y7PJyngBQg4ujiTMl1mr/ZWXP4PBLFDZu/ZGiisgPkpTFar\nJbEf\r\n=MNU9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICPTRrSMWIjTvtNbT0I9jkgcO0L3mXGLU1akfT12/5ObAiEArnPINlM55Rmun+MHiy0ODKHJt5Xb5Uz5I6pwKsp9Wcs="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.37_1610358117937_0.5568755857181138"},"_hasShrinkwrap":false},"7.0.0-alpha.38":{"name":"destructible","version":"7.0.0-alpha.38","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that your services can\ndetect when the failure of other services so that they don't attempt to perform\nan orderly shutdown when the services they depend upon are in an unstable state.\n\nIf you have a database service fails a single write for some reason, it should\nprobably not perform its ordinary database shutdown procedure when stacks are\nunwinding and the program is headed for oblivion. It would be better to perform\na recovery procedure after the system administrator investigates the fault and\nrestarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"62a68a4df8fcda21343b7e17c8be991a6e5ce82e","_id":"destructible@7.0.0-alpha.38","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-qzrs35+n10tmKgizErHoYIis+odCAB7pUfqGjUhInp3QAx92aaGlXYvPvxlOwWRuzMOS4tOOcMMOqoyGWXaN2Q==","shasum":"37c2500ee7b1ffa7fe15322d9a12cb70e4f0c436","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.38.tgz","fileCount":7,"unpackedSize":64697,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf/ELGCRA9TVsSAnZWagAAmnMP/3wy2B2CerwD26DFbQai\nnwxumDGgkCpdfLi5dGJ45C3krdA73Vw2fCpJaLMuVtQvqdZt++dhy/U45sXR\nzSfZMs1UvMeqQaqStsrW++/CkBj03jfxPadafKQnbsacSmUDTEFecFogI4NO\nJf8jdramGYhneklHfJ0CPsggQjOT5qQEGunmNORAPn3oqLxcCxjvGsfesFfV\nVhdSK3yWyQWsed3jk9zVPcyCa7xHpdMIIMUx+J7swR5UVln3zwHxoJeIsnc3\n37sxiTUrPXbi0lvb0tAq1ujzuahDUWHX6D8hgI1McNGfESzFU+L/mX/+D0vR\n90cA88oILlOyL9LvgUECroIZ6AGFR21rsTIEmWgHYk8YHE0DA7NAtXzsDUyu\nHSB3EPCYW3W5pnIiHJEMzSpvrPmSsflWXUUfGPFy2o5un6gd24CllHfJiVxT\nYMceKwS/REBc+AHMqmmUWnevLwiyee3hGesu786ET18l+l4UYxIxyTWAZHJh\n8agitaALoiVBWRdilN4s2IkHv3mEV2ZaEI5HABzK2RqOS45Z6H1Rrn2VtUHA\nSbo9r7BGSRzIvofJulllgeKtaUZfvDXaE4uK8CkJt1DkTF3tqQIg3DD/23yo\nOIcP+4q/A0sTT7tCqj6kANXObgpINhugZndH4QyzqfDoS3Er1G/j02uaGlXM\n8Qeu\r\n=GMfJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFrNE/gv2NYktMvt2N14D3OgVy+8HGw1jwuF/yp9ekNRAiEApMjsTsVZg6e6OSOMXDmP0LjQlq6XDkyoRC29My7rzjY="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.38_1610367685554_0.7971482645855095"},"_hasShrinkwrap":false},"7.0.0-alpha.39":{"name":"destructible","version":"7.0.0-alpha.39","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that your services can\ndetect when the failure of other services so that they don't attempt to perform\nan orderly shutdown when the services they depend upon are in an unstable state.\n\nIf you have a database service fails a single write for some reason, it should\nprobably not perform its ordinary database shutdown procedure when stacks are\nunwinding and the program is headed for oblivion. It would be better to perform\na recovery procedure after the system administrator investigates the fault and\nrestarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"3c3dbc5860e980ac33443052f7b6a93fb85549d8","_id":"destructible@7.0.0-alpha.39","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-+9AJKIj+Z5+3OVlvipm0bmSWXL5OK2hrB20T18Cxp7E02gzUDcoj4cWUoJuQVDzLxBUlQZeP6FfmsZSroPG3Gg==","shasum":"29367c9b103ed4c9e323750f8c49419a0fa7483b","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.39.tgz","fileCount":7,"unpackedSize":64792,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf/8pdCRA9TVsSAnZWagAAiZUQAJ5NwVtwGJkPBxZkQ6Jx\nBsZuqNGQYqtcbbCO4RW1TnuDYp/WaMsZJDDpHkk+jQZEEJJNlLPGlFsgycKr\nzb9ZPcR61jy5K74iFTR98v1QC3a+E9PDOgHkWG83sljRStIH34Qsh/JeUMTK\nLczxDjkSEYxdZGXK+KtqHW8ho5kARZQYPByX/R17PNqbypAAGR3iK++NqTCZ\noGhi4/6SfOcSOzLNlS0g6+emVgAUZDttPQQMXDOcjtUKTkJIhHRX9iJ436vc\nOwu9Q9FIsxc6soA3zoG9aAeyhjLQiDdsyzB3whc9uEmiPAJ/85pCYohi7Jal\nkNAG2wIIS90EddbmQnW9L1NUSwIft3Be7kzj4W/wjxiwuLG9KRd76VzprBi1\nYE3KG1JBNBW5jf4WGHKPMko3OMNcxFgoRe7uyFAc3aFxvTyUyYCOl4fvgF7q\nYEmtx6RQebkX0H2Nb6n9BBCDpgWIY9slQta/X5PtpCKbKJHRaD2WZqDAcP5P\nEIA7lS+WhkZ9RU/giACLFH/rFaH1dLhh5KgurG1qqqwTQsdxvRJ3EGIuqLDw\nHHWyy2tj7LRmG6hoPJe3zmImyIVFHzO8wieltBIuBS/hQs7GKFMYG7++tKFj\nfs5Y5mm32RB/KVU3WjJc/dC3eN+5kuNEdUJ397SNuUy/w9R1YAoLTEQnWCXQ\nMLEI\r\n=t4cC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICyONP/3ArlBIcbLqp3pg/IwEulnzrN3+PN0W/PjjE6eAiApequ1j6B6EYxdaOku6+3VQB3Uxv+0sMPjTU8Y7HuVTg=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.39_1610599004627_0.6138771388810091"},"_hasShrinkwrap":false},"7.0.0-alpha.40":{"name":"destructible","version":"7.0.0-alpha.40","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"792af709a31f025fbd31570d7a9a49bbf1f971b5","_id":"destructible@7.0.0-alpha.40","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-PXJ93daw4kygaOxEePwH2SAyQioTKVzIpSrYz8ktdxH5S4HYQmjwvBLUzibnFxftNPBeJmBK5P4ChmyJGKcKDw==","shasum":"562b8e13a2a95eef97fcac064b3356f90ad64e59","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.40.tgz","fileCount":7,"unpackedSize":73830,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBbRJCRA9TVsSAnZWagAAAAsP/i8h2XKPl2vGo2QWnBA2\nZJr1Lp/oy6hLmxZuO3dQXi9FGHrNL6izaPHCUPFS5P84tTlkBZpSeoRQ2xCl\nL/4BANNUJ4l2RS9rM0c7fY2odZ2C/eGFDPuJH/ivgZwNhzOUC9jmbEmB/rJ/\nz2E5DUVOehOMtn5i2ruRE9VYudLJv+v7PPn0xNWy37fawUWOemwXRT8AL4Hc\nFEzfmkwLc/V9jO6fysliDe1LRQ5BGzt2Mm3Sr6Fk5XDJdSVXQsZDvQ33/VYN\nZALJFpegisKrKzm9Nr55I5zB9q2WjW125xOkRwCAceGiD8NUSzQUi+U6sn08\nWWg91c7vD/9IIDl3DWyT3MzxN+icX/TTjqbNMDsjB4pOFtpBK/1/pZHI01G6\n0XYp64FMzowHbIj0cxgxt4nt/r1M/P2IuoKhPhaKSTe7IRjR75Jv/1mn5K1g\niv8eed59JmSGDdtXT5qwNBtg3M1da5yWV9W0r8l6jPfx6DIXriB/+p2y5HmN\nquo9i9fP78rMX/GK2ivQeBesuJq7ixCP33oNLcwxOKC0ah58KJLeDVjQl/4v\n/MMILLozwgcx/qW0qlGfdEsqtZFaMmnQmiHSNcnITC7UTUgdAytUkoaE8MWV\no0M96Skv/fqFtFu0sewsr0nwVt8DGP4Y1VfWulb3YHJp1Rt7O5T0GCtnCC/7\nVZz0\r\n=9FNp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICEHf0UNP4+zGVLxkmctkPWD6StJ8itGKbSxxWjJQzB3AiBOVhffvUVHXKYtGzZGzEZxmmSHB9CdpZK630LNesKSug=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.40_1610986569228_0.1997860477698432"},"_hasShrinkwrap":false},"7.0.0-alpha.41":{"name":"destructible","version":"7.0.0-alpha.41","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"a474c7ad82be0c042303614beec5baf3ece5e099","_id":"destructible@7.0.0-alpha.41","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-iPwB1T/zC45pBAiQQsdGwWr4UhKRoTDs0AryUu+LhQlL+NFmpTisWK0XhsK+M3whPWmANgFleOJWfuUkzfKnsg==","shasum":"5a6e98279e70df1f8093d7b2d4e4c77da5aa7a16","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.41.tgz","fileCount":7,"unpackedSize":73830,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBbWkCRA9TVsSAnZWagAA0V0P/jXV86VSdrgGdklAfNPG\nvuvorE3I3VakEtpeUwU4OSEIckFc2vEQaBHBPhdFRzSuCNkySkDAUGM3XYoz\noaslDSnzT10SItNK+2BxtHG8iKu/coEkGtEWacLUsGu/fju8106vBoC7lrc7\nK8EQBVHVXZBKYCGcvV2Vp7zT8aITXyegRDaEuYs6EKuZNOIALntQBhmxCW9E\nf0TNtqPy5dno9dBI3ZGF3hbcJ2ijpM5OKyRLKFFnJ6FJRhfltz64YD5DNtCV\nYq2yAw6n356aVh8hQsQNcsSeOCJQr+8lHVi841axcprj71lHQwwetjIpS8AP\nwcY5/HtPS+3MRLlSoS4bGbU4mCyJNC2Tgipwnt3xtxQYICtavKAB/hiXqbFA\nm1NmIZUQWn4MLGN/8KeJJ0vDrEHCpViP9RGlHFyvChoHNR3ONeI4IqCh+t/M\n0LzH/CfFIx/836OsqQVv1jYVqGXb6V5YygcgdXXwa1LK9rh5v52250K6eETa\nQjWhj2Z9owLx4oW3vC/3sO7GWdkXZCPEl58ytLtnL+GrEIlnSmPD4aw/xNDS\nTOewoXdjMg0tDSq2l4pSR33q797DDAAPz5LOHsj4VGq5jrTMvRCOSD3fPmVk\nhxiCjhJTbEv5KWPB5WezsMMsg86b5rcAkRsYPoJfEAk6LB2YTd6odeEx6uUr\n59ju\r\n=9vKl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCt7fouZ6PWHvOVW9hrOFc4WUA1z5R1Y1oMb51TWMA34AIhAKul/ZINb2UCT/Hxe1o08UoJdLOHuv573nAWF3s8MuUj"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.41_1610986915848_0.015320026878363091"},"_hasShrinkwrap":false},"7.0.0-alpha.42":{"name":"destructible","version":"7.0.0-alpha.42","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"2f997ab201be54a5ab562a8f33d281b26939c012","_id":"destructible@7.0.0-alpha.42","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-HCBba9W8VpJ5p/1oNZlT2aucWHVm1Pc4ee09byKYLC0TqHOl46/He0gKe7S4B6wmhSsHcNNOPjj232DV7RhKAg==","shasum":"92f2f0c9410c61218eed7f78bc7bf28d0340dc2f","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.42.tgz","fileCount":7,"unpackedSize":74186,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBb6xCRA9TVsSAnZWagAA2VAP/0kiJDHKlSQTy/LnH1EX\nKy118uceZpBuCQX03z6czv3FKahe8kjFgg3t+zNGu8wiN25FOlDcmxxBaRwd\n9bNR1c6EsiQf6paM/cPItsH0DNDW1mlksQXI90VKb2N4r1Yw4LwthdwO3cRo\nUuJhFU56VvJ69GSKvczFcyd9JANs0AjwX1ZaVbE2VW29mMSbm8W3Ts699aGv\nRt1WCLkAxapsqEQs44Xnb/3N+3DP7HPqpJ05pu+JO5xf8Yq8nTWgQ4kNmGGt\nuQ3KPwY5CXJI527GlqYPZqLv5JQDaA9PKocruNrFWZ79tYjNTp4X6DD9ib3n\nA6BBApf/lCg/1NQ6rIItNZPtsgbnvYb31yBPzLTgyPdazMYSHWWjywCsUSR6\n+lTCBhGZvI0WWzhnb+zm41NgAwvdlxMbzePq9nh9xj4inA8x/ABDaF0dE7KS\ndJ+bryoKhjVLaem/gO3bVoJMgytqc6dGW+FMiqf9YaEDcfbcblHx8W47ypFf\n3tMacY1RZXydF2dAOP0XDe3ugQ1LXHFvgJ5srVQlD59tMdBn37+Xo/UaJdhP\nSyJzYTUreDFMsM0gI+wjDwbfbsKuP9MQgjHuLgPvWmc8PH0MFiHQTPq5OErw\n8CFFfCJJaHHSFWYX2i65bPIUf5kAbTpfB8q6ONXx3svsPMOh6zZIlEyKk/2t\nduX6\r\n=B4Pq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC1EzNs60gW4XOJpWaeULNZfHfVfblKYkdW0obxqgxsXgIgLdsy7HAvbdBzxYiWhLgSfaKiczTnqYriG4fyD0ZmVK8="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.42_1610989232996_0.19020565019538438"},"_hasShrinkwrap":false},"7.0.0-alpha.43":{"name":"destructible","version":"7.0.0-alpha.43","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"f5e665e58a8675fa4908bee2b275ee7b1b4e713e","_id":"destructible@7.0.0-alpha.43","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-dUa1TfDtmadkFsH+pqMQY7mNG+J5ZPuHxU/AEaeqk/CRgY2YXJwSQJiKVBYkybcBuWIR1SQUxlbtDHEboHHwGw==","shasum":"c72a1af7cf290a846701647bd612a1d860e6b879","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.43.tgz","fileCount":7,"unpackedSize":74002,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBiWECRA9TVsSAnZWagAAIRsQAKDBJBTzTsSB7vnMPV5f\nDIYH/5JHXCkRMGDgFIQZYWWGzSkYZKogceQJTEuI+HDbLf/jv51p+gf0qGwF\nuFbpvSwKA5cQT+bVIJ5ER8YVPejVBHz6kfl6Z5FiyZSFSM7aqvTT/XB/FXsj\nhCXBnihlJcG1LqsgOWa/bY91DnZnNzuLIhfRx3IEhbnE1CpUZzdbRQUHBcxQ\n/4VxB+528CY2wEugm49XuVe8vnCaVTLIKa9BUl80c5HiIc2p/u04KZzmvOJq\nlewpvqCSISJr60cVLm2n265DNIDWAEaso5LBwXaiDFPPp1XL5Mcy9sfbBGCb\nW57oi9h+ak3i7rBd6MeJOaZRzgLFmBNJgfdjqDy0Rcbg+ASyaKJEycijNxnx\nyEn0g+Nna7RMymt81913Y57YTIFxgDwds1vypcoHLooXjofHFo+nO7NyUhlX\nmsVDDFIZVIv44iXk1iLKa916wmejyXq+M7c4fDL0Di6o7EzNZYI/T303FGvp\n5TiGzarvlxWoA78W/Xu5zEqsd7a0xF3Aqli5IvuuTav1khijxtr+qn1cJSWa\n9rJU01hPw4Z1m234NjI+bq7w7tRWRa0V0mx4Gc04mIherUpAPxVPQcvqvCNZ\ntzCZINKyWQ9MpYDk/PYBusQ9D2VD1JsnK8uGRUJaQxqVnj193sBrnBbW4t7v\n0KNc\r\n=iOlv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHBR8LWTry50TjhiERPhdddop91ck6kiKUhDy5sgEpmhAiEAyVhfi4FSPIC4/ZFeSudBiPWS7mV7mW6KgP4CFCaJ5ig="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.43_1611015555957_0.5754135417522135"},"_hasShrinkwrap":false},"7.0.0-alpha.44":{"name":"destructible","version":"7.0.0-alpha.44","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"dafefab9be5be9c6a2db383b96d012d032f80f4a","_id":"destructible@7.0.0-alpha.44","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-DBLsAx0iENz84VZAf4vs5P47vQcMLPb+CyDBTFbwU8uCk7EnZjInWlDkw9zqE+wYKN9vhZsm7cWV/ZBdPJ/8Pw==","shasum":"57be216270d1464df06d514b63e1fbe7e17161bb","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.44.tgz","fileCount":7,"unpackedSize":73954,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBusdCRA9TVsSAnZWagAAvW0P/2ZiLhG005331nofAZXE\nkoLep3xjfXbS2v/AZE2VYrYOQbOuQeBa6HqLBWsB1euqto2UmZ8tjw7QgbLm\n1rF1jz2ncblB8IsUgdW/8mz16fgqul73aFJH+hkrufj5loCk6vnacUdUxA99\n+TxV/T4/55ZhBQvg/6wuLVFsIyL5hxYjBUZegqzR6d72CjL+aa1Fd+j9fW0d\nDBpUHH0FzPfP75yZ+1H8G0Ijh3R3lHLcDQxTArMux6g5vJ5hesBdPqKvJf2w\n8lxnydQXXBry5fPy7uGwmiD+PAPwh7u96HtWf5dGETHSPCtS2R5pIBbokVwb\nJGyikegV4mgf3bs8PcggP/R1H6fckcm4sKQjj6cQzRYcNiKfL8wIHOQ43IcZ\nVWMZPPZXamBVXQ/EVNkEBHxnSu2mk/56t8tPxkSkuwRW0nBhe4128P9ZCdVp\nuehNoX/QnAOBEu2TqxxZwE0EHuzDoU8Db0LhRhvOUBkHxvG84edsUBd5GJMy\nMlESY6PAp0hcWAUhOW1ADXfz0t9lzKnQGAlNBhJi85JsPmAFMoELwUm24PRC\nMNGoIz5AHVlukle6s4eIxQKSgsZ5cmtdUtWf2jMGmOrX+gQMxAtVd5tpHhIe\n2JOLJfCOeiROYkr6saKR4GCx1HmMidvztG6RXXQnJg1qXiF5/uMjJ+c98i5f\nrViF\r\n=1PfR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDM1vYe5yFBgESlInQ8btz1CODS28QKIvjvrHx+OebR4gIhAOG6IW+yXBWZ8354GvkUZ2pG/9I4HqL8uWIWnGcYciOL"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.44_1611066141054_0.6745350817439217"},"_hasShrinkwrap":false},"7.0.0-alpha.45":{"name":"destructible","version":"7.0.0-alpha.45","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"de446086d231f0ce28a3a9fa22173de30e81df7b","_id":"destructible@7.0.0-alpha.45","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-X7XVPB+HYBLrA0FwTomY3NsDlW87h3zKThtX4rzm78CSO3N0rFnEiVSC4XU78/08Y+50mI3z+0gx1WYZYOnRkQ==","shasum":"c3d0d8ab759294b7f376da77a6e39ef9c7c6b1c5","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.45.tgz","fileCount":7,"unpackedSize":73954,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBuztCRA9TVsSAnZWagAAAhAP+wYIpW/mjEMJU/uoy/nO\nzkzg8ukxHGZNWb0ZM+D+NyoHPob+RMColLuAvyhJJvvXeSJnMJON+FFCTwg/\nNAGalBEd9HQUGsWL7H/luoGSLcRxcTgKXjKDQZlYjjpFMZAne/zzG7iY9Vot\nDCCL1MPBB31TZkUkoPUZYsflSvdvEcRg7Jh+UhSrnaSoKSrDkCs9yoCpYJxQ\nQ2U+TgaWqdQ/GJH04TVhRp2nqonWjRJI6ipaO6S6cxui4NrmO9d05bDjSYf6\nx8maCi50fP5S5hhzhqdycV5GShjTe+qnQlZe8w6/r3vc9IQ1iUvux9di2fvq\nmv2O8yNnYCSENac0dDjJSujUUGsfEPvYxnA/DBYYjT1+/KnMlhAS26K/fkLd\nBXL6PiAHoOivf+5toMcy7Rwd5Qkrk2ArnTzkP0i/x/b7Ii+9BhLY03Mz6Vas\nxEKsBQfksasOEiqp/isZ3kj87VDJMdKqHXv1vC2YG/FA2FLr/9ey4P4WgtT/\n9tq5hzLxKD3tffCKfp8lpJsfSuh//YkQUhZrZ3CvXMPfgatIGrAynOdaR6P1\nYOXrmusTUzc9RS8gxFBMSWiI+2cH5Oo3YAiy5qkrrHi4Y+wKtMH4vwsFJayU\nHFPxXtkxP4Slgcj2mqura5sE7ne4uZT0vZJoLAeMVDKgYktDGAjwA8MPlxDK\np4e6\r\n=jCOe\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAEUG43I/qVuf/3LpEkSGtLi5SimIZNHzimItFuZVdXCAiEAmUl+dTdypE9B50GYgfZQhM0OfTwBCHO9g+/CeWRITKw="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.45_1611066605371_0.7255690440020424"},"_hasShrinkwrap":false},"7.0.0-alpha.46":{"name":"destructible","version":"7.0.0-alpha.46","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.16","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.9"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"d58aa15b3c0640dcf55da13e8c5a2ade0365db34","_id":"destructible@7.0.0-alpha.46","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-iYo6V4e2+aXVZgtxqzmsUWK7dqfN3YYb0GFq8limOVooC3mpyxrFDjn1b3To2JWfo1TkIhA+WCpHZvm6qZkg0g==","shasum":"3018a8170e625215af98c9ca999fff6b4b4f65e0","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.46.tgz","fileCount":7,"unpackedSize":76473,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgCZVVCRA9TVsSAnZWagAANl0P/3wqjR14w2yJqSb7wFcM\nDPvyLsqmXjH4YpzXO27m3LRqtPXhujJmcGsENhpyzQO0Wb3d+vW0Cj+3SXLN\nhRoMDLP42ebpscmnpaQYL7dBFoooTgLma9DrcQprfiF1gMuk06rUnXvyH5ve\nLyK0hrvpsUVtcKN6wUMFxUwUPUE3n8avlZkp5yWAepSbsurfXk9FXlM9uRxk\nflLWmkDE6NP5Ry7qC9ERhq0kDwXQFhYZD5F9D6C8F7eb6ANCjL8lA6h2BZ/b\nKbyw3p61at6ony03QDBUwXgNZzV+e22HBQsVBzb1xJ8Y4xcJsjD4/z8Szfax\n4d5QQ69eUD6opK7yR6/v/XINFMpWaXxKdxjPi+RPCLfh68GF4L1RyAPFLmxs\n+3zgcdcP9UwON0ceW1XeMosXU3TsV1Hbre5ROwpXL2LNfwFvScz2yY3itDx3\nnV3KewtXS+c4/x8bKCv7AzAkX6U+7kScftX+PJieOt4bblQzkG7nTXHUX++G\nXd7v37GsgatkP5p3uYc7N/83q4EglbW5i1TGR5997jt3sAqAotfuEB0EswLE\n/x+qBCF0gXIRxR7p5MRZYUe6J0tLu+DAJhFf+SBNEpljDOzODx74iqr3jxlO\nd8kKBmjcEraA6g6usJC3NFth9hEoSiXFymbum7pZ/5rdfJXNcgibYRvwbC1Y\n8XMj\r\n=jCBT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICsDdiPrbsDn2ezzTiHYCgAaADklCWE2/WMLDQclj3M7AiEA9UjgWydH+jRnaTXGy68GzXojl7zofUZjy2KKuTybZcY="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.46_1611240788856_0.6797610206268232"},"_hasShrinkwrap":false},"7.0.0-alpha.47":{"name":"destructible","version":"7.0.0-alpha.47","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"interrupt":"11.0.0-alpha.17","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.10"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"d4fddd8d4ead651a68dfee911081a1ef0c6eb609","_id":"destructible@7.0.0-alpha.47","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-XOVPA1GiDvc53dnzRY/GoQXeOCla/7mYHLZ5Dwc3khuT+s+Agzp3AG8f2CvQtTrYmOxyTIpskF5bJcnYxxIrFA==","shasum":"dbfd7a992b7c44f6f8b32abff53e6454f1c4eee3","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.47.tgz","fileCount":7,"unpackedSize":76474,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgDvXiCRA9TVsSAnZWagAAQtIP/1+407Pq2PuP8IZ/RIOX\nCFL9XJqsRnNLjcStS5khn/1WpjZsg1l4qHRsKTCfJd1ctV84xYXObSkyWcsv\nKVHQlwnZpns0RY/KJlAI0Lf/ksiVJSRTr0Bh/6nYOlEz+OIuUjJtbowIEEsE\nyVkAuFUlynQif1/LSgWKoM2AQ7vXY+3lWxLzx3oQtjEB2adij167WiDbrD6G\nKNPo6+SHvyyq61ZDxBSO4dGFSScEvsfsvnGhY3+H1Qi22fAMN8gMBzBFVaEO\nwnA05rdsUJLdYPJkggmIyAf9wK+SRxMJTAwvtQYMwpE7cl7vhXVDfWAR97B8\need8GtULgd1jn5XC6KLzVVuZlmgqdmuOI2RN7LB5dQcY3XgwZcIUy7nO07nv\nj2NNxgphK5R/Dw2bN9IaZtjollGKBNUqX2cv/3mCdNWprcozltwQKQ+LY0vL\nvRxS+ZQ5y62Lai169hCqZP4Cc8RUBNKITTqqUfT1fsaSCW6nZbzpObcGqJ9M\n7aHpFgDktskfZdp0OK8uKtW+i78g08KYC+kP4RqGXaGWRNbrS3oKcC5qHSwC\nrrhrqak67Yy8LTpindTY+4AM9PwWLaEYy3tAgP8V6QWr5bg7RIXLE6ui6WYt\nqoR8Y6ysK2SPW5cMWuVH+qah3JVe92hsB8Jln837JdlLv/glFcTxsoYyqx8Q\nDak3\r\n=q8Ab\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCCMGZh/ndeHKTID2l2TBNX6/ZollKha1sL/yZncCPavwIhAKSrGuvPmwD8viRb57MtxZWfS4O379b6Iblnf2IehFm4"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.47_1611593186454_0.4201348686920843"},"_hasShrinkwrap":false},"7.0.0-alpha.48":{"name":"destructible","version":"7.0.0-alpha.48","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.18","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.11"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"c8903bfb80cf38d2e3d77c9bc5682998f8acf610","_id":"destructible@7.0.0-alpha.48","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-J5u8zlkatINCcgnssgA3hUcvtDDB2/yGqKJjfLanxibU1FvvuyblUYVRnobhySQm79RjXgECFlrejU+HEw5Q/Q==","shasum":"24671b97179ecf00bbb058b497457a2f745c5162","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.48.tgz","fileCount":7,"unpackedSize":76559,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgGDl1CRA9TVsSAnZWagAAO/IP/12+L1YxdSLx++7qoliq\nehBvs1ACp7KXueOrBmgErROUE/cs0IoAWi1gqYuRU4MvhmseSUlMWPx+pIAf\nF7iaFbXLLHQycUtKEZ/cnXcqYTdiDcmc4J0Ls96eg4RgPqd3+SD1/Ol4R00J\nJGYQCKEAuOXa/gAjvQhtFgNKAZmGEpEUcxq1g8MBtfPOymgXmG7aBpnadRM5\nQkfJcB9dL6u8+/oYIZ3pHZeqq93hImXCXorXpULYnrmIcu6FzeS/5bogA0XI\ng0jMikgApg5hg8eUacuONlGxCXk42sAfhO/Vs1DVwyrjq0N12e7pHJqBzB9C\ntlJJkU6SKz4N/SJUsNzJgW5dDFc0LTI0Z2sRd78EoyG8CNpmC14IDI/h/FTX\n0ZD+iFXnMd6rwu3grNQsCrAOOTet2l902rFMxUaYXYvpbvlWtxklEGo1l7Ud\nR95aerMu914pJE7/HC2Awge3cOuChIUh6CJzN6pW8e+b64aepB/QJ0tugzKR\neDLVxGknYs1PZ+KBF8FJ9gpKGDclK0H/qQ654x6VE5bY2RQ5KpxXvOdkzZh7\nbFnrYC19iq2S62Vr5isDmJOMUCoRqDaWdq51SV4M7HcBnvR4ldTcCsAwgaWS\ng9Ccv1npsE/fPU04tDHQSKZmdTCtv5Wy2SDGTikreFmTO7aI74el1EDehUWG\n6FWf\r\n=TWOG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGe71FUVMyJ6av1VLzEl3W2bZlvzy0pWLjJhz7ct9pNbAiEAtpwduIzexJ4FUfDQlOyjGCa2dnz9c9p9dCcJt7BbMnE="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.48_1612200308994_0.2698948334364455"},"_hasShrinkwrap":false},"7.0.0-alpha.49":{"name":"destructible","version":"7.0.0-alpha.49","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.18","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.11"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"b14901cde57cf7508ac22f2cc9d1657e20a93d7a","_id":"destructible@7.0.0-alpha.49","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-0xKrYzAKuss7KfGtFkRbPOZcRzJfWpjbJ9NUXyps0G5PyNuDKquLQOieV1B0IRAyFfCUWewOdXTsObqyQ4B8yg==","shasum":"18c13239fb133f2f68dd8b13c7c8207f0b83b7a6","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.49.tgz","fileCount":7,"unpackedSize":76568,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgPu41CRA9TVsSAnZWagAAQwUP/jTW6lT4orvIIO4Q9bFT\ncNwrYGrous2Q5MNlJiw3Z3tuxQ2khmE9PPSgmqScYW0UlQhX5aANGOZBo4yo\nn0i2fsRQ3Ql3Oto0vmUqSFPmbnOzSzOYiIfuK40k6zNu3GZb3vI3bhnnrH5I\nHwEpXqG2bn+3k9CfB2XCfZfbc9jZvTg7Wd0ypsgtCyCpJqVOXa3vfMkMaimx\nSiHl8YZ2kru3T5WHj3MgWXT33HzKFak9GX2aygunaMwM5rGMx0C9YPc8YtIu\nw1MxkHUgGWkkFS16gx/922Wq55mVnAFvg12lPMvN6iSK3+p6agrWrG7BqRPy\nfkM2s/9Lk+vY1D30fa5n2HnxWvBcVF0jKgzeiOQ7M+NWZ0l3201vQ6Th/piW\nC7gPaJbe8V/dF00Ub1CFSJ3gkK1rnzaVKLSQCAQlOY4QFrjj0w7E/xeSb6LG\nSjJBdsvg50MB3EY56ggYeyZZtxWWSjrmPU7GGKeH+QF4KMCOqtqlV0p36VcA\n7qJBCCw28tWO0Nsb+tq9dPtVPErGBnx1ejOVwRxNgXrK3A5HSmrALIPqVho2\nVx+eQrUcr1HblJetoVVzNOqINaanaBZafWkbgKexv1FhnfE/5HIjaAyDF/jm\nsdBowjky65gyQuCVMAkGfow/jnNT3kfct+hsL3zEwFdni+mhBebO8NAmtnL1\nH/Pp\r\n=pWw5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGOCEeELKI8f+newP3IvD/ZkIYvmORikteOiqtbkUGbjAiEA8H2VQJn5zgF4tB/r/r0N9SAxSKIpX9dAfARma6PDqXg="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.49_1614736948685_0.46292905771656434"},"_hasShrinkwrap":false},"7.0.0-alpha.50":{"name":"destructible","version":"7.0.0-alpha.50","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.18","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.11"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"63bcb96d4c8580977fc271bfda96531ec5dca65c","_id":"destructible@7.0.0-alpha.50","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-v5/dbuUbgw4IaOjfE/P5mQv+gorRHCHv0YyIJmbXDEWeS0hxq7BpV0P92eYkxguMpyq495RTCSeIHankLm88qA==","shasum":"5455ad5e58cce334c3cd8637800cb26087cc3123","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.50.tgz","fileCount":7,"unpackedSize":76593,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgP8aRCRA9TVsSAnZWagAAvdUP/iTOLA/m+wVqAd3e0pVF\nR3RJnF8WvUhp4TqsNT6L0SdmOMZcZU94AiQTTAaOA0Xy6SZS0Cd4sXmaGaum\nq7kMsAYk4iiZor+ucFpsPTn6nLfX6Qj9mDVkfe9bopDEGxX61N4J3iRT0Ybw\n2G9a+/mdnSd5wcH3feXrX5KKJ7CVORBfoXdAj2BwjnpENtzjCUoiiGUMNiqs\nmgRda2prvIaUAAB4USq60+rh/6VxhBLMpJeb7yoh+byck+ZU+41HvAvgcwRG\nrAHNwRWsaE4VCLGASEjmHalZ8inOAWasMj63ZzimpTG6rL9sZERVdbbvZHAn\n0INDX66EjqZEKkHhC8SN23BfcDyavJF3/z48UK0dolXt2RVnD64iuboYpiWI\npiRxxCbdy/ExSfSJpbcP6sl+kZThlJHGnxbGnh/1h2sLDY198Oxxl7DiMxi4\nWL4LbXFAmRayacAIkN58Zi/ZALG/7wBeoHWTp7e6EsP/3cBZ+quxko1XPJWM\nqp9QiLjKxWnyzW94fjDp2BXwHnSleg0iXPrbfyx8BPFJdONaJyGMixEvwmmy\n7wqWcIr/f/XkpbiPkMO0652TkIuW5yCr59JJadX3SFoyHzfg0pmQcNjEw5Kl\nGaRxWnnSMqyE0HepAKP5RL8YMeOb2uuqaFJeBefSE01hMRYhDuu4LpJ/kR+q\nJz1W\r\n=0rQE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFqMxn2MjnTzDIzcy2G5TglZxDC/MNR6kf0Y0vmxitZTAiASM4RniqFhhktVpnK7UeGcrLCGiClhZm+qCz0dI04Z6w=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.50_1614792336936_0.29323708750359034"},"_hasShrinkwrap":false},"7.0.0-alpha.51":{"name":"destructible","version":"7.0.0-alpha.51","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.18","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.11"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"df008f94e6fd87bee165af9c3ea3b8eb21f02ee6","_id":"destructible@7.0.0-alpha.51","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-qIjNsm6LzYKDjgAukfRPSdHSBseDSuOActDR10an3oZaoHQ8T6SKY7VpH2k1KK8d21gngkJpYfgk8EBsubH1Qw==","shasum":"6e44f650ebf8e3017b754b98caad5bcae3274279","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.51.tgz","fileCount":7,"unpackedSize":76852,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgStCOCRA9TVsSAnZWagAARQQP/14cE8DbEWkETG3Z44Eg\nMY1clu6pyQe6iXTeHhTK+j0hmypj16kQ2C1eqbcsHdUuhflrwq/AqHGknRlV\nnnNqoi9TKyBQBhN1RBd7KVV2d1f8N6UxlpCrZvMW/6U6LeQp8bmffj8gKyvu\nP4tGImTF06Gpk4dbsp/c5PsUerHKvFOvsfZsJSpvBnV1eIqHSQEhqEELo79+\no/U8GzO2dkau7U1UoZwy/7ZmJItP0DMjRqUGj8CZIN9ZU9SG54sXjtKr84yG\n+Su4E0wG78A1YpmL60pY7W83bp0kmq6nuO38HwbeSrKGuShXXWZ9RZJxoHEE\nJx0i54TGRjqleIUVYAckrsIYcpGPK06hR7Ar/AzFdpO7OW69akouE96ldZ5m\nDj03Zl1UQkaPdI/oWfGG8bgXDUts57hmUE6RLqQDqjBTcME8YXdbcL6vUBTf\n16ol6pmA6uRRjZlBJ4qApMesWrpk75q8OYMtNTvBxJzpnP1NE9ciz4foc8FZ\nzCPdPgAK6T3iWNR0XPwz1UP7DJ71DV9D4zrIUeDDa/TlWxUKCZDReLDEdduo\ndJtpdj0Gfh/J7ms9ceCHE9vvZqmzS9ucHekppF2uqXq0EDfHuU2gOb8jJQHP\npd8QcddOYy2W4NIONQQgtOnIh5u6tZELgQwMc51zB+4vI76tJLOpiVJaH+AS\nTfvS\r\n=Q7AS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAvCbU80gJR444ROf4+UssxO5n69onauwWXqSEjIJjqvAiEA949JfIAvct9+9kTA8codQ4iy6G9l2txUnxdv+UdVJbc="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.51_1615515789644_0.5561415717560789"},"_hasShrinkwrap":false},"7.0.0-alpha.52":{"name":"destructible","version":"7.0.0-alpha.52","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.18","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.11"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"01c029bf04c30a996565273c6a47a90cb1b72f91","_id":"destructible@7.0.0-alpha.52","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-98Xs86FN5ctywBqfui+a3jnKViMOr90PSBHQy5g/OHB50ZpIIJtteKm88BKqhio4bbfB8O8E1KzTzl2CvWIwgA==","shasum":"54980079de07dc610885e54cd6d3299a92d27aad","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.52.tgz","fileCount":7,"unpackedSize":76870,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgStPsCRA9TVsSAnZWagAALKQQAIn+nwY1vXXFoGu0L9DT\ngB7zhtaMxSemWC4yo0F3A7/G1Yf5SEasY88jszZEcK+OtwdqBLefRhKJ+gf0\nvjSxjyFFbwf9wROAbSlZmOT2Gm0tm8kHa7WiVptMduhfyhTyBULeJWNMbJUF\nXOVGKlc7MSft0G2zNzWGQ+1k3IPjz+9J4NQmC3DsDhoQI5VJNPLviNpMm4TI\nQr2xYY7apTD9qtpn6P5xtju8yh8MceFJGfmmQHVTghnExY+yP1JHmSdWojSo\n3HEEfXAuuY9NJP13wABz4Gd6gLL+i9rRQM9MPID6HZL2eH+uBM1ESQMf+ypT\nNgqPgtgzvi6P4GBNyfy5m4X1mDuAc9MPxC/uxjC4Us8bqxDbYpWVoU/uyWTX\n2O/vsUTTT4cnub/WZn3HRkCVfPgMaO0aXIXjQchAkodgbhS58RP3e8oCbSH3\nyoV5Lm9eRDKEBtmXgPLwMIEeo38IxkSWomWv+s68qIOoLo+alqppF0WRF38g\nLPEd1Kt0hJ1Uhoyv7nP7jMMISRsfbz11JUq+q97m81KuIHUoiOCaDoz1wx2T\nesHhnzHyuQCY+ELH7SPmIDbyiokGzp5pY7VWujoc8XIt4pQESRQAR4cJJlXK\nChbjZcfYhGgdpLpfDw6VHHY/vGdTU7mGPeENp4X91i8mWlh2SIOKmiEUw9ge\nnsMl\r\n=EQW7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDWwbpRjGH/Csqffq1n0CPD2IiBKkicjBhUSPoqA9cmJAIgCHb3dEE8TNmA2OWPZzQikO9I4XjE7IaqvBQPDNcUVYU="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.52_1615516651614_0.1751679569201634"},"_hasShrinkwrap":false},"7.0.0-alpha.53":{"name":"destructible","version":"7.0.0-alpha.53","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.19","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.12"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"e2338ae3f6484155884f1def079f9284f2200934","_id":"destructible@7.0.0-alpha.53","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-kLMWgJNfFc134XSBi8R6yrndidkbw7qr12DDTFbeBCt/Xf+3CW7uWuN8U9xVlFjAm9bZP902qbLv9Zy9Y6D6Gw==","shasum":"4eb78da6d386fc102245f1e027a439be422faf53","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.53.tgz","fileCount":7,"unpackedSize":76634,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgSwWGCRA9TVsSAnZWagAAnGcQAJDS5EdzvzpIGI7nm0wg\nmKJCWV1qutssQjWlo7a5upbq/woanXwfKgI9QjK6iNT9OHc1XaE7c0emgE4e\nIrCAONUmWtsLELyXxyBNpvgy1HKtwbudFWjLay87w9Nm+cPqopXAlNPIfvAu\naDCZjGgUB09CjCMnnJTaMbeAUG5DVQC7vRAFL61wCfMbEcg8kKgvZG9hfIn8\ntg/Alp/735Wo8NpJ/pp1Rrzhjww09Gpt32RxqhcyvSSVZN75y9iuxgUPx+0c\n8QGI/hHHc2f+wcjmPzPOWnl2TVp+QHhXlJZLy56DZzOu7OH3f55ewtInVdRG\nw4o691FrWd3WO4emnc6QKho+Wy6Gl2+beqvTSUC2VbFleR4q+7uTffH+4vj0\n9D18EbpbwncrFSw8ULpWWrjUGYdXueFuT/5ajL/Sy0c266+Rt0+v5/j9cF6q\n6eH1pl9zUZ8UVKXqFvJ07sbu4qLxSz4XiO5JEaQGCyrbM+r2LOwp873jWCfF\nNcuGIcWe9ewdL7lH4ypRu/bRxXBUBItDU+PxRctUoCfVx4NFC8pkPTjUJOt8\n/O/4M2C5ZNRdMJbj3vbsIeEhDB18Gohn0uo5nO8Ij51uljB0dc3hOXkVxval\n6Z6sq8Jrk8xzCSOBYuhc56VDrroQZRa5ZC/V/bAvkhvuT6PDEBRk1thGMQOI\nr5Cq\r\n=9f6P\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDE7IEaorAdWpkobrYc6IGmGgpiGwuhldB4iX2SENMabgIhALkJ3kCsDtXFn9Ttz1tctbKw5P/CVdsnAqeAiolbOWqK"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.53_1615529350190_0.4427940371734689"},"_hasShrinkwrap":false},"7.0.0-alpha.54":{"name":"destructible","version":"7.0.0-alpha.54","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.20","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.13"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"9df6d737af69ff46fc7683124785075359ef6d19","_id":"destructible@7.0.0-alpha.54","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-udJehvx6Uz8Aco4r3Y2USSKujKCaRuek2a5zcaKt9n4BN+HoRsKGKC61W2QDyzB+/yYNNv+TLc00YzrLzz1sAg==","shasum":"acb6328d1ae136ef2992313e88675a732e1b00a1","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.54.tgz","fileCount":7,"unpackedSize":76634,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgS1RFCRA9TVsSAnZWagAAMQkP/iupZrEAm7GBN6lDDUaT\n5dzydEeBjboQGvxAj9sVMqJ/6V1C9wChv4bc2BhIC/SCFLv1igLxzrxY3FkV\n8gVL2D2GHeeF6Dmb9jJVhHi6zD3oiYUF6i+xGXridLEYKgbuQka1DS4jcbE4\nuzgMXJquqV22lZMHdpypO0IvMyY7ENtTWzQ7kLy3dYJAyEGyORKYbkp4KNZv\nk37wEP+owXJbU5bYlYr/BGBlJIV7wWD/Be5UNMyTv6eRfJQp4nBsgFep8sio\nfIn8XU7z0VlOM/wtjy0x3iLU2JTj8tYYY6946TvEP3zOzvOXsuBYbpa6u0Hy\nS+b2L+SJRQR1tE0WpAUOO2q0zM4crkVqemgMhG3UuZyMGcB6qCkKsUxNp6pc\n+oI5XD9Di2OhkBtWl5r6im+MEEsAvaDfSIKrntLG3cbj9+zjhoAushsrH0XN\ntmLmEFD7iuPV0bHpSEiBNjHfbEZ4zwmzC3iYRhxSjSfgLmmQX5j/+H1z1wZb\nByAjt+U49ic4+HUVhi7tzKpTQBluOpzWVmUf30O6n0zg9tHreykI4cxz9g8E\nUi3mm28gjz53NUMUbt+pFAiry49i/CdtAoiU4yuvAWI5n69Wvma22ge0WQc+\nxDBMDXmZBS01kAtpNsnNxyf9xO3cotIh9CQ1raGWftxOV7QJunFjZ2auU18M\nnF4k\r\n=OQaD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDtau47/nr5KnvMRDYbli533qZcdSMgPA2u6ygw8NTbEAIhALMJiBppt3losaE+wWo91VwjWQG3dsB/yZuv4VAb/Psx"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.54_1615549509091_0.5688050984276194"},"_hasShrinkwrap":false},"7.0.0-alpha.55":{"name":"destructible","version":"7.0.0-alpha.55","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.20","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.13"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"11d83a49126820101dad7774b967a8ffe3ceb13a","_id":"destructible@7.0.0-alpha.55","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-V2sm1l/b4jk4sW0MGbBmFJXNVY4pMa8+/zM97Et9gFrlvxhKuVlkkagnfIKwP4cnwI11JkokhteXlQI67AjHmA==","shasum":"bc9d339c864dec40744264a7ff7ed928c94ea07f","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.55.tgz","fileCount":7,"unpackedSize":76742,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgTZ7XCRA9TVsSAnZWagAAG40P/3knLSJwGMrPINxaoJJK\nvHyr9zA4yLJT0rlJSpR928wwi1Kz11lpOWVdlOCvykE5xMw5BfbX1/8DCbQc\nDwpF44wwIcNEes2552jFtf4mUzX0yYjCKA8k9g9ejBnsgSbDP7FOW4Cupnas\nzpHZkcQNmlOqrRO1oq9LiJrSNXdzJwMmbf6vBk4v2IQ8OldNIBZxofHswdsr\nuz9my/xNYUVNISC8RsetQdjlMfqozzfQIUMr1z3susuFq40ek3Ewfm5o10Nf\nbE8Y5NtQivg3Mc+ZcD6hFRmwf/KUZJ3DoNsCf99dG/ovjU97JWFtz8DChbat\nK+McJSJ8suJWZfwjhOY7ovgS867a6qjC7gN5xLiRJhwyufi4jKbgoq4tJlJn\nQCdD+Ylf49K5r8ejJ86FYy9pDPWavRVy2STFzxxjL4utWkMPt/OsitZoSRfH\nEv/q+8Ra681p+Nr2vmWYywHx5M5x3WI2F+59xlMGfPeYfFTdcjZO3JEcLVI+\nWm/mB2XGsl+t5zu//ij7Sc3lvDWm5sjdzCQANeIOyxK5tUj6Eq8QNdMdKsa9\nNHCcro+2Y+HpP5Y5R9MJOVrGwH5ZWuf6LvU+yGAF1VjG1DB/AcLobBPT5/2S\nslgPYvaKdw/PlPwoNGF/hS0iyR6qN7VmcxmuCFwTmLgD1Oe+kZ94nfkT+pJI\nRq4a\r\n=ECNB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICuE6VCcEae3qioLWUU/CX0dcwKrpsq27URns3k/wq5TAiEAuVSTOAIjVEYoneeWlr0luMgnVzkR9VNErZqQmSvNxlw="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.55_1615699670483_0.41030051250065225"},"_hasShrinkwrap":false},"7.0.0-alpha.56":{"name":"destructible","version":"7.0.0-alpha.56","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.20","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.13"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"254d8a73dfaaaa4b9a6a8aa2ac605d23cccaab5c","_id":"destructible@7.0.0-alpha.56","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-aPQylsp3U1nF5ZtnPtwjrw8WDHKtYiAhX1umF5secHV0JIzjEYgYIsvlegdq2cS5kwfiPXSg+N0m7tN05W/w/Q==","shasum":"4a27fa4c8d3376870329b90c7f27690b2ac2b283","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.56.tgz","fileCount":7,"unpackedSize":76742,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgTZ8OCRA9TVsSAnZWagAAZ0MP/At89n/UcnTW47ggYhsd\n1nHbOi58vhBrZrXR6HosJYjBp44L81Z1kWPCMLwpLoUKEDjX4OW8AyOq2vSm\ncMpHMoyS5/sCAhRyGf79e4Efpzj8EfJpLxF1REPoCyo5jxzRLJqWIXfAGUqH\nuB/1XeqOED0tFQGrIs3Bu6btgWu6/MqlErozBJMKvat6tfwT72jv9kNQJpqN\niKVyHyjv0Lap2VqGARFbRlODiygtKb7XfQi/0TuM4T2CHZVhpcRMF1evxC9C\nZPLQaguKaP9+zdgarXyZNe4dj5EHOMuycuZi1odXrIJIaerZ2MHqveV+vB9S\nO3GgxBrSIy99daRd9L2N8RnEmzWHV75XlgEH23ZfxZyNfquyBRbUva9xkIvi\n6RKBMy+tfUcjE/NiQ93M2cjZzFW3nfozQL7UKNCO0C3xupzgSsA3VyD75CRH\nF53optypQNqJJTWfpTkY92PwQcj9NHqXtRgG7n7JGdDCBBCMhAtuoiznaYdJ\n5ETuBQKKA8MSDhrd+0m7hwh+01Gs6/0DIHYy5LhkGC5ncSlEVLgCIpEfJZbQ\nmIuzYS3tX6jSS52NIuGEE2uznUDzuF5QwhixsxO5vOqO5UyWeJjE8G02uQiO\ni2VKqHY1xXXFvADJpioUJoPnwqjZNueZBZGON0hGZ7UCxp/RhcAP7LduGNza\nt67+\r\n=LRXH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICWgEoeKI+1YY9qix6lAmjMrrCLkSeHH0XiKchk5lJBMAiEAswRNMdZhgJ4KCJ0D7ipe8RjCHxbbX8KqTUg1mFh3+0I="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.56_1615699725673_0.7804143243955388"},"_hasShrinkwrap":false},"7.0.0-alpha.57":{"name":"destructible","version":"7.0.0-alpha.57","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.20","perhaps":"0.0.6"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.13"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"bea4978f437d953a355f384877cd3ae266345621","_id":"destructible@7.0.0-alpha.57","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-Ln/ifq7oL746xUPu0gxbqt31r2oVIOaMxakC0o301Gh1dyIVdJrD3KVa5VVHQyx1jaADaWn5qid8JM1MjQ9kew==","shasum":"21115a9a20dd6b54a6863405e03d19e368c32b48","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.57.tgz","fileCount":7,"unpackedSize":76750,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgTbwuCRA9TVsSAnZWagAArvQP/0BwBzT1a3fjhSzYq5Pu\ncxENgWy5GNErEx9f80f4Z8Lb/1lJOrfWy1Gjn+4KYJzqwYJt4SrscolZefRr\nWB6c61tS82JyHrOeo92N3NsLu5slkLyo5wyJAXzvrTq7K3Ro9W8yIdSJylV3\nO4Yy03Fj7glv16XfMLFaos4ClTA/WxBcvnIm8s68mATFknhabFzbWm1VhrM+\nFRM0w99VNEIdC08NrEaooorDW59gOiDVh0MU2tjksjmmWsaKObmAlyGIuYuF\nUjaUWGuAZ8HdNqKqH947HL/8MjP4E3tGW7aStIjpaOSRrepWrlTZ1y/bL1Dr\nSX5iVrT7Erfcwvh4PxOTAK+JLa5643NmB/cC0l0HbmhZwiTQEEzzJdve/4Gr\nwo0wiuC62mS1/1ZdZo7gYiXHFTdv0XVlP6czWDrv9SrGuYlKtadf1suKbSXQ\n8/bz7lYr/oz/jtqNlBjW6b9MqjTa7z/lzcLmCad5oS1wrKuV4AFoxXxQnp/T\n2j5FYpvng3nAU7QGwK4PkPvhIbFFN0PiXGLKtUZtz0kvOyroSlGEcbBZwjxG\nE6NVAAH/OO95Dx7BFsYUsTKhGArukwma9LNcUYdMIl9BlrJda9yeicXkbG1l\n/7MAgpDMfMOzyWOrmcVtB3VPhTilr/l+XOzG4QpWraB7Eli1HzgpRMwXvXSt\no3Zu\r\n=ZdoI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC11F5gRwp2WETm7I3nuStt2PIHnNCY3i58SR0hWbPDEAIgATWL8V4OgcX2ty7emjU7lJx+cycRSt8wEv24yskZwLQ="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.57_1615707182100_0.880701254912462"},"_hasShrinkwrap":false},"7.0.0-alpha.58":{"name":"destructible","version":"7.0.0-alpha.58","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.20","perhaps":"0.0.8"},"devDependencies":{"nop":"1.0.0","proof":"^9.0.1","rescue":"7.0.0-alpha.13"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"bb618cf720b48b4b183d4a4f7cca9c1dde325fcc","_id":"destructible@7.0.0-alpha.58","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-IQrne+TN1wGWabgjMJhoHog4rHGQUEdxdculLb1ni33tMqEA7v3F5fqeZj38s76qkz3OQzbca6EWoTYYJsFd2A==","shasum":"c818858978d13ae5c1c545ea2d7356966ed6adc5","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.58.tgz","fileCount":7,"unpackedSize":76691,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgTpNBCRA9TVsSAnZWagAAcPgQAIvsvVXklpArhBDL1k+R\nD0MJLV7kCoaL6oRYDdjLVAKmRmFF1vKKxbzohKbBRRwpnFDdaaG7PX/r10em\n8OtIVeWDTyIQPuUXaGdwBHIfJ5ZgemsXGY87fAw3XnmGL1EMb2xGsABIgYtX\n9gJ6k7IP5ZJtWCMDA2mDFyt13p7QjhnlPfx/pYhstUFAx/Kpl+Ngl4opZTO8\nS7sOtkn4gBxw8O25rMMmPF2MkniDG7LxgzfIze6Lh/t/Y5++Tj6h4oak0dh3\nAUge01KamzMjy/uOujN4PMBcqiM7J0xheH0qUxJ/M+M6TtHW5vi2CPsFE4Fq\nDmO86MjJHYL5X+iDAtniuP4uJTYWTC103e7lkqcSm+xQGY/B88QYg4eRy8lE\nGUJpEHjILbFH/ndtiWekKGmepNW8DBsWkoWhF7+MLhk0u8dnEkD/ArXbKXL6\n5QRQucuKmhLiGqoYUrnY3jJqnoe4TjV8ULWvceB5UOmfhjBvgbnHwZsDYfae\nMJNMjtH3YHZKI04TbqCH/o4ole3AEU+c9thd9pK0HRCQvXpxMH4FTYeiZmgN\nP954Ds3ggaDOpzfpE2HN3JdEKWEMrMSNJRLZNpQkb1XSI43m2lNhmHTfQeqK\nrfSUYbzbTc2Rkw8ZBTceXueHtKkXIOG1bZJJcbUXmDNlobit5r6qAaO6uv9H\nmH4r\r\n=HmnG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCEhR3/GK58L7I8ruPeDmfOT7Dk3hG6UENW4dOT2YHqLwIgUfmdK7pkawzd+XKSMDNK7/zaeKj24kkqPqcTK3utPuM="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.58_1615762240793_0.1861620838561484"},"_hasShrinkwrap":false},"7.0.0-alpha.59":{"name":"destructible","version":"7.0.0-alpha.59","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.20","nop":"1.0.0","perhaps":"0.0.8"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.13"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"06a4b88df3f152462e3d7ef15a737709feffb941","_id":"destructible@7.0.0-alpha.59","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-sUeVFi62mr7IQf64JI+FNsE4epEkja7NuUG+0kbfqxmqKSKkc5+s0Hp/YUDuAYKwh4uC8umyPAdnctGEZkmkkQ==","shasum":"d9863d7411ed3bded633b6014cb8e6cbbbd47e0d","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.59.tgz","fileCount":7,"unpackedSize":76691,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgTpP6CRA9TVsSAnZWagAARM4P/2pK8lB0tLExA2Kej5vv\nmlRDpkYWr6sIBD7dijWAB74m+9+z1CmeHM5DXP7rEyKwfTSJoORcutmylaoD\nYde0HB/GCokMw4iNRRKajw6SguPFeJwCWADY8JkWfCVS9nTy7qBXTKvFPiJC\nQTIZZHpbpjPSy6tF63TX39LCc3EyirOour3WI+5HhGDnWEGXpHZ4sSGKZ+BO\neWsULUEWGlm4eN2uL7DFVfdwmxMHGhedTTfsYN6rX9gZsOhvTtUSQlWNSzGh\ni3KsK3gk40teki5EWv/BaibDoOU5BDGTaQ0mITyJyCXk71wbcwpvLAZMGAqJ\ntfXc1NZjLVb89rd4aEIosQCJGCWfG/YemO39JQNf76IFeNs1H3AR9mQcf0ST\n//GUqrk/cYGuGOU/WSypA5ebCDZ+eE91xGH/vLK0OA/O9hhwW0kVttGcRCyh\nAVWhkaN/wBRs8euQbOl/NRK8rv4MWh7qOy+RR+0iUAwDgme4QaQILXGc2s+P\n2LsYFnWXs7uDfGFF/yzFQTh2eMETcheqU/GPVNbs7EqrMFgZ17u6oGYKjwCd\nWkRxL+WJjTVGyUN0dMaicFoTiOj6NQTPHN1GFUfBvgSMJNv8sU8aBxDbw8+E\nL2x52/nX9U/AJftPvKAkSnaYQh/reGCuZgCjhU1FgexT8h1LcgdyRkBgANJe\n/ibM\r\n=XvqW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBJral68YIg7vZOkrjAwHYCnMW51tiaDSAIeOp5TmY46AiEArk1Un8FdeZZu/XeXmn0csbFuZkefvQgcTr8QW26Pp6Q="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.59_1615762425865_0.3920678311285053"},"_hasShrinkwrap":false},"7.0.0-alpha.60":{"name":"destructible","version":"7.0.0-alpha.60","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.20","nop":"1.0.0","perhaps":"0.0.9"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.13"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"678603c458b8f6aaa71d64e8bb36e9eb60f9e9f1","_id":"destructible@7.0.0-alpha.60","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-VJLCLs27wvMYe5jj4wtHa71t/WaNu/b1RUvrPMR6B/iaayRjOKz6lytuu2J4tsMsNwa1JJLnaMd5RU5fReyhXw==","shasum":"49ca07d092018f7d874172fda5fbbee55fd6a839","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.60.tgz","fileCount":7,"unpackedSize":76691,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgTpVuCRA9TVsSAnZWagAAjZ0P/RRXNNtaPVN62suHq4hB\n928pKqhom6z2XbXTKWIlwi2+9swx7gFmd33VtizPvCv8VHeh9mLF4jwDocgF\neO1ZoGCdoJxiR1052Tsbq+flFA55jMfAw/JF16B/u09mwNwxMQn7I8nX/Y/s\nHRvbdXCAp/3MEANB+b4zqXAG42G18SMTo/CoI0cHQNRYYV97Egt9hW0P0Jqf\nWBFMLTGCOAZBF8EF19e2ztu0Z8keW+CVQF5KHE1k44BK8e+NCmbTDM5OCT/5\nj2/weGenhrOgxmu7lFkUFOtAQJXMgWpaTFjRZ5N7tLM57TsReG1ODLzb+13Y\n3sFPDtL5OyrZGkS57Y/DqH9azy6rMDZjk93b6f0rqVo4OU4IzkxuQIR22CDZ\nEHcjBgRFvApEJG9Jha5PsASlzgoiDCxEYJ/MYUuxzOR/UoCun6GBmoJ9GIZt\nVUlZHfs6Gtr2zVn0Dkm/ON3hjiLDgaF7zHz3sfiOrUACfKlTvx5ErPJoEDlf\n6MuHtscivrhY6hzeCVlZxjedxbjYKcWgyo3m9WUv+QE0ePI9odQKWapf0dBb\nLMfoMpPNyPbvG35YfEfI+97VBu+njSPTdt/LBIjIhefbeZd2siqxTtROAyoJ\n5deLWhHDcDhvxnP7yyl1CssbWC7rh0gFdfu2dErcyrV+g858wbb8wSvQeSu8\n3zay\r\n=4e2u\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD8vosFdsrp77N/AKhQnNjfgDYh5rUtu0i6Bjlg0VNObgIhAJg9hv8QPpI7Y+z8sxypul5oQ5mILDhaOALPBoMBRVwK"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.60_1615762797863_0.42193680164165226"},"_hasShrinkwrap":false},"7.0.0-alpha.61":{"name":"destructible","version":"7.0.0-alpha.61","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.20","nop":"1.0.0","perhaps":"0.0.9"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.13"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"1db630dc3b37a27947a8b5b1ee9e1fdd25d1714d","_id":"destructible@7.0.0-alpha.61","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-WC3o6N+DE5kxmF0u+DDnG2fyrnqJc4rzxgXcVJJ5L1cDXM+f4ST6JctSmAlapnDZI+15qKLUWKrQg79t5rg2+w==","shasum":"70e34f7f9dd13d949f79773c49adfb9b2538ce2b","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.61.tgz","fileCount":7,"unpackedSize":73956,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgTpgYCRA9TVsSAnZWagAAWPwQAIr+tpOj8rMxWsNlIv1F\nvyRhHIfwhYrTskg/uqCu+n9zhZRPyF24/wAJTDLD+vNIDfVJr08zuD+psUkf\nLRxpNmacu8I8+/8+S+7tD8A/efINLQlvDeLAb68gwN1GUC+D0cY4c7wKDGoU\n3v2d3+IwM5PQe6dO9VUhuC6SDEjawD/WvkwVY140D6TzPsVTixKFMWBFPLAC\nLbJxu8llptNK2grgM94IveKAYq/pYLoc//NE2GuMtKw/AimPTE5hrz/UiMdk\nBLulFrp+Tv98Gb6krHgXaJOMp3oSgAw2f780juQzv7p2dgzBjCRsQtOhx/Ol\nvzDg5SylzGta0ybu4ECdSKzvk1bnI+qBQaGhz1PCbzZqR+jejY41znZe3IYF\n3bSps8nr37F1PE2wY7+aUKpxvapgc0AUMPkR5wd7VwUD0bQXqY7TGFNd3xy+\nhoeRROo+wv1ak93sxJN9vo/chnlOnJ1HzYnHoL2qP19c/Iy9NOpqdj62Iip4\nDtvPGvO1srtD0Sm/wl3OOmGeG0QBLBicZ1BS7h2edIzT1LpRG3qmUvEobSx8\nzLT2xY8X1dKLrwzxdPoDMZMUeyWTcbeuVLbz031O4m3WZFskCHX1CfOwjWNL\nW5uD+GU3aOklpMOY5+3NyxPcBOhgSZ3ELUNMg/ONMT7t9zXdPvlesWv1LZsg\nSzYz\r\n=5Skk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD5jKoWl9uM/ijxtg393EJllEDD08dFamxlHJw5kSWffwIgOAOQJuY2jS/hpA4cnPrFk18GtHivCtl21+Wbf4BMwko="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.61_1615763480024_0.3227344698088763"},"_hasShrinkwrap":false},"7.0.0-alpha.62":{"name":"destructible","version":"7.0.0-alpha.62","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.20","nop":"1.0.0","perhaps":"0.0.9"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.13"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"d109a0374735fe149dba4b9ac4994dc10f91dc70","_id":"destructible@7.0.0-alpha.62","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-a8+XBXeO3+KNMd4hA+c1GnU111xTCXiik/Uvh7kjZ8+QxIUNuWbHqjQUTwPibKE0wb83cW8cEry5Z3DlViPwUA==","shasum":"7f653ad26f9fc2d3141155185d26e5d14a0a66c0","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.62.tgz","fileCount":7,"unpackedSize":70121,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgTqBqCRA9TVsSAnZWagAAWL8P/Ru9bqBCkw7rZqEmTjxk\n9BZJhSG8vT5n+D+E/hy1l8EyjfZj58JW1EqbVo510wicl6SebYXNZw3AcBI1\nXQ2nFLnEKQH0uWhTnVlxAXeY96/d5SFONgsEKf9ue1ohrBGam8ECFxEhdHfI\n8fyE4Gt0pv6odPP/IM7S0ISbX90ANG3IiPShGgBtk5pkkcK9YZeax2HC20CM\nVkZt386NehDgxqKHym5nQlD+cGbpdG4aIBRMTYE5jfcS/5RSfsXPqSdxNTt3\nNZ8BMJ4LV+zdfsT05af/pLhp1csMo6OnKYliZIqdtu/RqPZw5PE7/S2J5AMh\np2Q6XKTH4RYz4rh8Ai+z0OBOfG0M8+HlZzQpa8BpRFmypyj3JNDdNQD/p3Bs\n1cuzs0gCH6hLoJmkbmPqnxDf0sqw0Z90aNSEDjHdWrbntvmFP4u3V0gyxhJP\ns6ArBkU03AdqsS1AD1KDlHBI4ATbjiJfs9OHdQblYnbx1QqCeVc/+KOoCN5f\nG7cYKGkNOdoGPmJ+gsu2XvmYSM5aeYwIQxGofgmXOVmrDRuZOVJoO3jOhdrA\nVsJU8D69Kygt024s0sZLo3HtL3hClwXyhaoj+gyu/9yWVR1etefe3rCCbZDd\nGqo+B3fgwTZR3pvDx0q5sO95PHXjvv9hH+PqAVR3ACNgBTZRWOlo0EKHgHJf\nWlG5\r\n=IA/8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDzduVWU5DhXlRb9kwqJqiG8Dc5YpkLApFauuoF6tWP/QIgYm+jU4j108rYo9WkOxiTzM5vgJzTmEbmVcpicOcuWy8="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.62_1615765610471_0.9049406038925825"},"_hasShrinkwrap":false},"7.0.0-alpha.63":{"name":"destructible","version":"7.0.0-alpha.63","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.20","nop":"1.0.0","perhaps":"0.0.9"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.14"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"712ab8f50d185a065b592b1b1f48b6e8f719acca","_id":"destructible@7.0.0-alpha.63","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-ZPBitUFR6u++ePYKVPAcTB8HlxT4YOoINzpN5IgmWp801i0+L+2KGYvmRYPxYT51I1dPERQbCDrX8luuKLajZQ==","shasum":"cecc6e2d446c2d2252e2984c7e72823355486213","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.63.tgz","fileCount":7,"unpackedSize":70121,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgWVu1CRA9TVsSAnZWagAA6yEP/09QzpfroYCHjJC1wK78\nyCv3w4kUq1UcDK5AoCpmSrvjWanxprnxRpY9swr84KTmiyAQxtZFcVNq9JE1\nU0sttkND/V1k7xwaHp84SNeJLSmThGsa5w4EQ3sLQRnbmCn1YudmJkdBEC5m\nYRop9yyFFaZXh7XEg9+gUGpvHNCSM+ebfQAH8k0Ep0gTp0HHkyUfgkg6rXQT\n01ZvKb7+1lXepCzZPdrr8lK0YQyD4R/zK52TwPxJrCJiJq7ToMI58fuOr2oO\nY/C46/NrmU5Aa6wNf1ZL72+UIRZGmNvQNZyDFOaliaymUI+x6ErHLZVItOje\nLPH7ahcU13kjs+dV7m7UOVYBJ/dKbPXW09d6u28vLkuTGMZ4ZSZ8rPeBq/U0\nN2iN0FWU5GKCuyN9vzAHC2z6YViRg/OnS6mX9P3ty8WxLo+Zj1Mhe0ZODVSh\nf2ojyzKiRvNfwZveucvYgiyLu/vNf8aVejULao34Peaf/8gHz2NFiaM2nRAG\nnKBcgjaqYNauGF33ERnxO4xEbxuaoEzD+/31mp1ZrXrfHXOPZHFazGwbAp+J\n18j7K4kbNRCdd6V0VA41UwIsLdxVFvz3UPEKbGmpy+oWk/VAn0iFDjksvft/\n4FmiEz3EIlZTmtXKGANJnEindFXJ9OfMOcx9H/ENHImdIJbxB3W1RXQX0uWF\nvlyn\r\n=koTc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHagnd0/iCtlojDjtyRPqKFNNGEReRa1zVBhJhakhRAwAiEAhLcBVVXkARwOSg4IeEcg7s2JDfP4zrsWuyxP5i6r2V0="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.63_1616468917095_0.1275607616311134"},"_hasShrinkwrap":false},"7.0.0-alpha.64":{"name":"destructible","version":"7.0.0-alpha.64","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.20","nop":"1.0.0","perhaps":"0.0.10"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.14"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"c98dd39dd621a5c3f85d9348a0b12244a3ac634c","_id":"destructible@7.0.0-alpha.64","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-o40Z0d/ySINikw0t4DZeMJJcpHVIrKV5VH7RDrLEjijRq5e0aihUZW071yi/WwRILZVtzYlQ2cQtPtcTfU0wow==","shasum":"943797713b39daaab6c56ca46edbefd9b47b2b66","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.64.tgz","fileCount":7,"unpackedSize":70126,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgX1fUCRA9TVsSAnZWagAAbw0P/RKaDSheJvCR/rTzYSl6\nC8mBxPps6DslqKwGT+2r+GNiZX69elpl5u49g75umcpxF3P72+I1/STa6prp\niaZjUfJ0wxk3IwlAK6BhfSyu0/aAVGL80LASe5wv2k7dcWTEQnEkniz179t7\nKIBUMseiGJxBCH9clfupmjt7WNTG4WiR7QBiTLKYcKpPZXPkGyxCGMb7FhcH\n11c9G/UqA/QYs9y2sSWkiauOk1YR98k7bw2OKxZxW9f6yg5fDVGSIEKmG2us\noX4D9xBV5mlvgqq1OLR//23050QBZswovJwxcvV0YWDQlptfr7hD71tE6piG\nP+akn4qyEmJP1QOYOP+2O34pYj/AdmtqKqpeQwjZRNz15R4CfOQAKt90TnJ7\noSRDwUW4DvftrQM48+QLLh4FjYqxAfxbsJO5uCFvVwDIA3U94fRV3k7mDhVx\nNlyXP8N/ejstUuQY/jbGugy1J+ryLhain0HIFX0EzqeZwtjdY9km1Hn2k1Ph\n909xr7b6A5SMLUmE0xYJn/UkTvsGEQVMvZ+XBotTe8Tu0H+3ubp3r3RBDvWu\ncbcJzF6cudNEaHdRh3BF0ClrDufQ68CKM6A+BXxjetrRszrsV5Dj9aFUxDws\n3dpLshhW6mRK7rqS0bEwwEW8gsaXkD04R8wNrvhlUrMzaCKYp5ZtdDyDr+kn\n1RE+\r\n=W8Zj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAb7+XIxwRNDpLsdABPoWGEeutKvco8oKpFB9fdPEOa7AiB8MFFDjCcT22CzdzF+FeUuP0kd1WbMLMdB2w6lh1OHJw=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.64_1616861139461_0.1802212304221411"},"_hasShrinkwrap":false},"7.0.0-alpha.65":{"name":"destructible","version":"7.0.0-alpha.65","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.0","interrupt":"11.0.0-alpha.20","nop":"1.0.0","perhaps":"0.0.10"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.14"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"21a4e07ed5af51e63bdf945ccb1c8a5d23d87b4b","_id":"destructible@7.0.0-alpha.65","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-wgAzE/iO3BK1siWvEIeBjuwHIdkbG+Jhl1ccjES1aS9Ae9XN+nsXCFIX5C70sTsxgoFg5ked/bT6HO4hgb8tJw==","shasum":"d691aaff57f2f7d1a59e45ce6c513bac145479fb","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.65.tgz","fileCount":7,"unpackedSize":70120,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgmrDECRA9TVsSAnZWagAASp8P/RVGSmimHSVq5I9xTSro\nxcwMxNxbd4sUAiwM4priTWDqqc8v51hDCdw7xdsDH0wDDpRcHWIiz8phrMCd\nxFeP+pChoDRw8deV2Tu+hJfdksrrh+8/qzGM1H5jWnONf1AbJrE3VW02wYqu\n7htGS0jaiU9TiR2gCknu3S0FZShJ2Ge0GFqK1JrUsDSk80zkpBO8gbiae9w0\n6A46yq4f9WQh3M7LvzYTz6k/I4pMigLTmv7piSGnWnWhQImwaQqQxM4DROfY\nWDN8zg1d8BfLibHUihj41apSf3tVfYv88i7r2jV3UD/fOhSmQJH7HCTGdmLo\nJNG9EKI2ULRVNTv7srTx9wq8k/Ujc9XDwwVMhRokD9/f4gttNk+bsUBDl+dj\n6WNqXvQ/NJUOBkcaRyV59wI36SQzvvwhlx3VvKhXY7a+jbgeQULXgSj83qoq\nh221cGKUqe23sEf2mWjHbyz17jmsv8Be/YHpCMGUXU0d7WlVgxbNHCZ2MCXU\nCR4RgLV+d/5rRdpk5ptCTJSU4+eb/rXHqkfJQHEiRoZRjLRawVgnbP6dsxVl\nxPuZm7xyzpi/e0RPWU/vWnOH5MQACKAnjJgEVc5LgO5pJU+uZFUhRaDRmsAZ\nE3Gw264E8wMQ/R4JRUTU707+tOvgH3oeVYh3U3LEwiFbna53xFFgG2PgRjTL\nHyf4\r\n=G0oW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBCgu33/QImrqwhFUoNVuLcsBqQPn/XAWszs11cIw3YzAiEA4GAl7gYzcXvr1+u0FaAItqIPc31LZHYZLEhBVyVIBcA="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.65_1620750532112_0.45149112044264283"},"_hasShrinkwrap":false},"7.0.0-alpha.66":{"name":"destructible","version":"7.0.0-alpha.66","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.1","interrupt":"11.0.0-alpha.21","nop":"1.0.0","perhaps":"0.0.11"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.15"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"516720eaca12fdb37b025a5371d0e081cf32e9a9","_id":"destructible@7.0.0-alpha.66","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-QtCtM5wsgRFo423qYXpHUxH1OgxUDOPN8AO9CbRzzyR0ykyrv7Voo/RshbIrMvjabsjlQ4jfFIq4ekNsEiCDCw==","shasum":"012616b434c13242dad089fd4711d4fb2becd650","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.66.tgz","fileCount":7,"unpackedSize":70120,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg+dLcCRA9TVsSAnZWagAA+6QP/26Fxl7vX2uUOqhwU/Qq\nbjYKNNfIntAZHzaYhMvH1AMl9otbb31FDhJYiEXvN0+oTjSP9qI7wSMac3wH\nOmVY3i+CbnLjzo8AUm1Dd6LgXo9Z4F678fIdvl80P/sODT/vXW/7YtusKaW+\nL6Ci/eWqe3pqDBkjFKsqJpNyZJLXyKcwJG+8UGMTtiUx3zPbSdVPpl6rxLLw\nYpej2QEhzNUu6UnhVtPoycHae11ikXNgO8ttEQ+mmkWjUt9zX7eHR7JwTTBP\nKPzuVwK8frwnNKA1YwXSbsbpdOXisg4jNCiBtHmjqIgSPmzarYwFxoWmM651\nMYENw856ZE/b2iEccthpvVWXk8MjJO7rABXQogLtwo7nUvjqi3lnkusXY5rP\nt3O+D/WbSPZjux4Z/Ve/E5UYeoHjcPHtWzLcahGNIXCS4l5BFV9E17sCDUdg\nIXSnVvWXPYIGNx8KXcXY+lGdhHye1MfqMyG2Oxm8IdXZ2MWvEmEYi/1+barT\nrC+Qk+IX8t3s8v8s+laSZDCjvTj/ZNhBhRNUJme/a147nrwD4/wZ0QQiKPRn\nZT0JEKLLzoJqa4k9nousTFgkpt7AbzM0YJxVHQvXuAwkpQWx8SNgkpcLIdV1\nRL8Y//uonBEvvVSdjKelN5LaFU6srtsQDczCmzq016Tnpumi3u77rNOCR3Rc\nWy2r\r\n=cjKT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDmz2yJ6GOSl+zXvRZHYRqYv7jkqH77EQ/unPwlQZGgnwIgEWYI6Os6t3NrBTQvJ3jM6o+bzdIR+FfVQJJsm4pcLWs="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.66_1626985180424_0.8551310991196435"},"_hasShrinkwrap":false},"7.0.0-alpha.67":{"name":"destructible","version":"7.0.0-alpha.67","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.2","interrupt":"11.0.0-alpha.23","nop":"1.0.0","perhaps":"0.0.11"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.16"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"a103df6d4f4d01b74705115b1c856f8c3e880539","_id":"destructible@7.0.0-alpha.67","_nodeVersion":"16.5.0","_npmVersion":"7.19.1","dist":{"integrity":"sha512-JQCxr5uHwsldkSMtdmcyMAhOTM2TVtNNaaJ4jaz3jlZsqXwflEDjPfwNjqB/PVoE1O+UXGQoj2tlhZUBIVFnwg==","shasum":"02ee0ce45a2de611c2fc232db5809158c6413f36","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.67.tgz","fileCount":7,"unpackedSize":70120,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg+lMICRA9TVsSAnZWagAA3NYQAIaOP4WbKo0XGqJXqn0c\n9QJHHMqgYtHMy3oSFnTZAWtB9FTBL60ZyyG3PvfJmwVVWmDsdn3f1uQT0OVx\nsgm+5ngKpdW/WTF/jybLuZuPL+iRwID/J6J5+cvwpPfNPjOn7909GXdyuk5/\ntBwKtf/+dWzTKvAJ21OaVmIlYuC3XpGPSbMaXqMiHPB8pSefHfY/LFsWCyku\nF3gODWUZ/8Pfryx323j3Z6aVL0T9376zQ0ZIuXzRsde6JhcpdCdnWrkrcj0u\nX/RlTvUidxd/1bQphasOC31WQxIsNao3+eMHODBtau4PmYE9D4dQKTSIex6o\nRrlzl8vsKxvafmS+5gttXe5ePzUuTJiajgQwwtujVGN4gjYt06lWYbgIyzPZ\nFwGxWHmJq4u4ad8eHhPwJ3UbJN5NpmgGvWcpD+vXfmyKJW80ZgieV/0xh/T3\nXrIQ//eTWe3WfWdpZ6MQKzvoJAn9NFiAUfVCFgC0E/xAp8M2qy8c76LFeZvK\ndk8xeR73eStnLN9ZFFaXPAaSTgY5CVGJsZmfyMWzKm6JB5HaFHQPYKBYxcWs\nIR8XCLHE6A7m5NpWCByTwY6KbicQCEIZiVz4nxbGeXdPu6b015BV3nhInaeQ\nWeNYLg6Pe9YjXP0yVBkoFIwrtBa3K+55wH+LRnRq0puanvus63LPdUOBSWfZ\n2+bc\r\n=783l\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCoOo+cNi8OAMSZh7YjCDXuVNe4tz3VWGfP7veLajq4kgIgL8R8Zm5rz1DwsM+neWcdKUKawRecS7ehJEUSUMW0dME="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.67_1627017992808_0.27572600330371433"},"_hasShrinkwrap":false},"7.0.0-alpha.68":{"name":"destructible","version":"7.0.0-alpha.68","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.3","interrupt":"11.0.0-alpha.24","nop":"1.0.0","perhaps":"0.0.11"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.17"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"d8e09eb6dcdf0cd81471b76565ef6a624ffa3590","_id":"destructible@7.0.0-alpha.68","_nodeVersion":"16.4.2","_npmVersion":"7.18.1","dist":{"integrity":"sha512-mtud953rJGlozpem38V43xicsM6PhftYcpInIB04B38CgOOmdBtBRhPVEORJS4ulIluXAGJn2E06pU0b+3QJWA==","shasum":"926256fcae63a7cc73f18759861bfa0527a192e6","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.68.tgz","fileCount":7,"unpackedSize":70120,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhCQzXCRA9TVsSAnZWagAAyVMP/jjSZMidE4doFBrypyPX\n+v7hiCjilr2St4M4cRt5gBHgPkt1jANQj8fCOLtGklPzKB4T2MmZSreacmvc\nigogV5+bF9FVH+0l2MZJfAI0w1kfV/sH5fdWKNUV0q3wvRE9yxnNMCvnVK8Z\nmlW7AjpRrHL8Z/1lJvlqET48WRNXREB9/PDrytViJ/vb1B3GbQev1yThyZRo\nwHqfYbGkiIPhTFV/SKd2C/bH0yq9NyUYNBIZDMVBG88bcE7VmUYunMiPsmuB\nBS1CVSo2Fdmkcqc8uisJeGLdPOtKtIlEYhEd4hucj2kVJnqMalbqw+KQRGJM\nLj1OgB4Ws/Keeew43Z5vOVEGtDTlYg/3yhfAPO79gkZfmRg+VpCo/FqDeQbC\n8IBsXpvPGbiZUfsyO5kWMwZP/xj0JwlFyoHjD1xOV2GyzxCttWPEY81o8mne\nPfLPe771fDdGNw2tXCgDvzpOd8A2y7CleMW+ob+rMmTZYDTYkRbTozrQ6w2X\nlG0XoFofmrziUeXhFJgxbSp1ym2TpmyW2VEN/PbHH5QFUqyJmN1Su1YWwsVX\nWWyl2kgkAI1yElmJi9Frkq8xXvxbrpgyvGVblGv9zuTWNC8Kg2EWgXTdJiZ3\nIMqZIKP03VzqNo56CDPWzsyAwULm0IqCxLJMQ0porLK7vvuNvwoYgesCQunX\nuEaH\r\n=nsC6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEA76Co3wdVB8FJoYoO3oqiv87kRFs3rymb07j5SylPrAiBT/REftkBXCSTDkSxHXxJYc4cCCXFEt/wv+m4tmCGzFQ=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.68_1627983062997_0.9687542304801227"},"_hasShrinkwrap":false},"7.0.0-alpha.69":{"name":"destructible","version":"7.0.0-alpha.69","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.4","interrupt":"11.0.0-alpha.25","nop":"1.0.0","perhaps":"0.0.11"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.18"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"9352b1e0f5e505572a6a74c8149c2e3770202436","_id":"destructible@7.0.0-alpha.69","_nodeVersion":"16.4.2","_npmVersion":"7.18.1","dist":{"integrity":"sha512-WL3V9M+iACF9oOHob1n9J+UCdIg9L/1tmxAMM9nwJhNHLyA4L5zyO8pz8rxKuOSNtTzPhMUvX6e/5IWpwVT8DQ==","shasum":"616241415704ebb200166961758c27420b0ccdad","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.69.tgz","fileCount":7,"unpackedSize":70126,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBsYKUBx9l/+UXU7Z43OPRlwys+mKrzweleD8t4atcxFAiBfhtNvIPNwB/fEmA7XgCGA7NrqUBOl78Au+1KudMVsYA=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.69_1632107560684_0.7625377016835169"},"_hasShrinkwrap":false},"7.0.0-alpha.70":{"name":"destructible","version":"7.0.0-alpha.70","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.4","interrupt":"11.0.0-alpha.25","nop":"1.0.0","perhaps":"0.0.12"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.18"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\n\n```\n//{ \"mode\": \"text\" }\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\n\nThis `README.md` is also a unit test using the Proof unit test framework. We'll\nuse the Proof `okay` function to assert out statements in the readme. A Proof\nunit test generally looks like this.\n\n```javascript\n//{ \"code\": { \"tests\": 18 }, \"text\": { \"tests\": 4  } }\nrequire('proof')(%(tests)d, async okay => {\n    //{ \"include\": \"testRequire\" }\n    //{ \"include\": \"test\" }\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself.\n\n```text\n//{ \"mode\": \"text\" }\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nmake\nnode test/readme.t.js\n```\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\n//{ \"name\": \"displayedRequire\", \"mode\": \"text\" }\nconst Destructible = require('destructible')\n```\n\n```javascript\n//{ \"name\": \"testRequire\", \"mode\": \"code\" }\nconst Destructible = require('..')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main()\n}\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n\n    async function main () {\n        console.log('file size', (await fs.stat(__filename)).size)\n    }\n\n    main().catch(error => console.log(error.message))\n}\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const fs = require('fs').promises\n    const path = require('path')\n\n    class Queue {\n        constructor () {\n            this._promise = new Promise(resolve => this._notify = resolve)\n            this._queue = []\n        }\n\n        push (value) {\n            this._queue.push(value)\n            this._notify()\n        }\n\n        async shift (value) {\n            for (;;) {\n                if (this._queue.length == 0) {\n                    await this._promise\n                    this._promise = new Promise(resolve => this._notify = resolve)\n                    continue\n                }\n                return this._queue.shift()\n            }\n        }\n    }\n\n    async function list (queue, directory, root = true) {\n        const dir = await fs.readdir(directory)\n        for (const file of await fs.readdir(directory)) {\n            const filename = path.join(directory, file)\n            const stat = await fs.stat(filename)\n            if (stat.isDirectory()) {\n                await list(queue, filename, false)\n            } else {\n                queue.push(stat)\n            }\n        }\n        if (root) {\n            queue.push(null)\n        }\n    }\n\n    async function sum (queue) {\n        let sum = 0\n        for (;;) {\n            const stat = await queue.shift()\n            if (stat == null) {\n                break\n            }\n            sum += stat.size\n        }\n        return sum\n    }\n\n    const queue = new Queue\n\n    list(queue, __dirname)\n    sum(queue).then(sum => console.log('sum', sum))\n}\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\n//{ \"name\": \"test\" }\n{\n    const destructible = new Destructible('example')\n\n    const work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\n    let sum = 0\n    destructible.ephemeral('loop', async () => {\n        while (work.length != 0) {\n            sum += await work.shift()\n        }\n    })\n\n    await destructible.destroy().promise\n\n    okay(sum, 10, 'basic destructible')\n}\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const child = destructible.durable('child')\n    const sibling = destructible.durable('sibling')\n\n    child.durable('errored', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(child.errored, 'child errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(destructible.errored, 'parent errored')\n        okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n    }\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    outside.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(!group.errored, 'group errored')\n        okay(!group.sibling, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('top')\n\n    const outside = destructible.durable('outside')\n    const group = destructible.durable({ isolated: true }, 'group')\n    const sibling = group.durable('sibling')\n    group.durable('errored', async () => { throw new Error('error') })\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(destructible.errored, 'root errored')\n        okay(sibling.errored, 'sibling errored')\n        okay(outside.errored, 'outside errored')\n    }\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const test = []\n\n    const drain = function () {\n        let capture\n        return {\n            promise: new Promise(resolve => capture = { resolve }),\n            ...capture\n        }\n    } ()\n\n    const producer = destructible.durable('producer')\n    producer.destruct(() => test.push(`producer errored: ${producer.errored}`))\n    producer.panic(() => test.push('producer panicked'))\n\n    const consumer = destructible.ephemeral('consumer')\n    consumer.destruct(() => {\n        test.push(`consumer errored: ${consumer.errored}`)\n        consumer.ephemeral('shutdown', async () => {\n            await drain.promise\n        })\n    })\n    consumer.panic(() => {\n        test.push('consumer panicked')\n        drain.resolve()\n    })\n    consumer.destroy()\n\n    producer.durable('rejected', async () => {\n        throw new Error('reject')\n        drain.resolve()\n    })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(test, [\n            'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n        ], 'panic')\n    }\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\n//{ \"name\": \"test\", \"unblock\": true }\n{\n    const destructible = new Destructible('destructible')\n\n    const panic = []\n\n    const child = destructible.durable('child')\n    child.panic(() => panic.push('child panicked'))\n\n    const sibling = destructible.ephemeral('sibling')\n    sibling.panic(() => panic.push('sibling panicked'))\n    sibling.destroy()\n\n    await sibling.promise\n\n    child.durable('rejected', async () => { throw new Error('reject') })\n\n    try {\n        await destructible.promise\n    } catch (error) {\n        okay(panic, [ 'child panicked' ], 'no panic')\n    }\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.in.md","gitHead":"c0558c8b3d5437f078a17238d437697900a15654","_id":"destructible@7.0.0-alpha.70","_nodeVersion":"16.4.2","_npmVersion":"7.18.1","dist":{"integrity":"sha512-oEF/i2/kGqu58eksxxdNq99xUDPqIinyxxYIZVbOwePpL/f//MyVpsdpyUVNE6dcnCS4IwaSbrAIX5r1VNe7eg==","shasum":"81ae0d25e261f0a06f292d0e92d9479ff10085f9","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.70.tgz","fileCount":7,"unpackedSize":70126,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIERFlOC0TWzu3NLNkCOrzyQhPTLVN7e/LH+0wvPw44C4AiEA6sEeFSi0Ktr48uJ61CxW7zD5/RnBbTJRusXJO8yb3wE="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.70_1632163932867_0.3917996426279926"},"_hasShrinkwrap":false},"7.0.0-alpha.71":{"name":"destructible","version":"7.0.0-alpha.71","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.4","interrupt":"11.0.0-alpha.25","nop":"1.0.0","perhaps":"0.0.12"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.18"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\nDestructible installs from NPM.\n\n```text\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\nAt the very most it is a framework for structured concurrency.\n\n## Living `README.md`\n\nThis `README.md` is also a unit test using the\n[Proof](https://github.com/bigeasy/proof) unit test framework. We'll use the\nProof `okay` function to assert out statements in the readme. A Proof unit test\ngenerally looks like this.\n\n```javascript\nrequire('proof')(4, async okay => {\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself to see the output from the various\ncode sections of the readme.\n\n```text\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nnode test/readme.t.js\n```\n\n## Overview\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\nconst Destructible = require('destructible')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\nconst fs = require('fs').promises\n\nasync function main () {\n    console.log('file size', (await fs.stat(__filename)).size)\n}\n\nmain()\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\nconst fs = require('fs').promises\n\nasync function main () {\n    console.log('file size', (await fs.stat(__filename)).size)\n}\n\nmain().catch(error => console.log(error.message))\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\nconst fs = require('fs').promises\nconst path = require('path')\n\nclass Queue {\n    constructor () {\n        this._promise = new Promise(resolve => this._notify = resolve)\n        this._queue = []\n    }\n\n    push (value) {\n        this._queue.push(value)\n        this._notify()\n    }\n\n    async shift (value) {\n        for (;;) {\n            if (this._queue.length == 0) {\n                await this._promise\n                this._promise = new Promise(resolve => this._notify = resolve)\n                continue\n            }\n            return this._queue.shift()\n        }\n    }\n}\n\nasync function list (queue, directory, root = true) {\n    const dir = await fs.readdir(directory)\n    for (const file of await fs.readdir(directory)) {\n        const filename = path.join(directory, file)\n        const stat = await fs.stat(filename)\n        if (stat.isDirectory()) {\n            await list(queue, filename, false)\n        } else {\n            queue.push(stat)\n        }\n    }\n    if (root) {\n        queue.push(null)\n    }\n}\n\nasync function sum (queue) {\n    let sum = 0\n    for (;;) {\n        const stat = await queue.shift()\n        if (stat == null) {\n            break\n        }\n        sum += stat.size\n    }\n    return sum\n}\n\nconst queue = new Queue\n\nlist(queue, __dirname)\nsum(queue).then(sum => console.log('sum', sum))\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\nconst destructible = new Destructible('example')\n\nconst work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\nlet sum = 0\ndestructible.ephemeral('loop', async () => {\n    while (work.length != 0) {\n        sum += await work.shift()\n    }\n})\n\nawait destructible.destroy().promise\n\nokay(sum, 10, 'basic destructible')\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\nconst destructible = new Destructible('destructible')\n\nconst child = destructible.durable('child')\nconst sibling = destructible.durable('sibling')\n\nchild.durable('errored', async () => { throw new Error('reject') })\n\ntry {\n    await destructible.promise\n} catch (error) {\n    okay(child.errored, 'child errored')\n    okay(sibling.errored, 'sibling errored')\n    okay(destructible.errored, 'parent errored')\n    okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\nconst destructible = new Destructible('top')\n\nconst outside = destructible.durable('outside')\nconst group = destructible.durable({ isolated: true }, 'group')\nconst sibling = group.durable('sibling')\noutside.durable('errored', async () => { throw new Error('error') })\ntry {\n    await destructible.promise\n} catch (error) {\n    okay(destructible.errored, 'root errored')\n    okay(!group.errored, 'group errored')\n    okay(!group.sibling, 'sibling errored')\n    okay(outside.errored, 'outside errored')\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\nconst destructible = new Destructible('top')\n\nconst outside = destructible.durable('outside')\nconst group = destructible.durable({ isolated: true }, 'group')\nconst sibling = group.durable('sibling')\ngroup.durable('errored', async () => { throw new Error('error') })\ntry {\n    await destructible.promise\n} catch (error) {\n    okay(destructible.errored, 'root errored')\n    okay(sibling.errored, 'sibling errored')\n    okay(outside.errored, 'outside errored')\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\nconst destructible = new Destructible('destructible')\n\nconst test = []\n\nconst drain = function () {\n    let capture\n    return {\n        promise: new Promise(resolve => capture = { resolve }),\n        ...capture\n    }\n} ()\n\nconst producer = destructible.durable('producer')\nproducer.destruct(() => test.push(`producer errored: ${producer.errored}`))\nproducer.panic(() => test.push('producer panicked'))\n\nconst consumer = destructible.ephemeral('consumer')\nconsumer.destruct(() => {\n    test.push(`consumer errored: ${consumer.errored}`)\n    consumer.ephemeral('shutdown', async () => {\n        await drain.promise\n    })\n})\nconsumer.panic(() => {\n    test.push('consumer panicked')\n    drain.resolve()\n})\nconsumer.destroy()\n\nproducer.durable('rejected', async () => {\n    throw new Error('reject')\n    drain.resolve()\n})\n\ntry {\n    await destructible.promise\n} catch (error) {\n    okay(test, [\n        'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n    ], 'panic')\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\nconst destructible = new Destructible('destructible')\n\nconst panic = []\n\nconst child = destructible.durable('child')\nchild.panic(() => panic.push('child panicked'))\n\nconst sibling = destructible.ephemeral('sibling')\nsibling.panic(() => panic.push('sibling panicked'))\nsibling.destroy()\n\nawait sibling.promise\n\nchild.durable('rejected', async () => { throw new Error('reject') })\n\ntry {\n    await destructible.promise\n} catch (error) {\n    okay(panic, [ 'child panicked' ], 'no panic')\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.md","gitHead":"091cab5e230e251673e909a3836ff1a9be38d5ac","_id":"destructible@7.0.0-alpha.71","_nodeVersion":"16.4.2","_npmVersion":"7.18.1","dist":{"integrity":"sha512-IqJzNhsXRbTtng1Wo20XaeXCAyVsWmprmHROLp33HObSfR6WCXdmb1PaZbRiS7BVYmATmvbHLInxLQx0ouJzBw==","shasum":"4e8642cdf92f17d485d8442abeb03238423cbd42","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.71.tgz","fileCount":7,"unpackedSize":55572,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDTUJmjNGwxzTZ+xKeYD/4tejzqYqGR7h3e99uUlRzawQIgAyKHl5oqGmsmPr6UJ9oxHIzdqo6VO2zOqSa0MtnwuwQ="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.71_1634192831556_0.49258405709360953"},"_hasShrinkwrap":false},"7.0.0-alpha.72":{"name":"destructible","version":"7.0.0-alpha.72","description":"Controlled demolition of complex objects.","keywords":["async","promises","cancellation"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"homepage":"http://bigeasy.github.com/destructible","bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"dependencies":{"extant":"2.0.0-alpha.5","interrupt":"11.0.0-alpha.26","nop":"1.0.0","perhaps":"0.0.13"},"devDependencies":{"proof":"^9.0.1","rescue":"7.0.0-alpha.19"},"main":"destructible","scripts":{"test":"proof test/*.t.js"},"readme":"# Destructible\n\n[![Actions Status](https://github.com/bigeasy/destructible/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/destructible/actions)\n[![codecov](https://codecov.io/gh/bigeasy/destructible/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/destructible)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nControlled demoltion of `async`/`await` applications.\n\n| What          | Where                                             |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/destructible/issues/1  |\n| Documentation | https://bigeasy.github.io/destructible            |\n| Source        | https://github.com/bigeasy/destructible           |\n| Issues        | https://github.com/bigeasy/destructible/issues    |\n| CI            | https://travis-ci.org/bigeasy/destructible        |\n| Coverage:     | https://codecov.io/gh/bigeasy/destructible        |\n| License:      | MIT                                               |\n\nDestructible installs from NPM.\n\n```text\nnpm install destructible\n```\n\nDestructible manages the concurrent asynchronous code paths in your application.\nAt the very least, it provides the functionality of `Promise.allSettled()` but\nwith dependencies, error handling and reporting, and cancellation.\n\nAt the very most it is a framework for structured concurrency.\n\n## Living `README.md`\n\nThis `README.md` is also a unit test using the\n[Proof](https://github.com/bigeasy/proof) unit test framework. We'll use the\nProof `okay` function to assert out statements in the readme. A Proof unit test\ngenerally looks like this.\n\n```javascript\nrequire('proof')(4, async okay => {\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself to see the output from the various\ncode sections of the readme.\n\n```text\ngit clone git@github.com:bigeasy/destructible.git\ncd destructible\nnpm install --no-package-lock --no-save\nnode test/readme.t.js\n```\n\n## Overview\n\nThe `'destructible'` module exports a single `Destructible` object.\n\n```javascript\nconst Destructible = require('destructible')\n```\n\nDestructible is a utility for managing the construction and destruction of\nconcurrent paths of execution implicit in `async`/`await` style JavaScript\nprograms.\n\n`async`/`await` lets you wait for results from other threads in your program\nmessages from your operating system. It also allows you to jump from one code\npath to another other within your program. When we're jumping around from one\ncode path to another within our program we're doing co-operative multi-tasking.\n\nAs you're well aware, if you have an endless synchronous loop in your JavaScript\nprogram, your JavaScript interpreter will not pause the loop to let another part\nof your program run. That's because your JavaScript code runs in a single\nthread. When you return from an `async` function or `yield` from a generator\nyou're allowing the path of execution in your program that was `await`ing that\nfunction or generator to resume its path of execution.\n\nIn other co-operative multi-tasking platforms these co-operative paths of\nexecution are called [fibers](https://stackoverflow.com/a/796255). Threads use\npre-emptive scheduling, whereas fibers use co-operative scheduling.\n\nIn Destructible we call these co-operative paths of execution strands. We do\nthis so as not to confuse the reader who reads some part of our documentation,\ngoes off to Google, and comes back with questions about green threads,\ncoroutines or the many other fiber related concepts that are not directly\napplicable to Destructible.\n\nA **strand** is defined by the `async`/`await` call stack created when you call\nan `async` function without using `await` to get the result before proceeding.\n\nHere is a minimal JavaScript program that will create a single strand in its\nlifetime.\n\n```javascript\nconst fs = require('fs').promises\n\nasync function main () {\n    console.log('file size', (await fs.stat(__filename)).size)\n}\n\nmain()\n```\n\nWhen Node.js runs our program, it creates a wrapper function around the entirety\nof our program. This is not a strand according to the Destructible definition\nbecause it is not an `async` function.\n\nBecause it is not an `async` function we cannot `await main()` because you can\nonly use `await` within an `async` function. Therefore, when we call `main()` we\ncreate a strand.\n\nIf `main` where to raise an exception we would then get an\n`'unhandledRejection'` error in Node.js. We can handle the rejection ourselves\nusing `Promise.catch()` but that does not change the number of strands in the\nprogram according to the Destructible definition of strand.\n\n```javascript\nconst fs = require('fs').promises\n\nasync function main () {\n    console.log('file size', (await fs.stat(__filename)).size)\n}\n\nmain().catch(error => console.log(error.message))\n```\n\nWe will no longer have an `'unhandledRejection'` exception because we handle it\nourselves.\n\nHere is a program that creates two strands that co-operate to solve a problem,\nthat problem being converting a base 10 number to another base.\n\n```javascript\nconst fs = require('fs').promises\nconst path = require('path')\n\nclass Queue {\n    constructor () {\n        this._promise = new Promise(resolve => this._notify = resolve)\n        this._queue = []\n    }\n\n    push (value) {\n        this._queue.push(value)\n        this._notify()\n    }\n\n    async shift (value) {\n        for (;;) {\n            if (this._queue.length == 0) {\n                await this._promise\n                this._promise = new Promise(resolve => this._notify = resolve)\n                continue\n            }\n            return this._queue.shift()\n        }\n    }\n}\n\nasync function list (queue, directory, root = true) {\n    const dir = await fs.readdir(directory)\n    for (const file of await fs.readdir(directory)) {\n        const filename = path.join(directory, file)\n        const stat = await fs.stat(filename)\n        if (stat.isDirectory()) {\n            await list(queue, filename, false)\n        } else {\n            queue.push(stat)\n        }\n    }\n    if (root) {\n        queue.push(null)\n    }\n}\n\nasync function sum (queue) {\n    let sum = 0\n    for (;;) {\n        const stat = await queue.shift()\n        if (stat == null) {\n            break\n        }\n        sum += stat.size\n    }\n    return sum\n}\n\nconst queue = new Queue\n\nlist(queue, __dirname)\nsum(queue).then(sum => console.log('sum', sum))\n```\n\n**TODO** Left off here. Probably need to stress that this example program is in\nfact a toy, would easily implemented as a single strand with a generator.\n\nBasic destructible usage.\n\n```javascript\nconst destructible = new Destructible('example')\n\nconst work = [ 1, 2, 3, 4 ].map(work => Promise.resolve(work))\n\nlet sum = 0\ndestructible.ephemeral('loop', async () => {\n    while (work.length != 0) {\n        sum += await work.shift()\n    }\n})\n\nawait destructible.destroy().promise\n\nokay(sum, 10, 'basic destructible')\n```\n\n## Destructing With Errors\n\nDestructible does not provide any sort of error recovery mechanism, it assumes\nthat you will perform any error recovery in your appliction strands using\n`try`/`catch` or what-have-you. If a strand rejects, the Destructible will be\ndestroyed and destruction will begin.\n\nThere is however an error notification mechanism so that a service can detect\nthe failure of other services so that it doesn't attempt to perform an orderly\nshutdown when the services it depends upon are in an unstable state.\n\nIf you have an embedded database service and it fails to write because the disk\nis full, it should probably not attempt to perform its orderly database shutdown\nprocedure. It would be better to perform a recovery procedure after the system\nadministrator makes some space on disk and restarts the program.\n\nYou can determine if a Destructible exited with an error using the `errored`\nproperty. This is a synchronous property that will return `false` until the\nDestructible destructs, then it will return return `true` if the Destruction was\ndue to an error.\n\nThis property exists on all the Destructibles in the destructible tree. If any\nfail then all destructibles will have their errored property set, so the\n`errored` property is really a property of the destructible tree, not of any\nindividual destructible itself.\n\n```javascript\nconst destructible = new Destructible('destructible')\n\nconst child = destructible.durable('child')\nconst sibling = destructible.durable('sibling')\n\nchild.durable('errored', async () => { throw new Error('reject') })\n\ntry {\n    await destructible.promise\n} catch (error) {\n    okay(child.errored, 'child errored')\n    okay(sibling.errored, 'sibling errored')\n    okay(destructible.errored, 'parent errored')\n    okay(child.errored && sibling.errored && destructible.errored, 'everyone errored')\n}\n```\n\nAn error in one service is not always an error in every service. Using our\ndatabase service example, an error in the database service means that all other\nservices should stop work since their work cannot be saved. But an error in a\nservice that depends on the database service shouldn't stop the database service\nfrom saving the writes it has queued and shutting down in an orderly fashion.\n\nWe can isolate errors in sub-trees of the destructible tree using the `isolated`\nproperty when we create a sub-destructible. When an error occurs outside of the\nisolated sub-tree, the destructibles in the isolated sub-tree will not have\ntheir `errored` property set.\n\n```javascript\nconst destructible = new Destructible('top')\n\nconst outside = destructible.durable('outside')\nconst group = destructible.durable({ isolated: true }, 'group')\nconst sibling = group.durable('sibling')\noutside.durable('errored', async () => { throw new Error('error') })\ntry {\n    await destructible.promise\n} catch (error) {\n    okay(destructible.errored, 'root errored')\n    okay(!group.errored, 'group errored')\n    okay(!group.sibling, 'sibling errored')\n    okay(outside.errored, 'outside errored')\n}\n```\n\nWhen an error occurs inside of the isolated sub-tree, the destructibles outside\nthe isolated sub-tree _will_ have their `errored` property set.\n\n```javascript\nconst destructible = new Destructible('top')\n\nconst outside = destructible.durable('outside')\nconst group = destructible.durable({ isolated: true }, 'group')\nconst sibling = group.durable('sibling')\ngroup.durable('errored', async () => { throw new Error('error') })\ntry {\n    await destructible.promise\n} catch (error) {\n    okay(destructible.errored, 'root errored')\n    okay(sibling.errored, 'sibling errored')\n    okay(outside.errored, 'outside errored')\n}\n```\n\nError can occur after destruction.\n\nAt destruction a service might wait for another service to drain but will skip\nthe drain if the destructible tree is `errored` because the drain might never\ncome. If the destructible tree enters an `errored` state after destruction, this\nservice has already begin waiting. It needs a way to be notified so it can\ncancel its wait on drain.\n\nFor this notification we can register a panic handler using `panic()`. The panic\nhandler must be synchronous. It can launch new ephemerals, but I doubt that's a\ngood idea. If I do so myself I'll come back and talk about the use case.\n\nThe panic handler is supposed in indicate that an error occurred _after_\nshutdown, not before. The `panic()` handler will only be called after\n`destruct()` and only if the the destructible was not already `errored` when it\nwas destructed.\n\nIn this example the shutdown of a consumer is expecting an a producer to signal\nit is done by releasing a `drain` latch. Before the producer can release the\nlatch, however, it raises an exception. The consumer registered a panic handler\nthat will release the latch itself so that the consumer shutdown will complete.\n\n```javascript\nconst destructible = new Destructible('destructible')\n\nconst test = []\n\nconst drain = function () {\n    let capture\n    return {\n        promise: new Promise(resolve => capture = { resolve }),\n        ...capture\n    }\n} ()\n\nconst producer = destructible.durable('producer')\nproducer.destruct(() => test.push(`producer errored: ${producer.errored}`))\nproducer.panic(() => test.push('producer panicked'))\n\nconst consumer = destructible.ephemeral('consumer')\nconsumer.destruct(() => {\n    test.push(`consumer errored: ${consumer.errored}`)\n    consumer.ephemeral('shutdown', async () => {\n        await drain.promise\n    })\n})\nconsumer.panic(() => {\n    test.push('consumer panicked')\n    drain.resolve()\n})\nconsumer.destroy()\n\nproducer.durable('rejected', async () => {\n    throw new Error('reject')\n    drain.resolve()\n})\n\ntry {\n    await destructible.promise\n} catch (error) {\n    okay(test, [\n        'consumer errored: false', 'consumer panicked', 'producer errored: true', 'producer panicked'\n    ], 'panic')\n}\n```\n\nPanic handlers will not run if the destructible resolves or scrams. **TODO** No\nlonger true. Updated test. Did not update README.\n\nIn this example we wait for the sibling to shutdown completely before the child\nraises an exception. Because the sibling shutdown completely, it's panic handler\nis not called.\n\n```javascript\nconst destructible = new Destructible('destructible')\n\nconst panic = []\n\nconst child = destructible.durable('child')\nchild.panic(() => panic.push('child panicked'))\n\nconst sibling = destructible.ephemeral('sibling')\nsibling.panic(() => panic.push('sibling panicked'))\nsibling.destroy()\n\nawait sibling.promise\n\nchild.durable('rejected', async () => { throw new Error('reject') })\n\ntry {\n    await destructible.promise\n} catch (error) {\n    okay(panic, [ 'child panicked' ], 'no panic')\n}\n```\n\nAfter destruction service might be waiting for another service to drain but that\ndrain notification might never arrive be\n\nYou can use the errored property to determine if an operation should be\nperformed or skipped during. If you have a work queue, once errored you\nmay decide to skip the work in the queue and let the queue empty quickly.\nYou may have shutdown ephemerals strands that you won't perform on error\nexit.\n\nIn our database example, we might write some state information to disk\nso that the next time the program runs it can resume quickly. If the\ndatabase is in a bad state we probably don't want to write the state\ninformation because we can't trust it.\n\n**TODO** Code exmaple.\n\nAt times we might want to isolate the error property in our tree, so that\na particular sub-tree will not be marked as errored if the error occured\nin a branch outside the sub-tree.\n\nIn our database example, we might have an error originating outside the\nstrands that compose the database. The database itself is in a fine state\nand can perform an orderly shutdown, so it may as well attempt to do so.\n\n**TODO** Code exmaple.\n\nIf we've isolated a sub-tree, there may be times when a service in that\nsub-tree is doing work in an unknown strand. Our database may do its\nwrites in a work queue that is managed by a queue service. If the\ndatabase write fails and it throws an exception, it will get caught by\nthe queue service strand and shut it down with an error, but we need to\nkeep the queue running so other services besides the database can clean\nup. We'd rather have the destructible associated with database service\nreport the exception instead of the destructible associated with the\nqueue service.\n","readmeFilename":"README.md","gitHead":"d07919b983b4e0abbd2bfbbc678ab22801fc91b4","_id":"destructible@7.0.0-alpha.72","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-Go7KZBmLzsuyLCE99onN3d4agT4bGb375JLXWxkTj5fyvvSC+UgmJgUaOoZqfY7DeRdZSSmE58NuvKwS3kR+9w==","shasum":"96d8ea87c55993521be1b27fb191cd77ed75ba0c","tarball":"https://registry.npmjs.org/destructible/-/destructible-7.0.0-alpha.72.tgz","fileCount":7,"unpackedSize":55572,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJiAMNtCRA9TVsSAnZWagAApYgP/jRZqT6vQeonLZbDq18r\niBXFtKYcinlgTAb0S9uNed9i8MlyIR1beoVbHumfRUYFQ68RkWqCX/BY+jJr\nDyhvAaH/+6Ys3WM7rhe9cbZVY/l2nlwEbQ9jsHmci+rjBp3Jul83HjXVdHJ3\nWfZhS1eBeZepdSf/7H3PByxD/HycpYcCJYVlpzEA4oludbrjKMxO+JMfGl4c\n9T092X+SYPiOLB7gZGHce9bHAndhrKs6ldjx5xRWG2vYWwLc0yTMxKtpR7uC\nVlQ6EUfn8gvQhIobuRodFnfIjA+33zm+Q9UOY/mQCBvPaa5fFI/q7KKVXhh7\nc5TZEmQWSQ/v41eBrpH1B9asBDqlQpIt+wIb78vtmV+uCLZ5pudCSIKk9V+N\nfQ681aHncox9lBMlVAyDOGW79iuzrsIbx/dpwZHD1nH6YNxzSD5uZJOaDv3A\nBk3OeSw9Tm6eEFZs9PLyYvBhlqgV8BCewnnR/oHB4/ANGmrm3krYARbSrD+9\nWN8lCIcKAjyyGc5cEt3KMVe8V14AyOVlB6V9GcWY+XpMpjvRIAM9j4YeHjgK\nL5TVmuaqDJJ0BLVg8nuK1s101L5UGzUs1gXur0EkM/99ufAnKhXwECNNEKTT\nJQ3YvtwnCDQpM2ZI9Y2V6pmah4QOIoAlbmDcmUQ2KrW3OCG6MF+ceh6EEOe1\nBhxR\r\n=EgJN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFYPXNPIbl8wTAmuY65YXD296uUegStTtL50YD6D1FPgAiAr0jtT/AOtsIXB4Io3L2p0sQ3Bci7uoj2P7hY5sAnKUg=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/destructible_7.0.0-alpha.72_1644217197415_0.782859116961331"},"_hasShrinkwrap":false}},"readme":"","maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"time":{"modified":"2022-06-15T01:50:11.032Z","created":"2017-02-11T13:51:51.406Z","0.0.0":"2017-02-11T13:51:51.406Z","0.0.1":"2017-02-14T22:32:36.469Z","0.0.2":"2017-02-15T08:57:34.659Z","0.1.0":"2017-02-16T11:18:08.176Z","0.1.1":"2017-02-16T21:14:10.801Z","0.1.2":"2017-02-17T13:51:13.819Z","0.1.3":"2017-03-14T15:33:11.511Z","0.1.4":"2017-03-15T16:24:32.488Z","0.1.5":"2017-03-22T15:05:55.223Z","0.1.6":"2017-03-30T20:25:51.724Z","0.1.7":"2017-04-06T16:22:49.469Z","0.1.8":"2017-04-07T07:42:10.858Z","0.2.0":"2017-04-10T04:06:14.417Z","0.2.1":"2017-04-10T04:35:41.517Z","0.2.2":"2017-04-10T06:24:14.445Z","0.2.3":"2017-04-10T17:30:20.779Z","0.2.4":"2017-04-11T16:53:54.806Z","0.3.0":"2017-04-11T16:54:26.013Z","0.3.1":"2017-04-11T17:10:57.206Z","0.4.0":"2017-04-11T17:50:56.768Z","0.5.0":"2017-04-12T08:59:20.036Z","0.6.0":"2017-04-12T16:42:45.586Z","0.7.0":"2017-04-13T06:13:36.763Z","0.8.0":"2017-04-13T07:00:14.942Z","0.9.0":"2017-04-21T13:17:41.564Z","0.9.1":"2017-04-21T13:22:12.798Z","0.9.2":"2017-04-21T15:53:40.352Z","0.9.3":"2017-04-23T04:06:57.954Z","0.9.4":"2017-04-23T17:24:42.314Z","0.10.0":"2017-05-19T19:24:43.885Z","0.10.1":"2017-05-20T02:46:52.793Z","0.10.2":"2017-05-21T03:36:09.819Z","0.10.3":"2017-05-22T02:14:35.350Z","0.10.4":"2017-05-22T13:56:08.139Z","0.11.0":"2017-05-30T04:07:56.609Z","0.12.0":"2017-06-01T06:02:19.543Z","0.12.1":"2017-06-02T13:53:17.824Z","0.13.0":"2017-06-19T17:16:03.324Z","0.13.1":"2017-07-02T03:11:16.441Z","0.13.2":"2017-07-07T16:29:29.387Z","0.13.3":"2017-07-07T21:06:29.825Z","0.13.4":"2017-07-14T03:54:29.854Z","0.14.0":"2017-07-14T17:13:15.801Z","0.14.1":"2017-08-03T18:54:14.930Z","0.14.2":"2017-08-04T02:05:29.276Z","0.14.3":"2017-09-07T17:38:12.871Z","0.14.4":"2017-09-18T15:51:16.164Z","0.15.0":"2017-09-20T04:21:46.715Z","0.15.1":"2017-09-20T05:24:59.911Z","0.15.2":"2017-09-20T08:50:56.784Z","0.16.0":"2017-09-21T09:50:23.700Z","0.17.0":"2017-10-01T17:32:18.199Z","0.17.1":"2017-11-23T03:50:14.845Z","0.17.2":"2017-11-27T02:30:43.312Z","0.17.3":"2018-01-16T13:54:24.032Z","0.18.0":"2018-01-26T07:24:21.013Z","0.18.1":"2018-01-28T05:54:45.356Z","0.18.2":"2018-01-30T08:12:50.522Z","0.18.3":"2018-02-01T14:08:48.795Z","0.19.0":"2018-02-06T10:55:15.935Z","0.19.1":"2018-02-07T06:22:33.132Z","0.20.0":"2018-02-16T19:57:23.147Z","0.21.0":"2018-02-16T22:15:53.381Z","0.21.1":"2018-02-17T09:45:38.903Z","0.21.2":"2018-02-17T10:59:16.356Z","0.22.0":"2018-02-27T14:43:12.272Z","0.22.1":"2018-03-01T15:29:49.778Z","0.23.0":"2018-03-01T15:32:21.220Z","0.24.0":"2018-03-02T00:44:36.023Z","0.25.0":"2018-03-06T18:28:12.297Z","0.26.0":"2018-03-07T15:00:26.254Z","0.27.0":"2018-03-13T06:38:47.860Z","0.28.0":"2018-04-19T06:53:14.918Z","0.29.0":"2018-05-30T18:59:58.912Z","0.30.0":"2018-05-30T19:02:30.019Z","0.30.1":"2018-06-05T20:51:21.774Z","0.30.2":"2018-06-11T06:34:24.898Z","0.30.3":"2018-06-19T18:52:56.540Z","0.30.4":"2018-06-28T01:48:23.464Z","0.30.5":"2018-07-26T05:24:04.011Z","0.31.0":"2018-07-27T05:58:56.277Z","0.32.0":"2018-07-27T07:32:40.698Z","0.33.0":"2018-08-12T08:01:41.475Z","0.33.1":"2018-08-13T07:05:13.357Z","0.34.0":"2018-10-28T16:16:29.273Z","0.35.0":"2018-10-30T18:13:20.761Z","0.35.1":"2018-11-13T00:14:23.481Z","0.36.0":"2018-11-19T10:45:59.739Z","0.36.1":"2018-11-20T11:50:01.142Z","0.37.0":"2018-11-26T00:20:22.414Z","0.37.1":"2018-11-26T15:40:19.860Z","0.37.2":"2018-11-26T16:34:59.732Z","0.38.0":"2018-11-28T10:09:04.335Z","0.39.0":"2018-11-28T10:26:13.708Z","0.39.1":"2018-11-28T10:36:42.025Z","0.40.0":"2018-11-28T10:59:33.358Z","0.41.0":"2018-11-29T05:55:10.257Z","0.41.1":"2018-11-29T12:13:46.142Z","0.41.2":"2018-11-29T12:27:37.046Z","0.42.0":"2018-12-19T22:31:31.819Z","0.43.0":"2018-12-20T08:48:49.376Z","0.43.1":"2019-01-25T07:17:11.056Z","1.0.0":"2019-02-28T11:59:29.964Z","1.0.1":"2019-04-01T14:47:22.370Z","1.0.2":"2019-04-01T14:57:39.247Z","1.0.3":"2019-04-01T17:52:11.018Z","1.0.4":"2019-04-01T23:03:09.247Z","2.0.0":"2019-04-02T06:17:03.732Z","2.0.1":"2019-04-17T00:36:30.078Z","2.0.2":"2019-05-12T05:02:20.473Z","4.0.0":"2019-05-19T05:01:42.949Z","4.0.1":"2019-06-30T05:49:39.200Z","4.0.2":"2019-07-14T05:40:58.447Z","4.0.3":"2019-07-16T00:14:39.896Z","4.0.4":"2019-07-16T08:37:30.363Z","4.0.5":"2019-07-21T17:10:05.286Z","4.0.6":"2019-08-21T03:38:18.473Z","4.0.7":"2019-08-23T01:23:11.098Z","4.0.8":"2019-08-23T07:55:46.507Z","4.0.9":"2019-08-23T16:22:48.464Z","4.0.10":"2019-08-30T03:58:23.734Z","5.0.0-alpha.0":"2019-09-10T08:07:35.672Z","5.1.0-alpha.0":"2019-09-15T06:15:35.580Z","5.1.0-alpha.1":"2019-09-15T09:36:51.333Z","5.1.0-alpha.2":"2019-09-15T10:09:10.621Z","5.1.0-alpha.3":"2019-10-05T11:27:39.876Z","5.2.0-alpha.0":"2019-10-06T06:13:20.076Z","5.2.0-alpha.1":"2019-10-06T09:27:31.815Z","5.2.0-alpha.2":"2019-10-12T02:27:14.201Z","5.2.0-alpha.3":"2019-10-17T11:54:37.823Z","5.2.0-alpha.4":"2019-10-22T09:38:42.186Z","5.2.0-alpha.5":"2020-01-26T08:12:54.144Z","5.2.0-alpha.6":"2020-03-23T18:00:54.954Z","6.0.0":"2020-05-05T00:55:02.736Z","6.1.0":"2020-05-07T09:55:33.817Z","6.2.0":"2020-05-09T09:13:25.944Z","6.2.1":"2020-05-11T17:49:01.051Z","6.2.2":"2020-08-15T16:09:33.754Z","6.2.3":"2020-08-15T16:12:15.429Z","6.2.4":"2020-08-15T16:17:43.753Z","6.2.5":"2020-08-28T12:12:37.432Z","7.0.0-alpha.0":"2020-09-04T05:36:13.744Z","7.0.0-alpha.1":"2020-09-04T07:08:05.522Z","7.0.0-alpha.2":"2020-09-04T07:10:35.893Z","7.0.0-alpha.3":"2020-09-05T17:23:46.029Z","7.0.0-alpha.4":"2020-09-05T17:33:36.591Z","7.0.0-alpha.5":"2020-09-06T00:12:57.096Z","7.0.0-alpha.6":"2020-09-06T08:21:52.283Z","7.0.0-alpha.7":"2020-09-07T12:42:58.284Z","7.0.0-alpha.8":"2020-09-07T17:25:24.624Z","7.0.0-alpha.9":"2020-09-13T08:54:46.095Z","7.0.0-alpha.10":"2020-09-27T08:19:03.709Z","7.0.0-alpha.11":"2020-09-27T21:56:04.914Z","7.0.0-alpha.12":"2020-10-15T12:36:36.539Z","7.0.0-alpha.13":"2020-10-20T04:03:54.950Z","7.0.0-alpha.14":"2020-10-20T08:13:49.168Z","7.0.0-alpha.15":"2020-12-09T10:21:43.027Z","7.0.0-alpha.16":"2020-12-14T20:35:33.677Z","7.0.0-alpha.17":"2020-12-20T17:52:41.622Z","7.0.0-alpha.18":"2020-12-20T17:57:31.323Z","7.0.0-alpha.19":"2020-12-21T04:43:44.755Z","7.0.0-alpha.20":"2020-12-22T19:16:11.690Z","7.0.0-alpha.21":"2020-12-22T20:14:35.372Z","7.0.0-alpha.22":"2020-12-22T23:54:23.446Z","7.0.0-alpha.23":"2020-12-24T03:22:37.574Z","7.0.0-alpha.24":"2020-12-24T04:54:27.604Z","7.0.0-alpha.25":"2020-12-24T05:24:18.912Z","7.0.0-alpha.26":"2020-12-25T03:32:19.799Z","7.0.0-alpha.27":"2020-12-26T03:18:02.467Z","7.0.0-alpha.28":"2020-12-30T19:40:52.777Z","7.0.0-alpha.29":"2020-12-30T19:43:40.138Z","7.0.0-alpha.30":"2021-01-02T05:32:59.332Z","7.0.0-alpha.31":"2021-01-04T09:26:18.560Z","7.0.0-alpha.32":"2021-01-05T09:10:58.593Z","7.0.0-alpha.33":"2021-01-08T17:36:57.883Z","7.0.0-alpha.34":"2021-01-10T16:59:44.406Z","7.0.0-alpha.35":"2021-01-10T17:52:18.073Z","7.0.0-alpha.36":"2021-01-10T18:49:35.794Z","7.0.0-alpha.37":"2021-01-11T09:41:58.098Z","7.0.0-alpha.38":"2021-01-11T12:21:25.671Z","7.0.0-alpha.39":"2021-01-14T04:36:44.752Z","7.0.0-alpha.40":"2021-01-18T16:16:09.422Z","7.0.0-alpha.41":"2021-01-18T16:21:55.984Z","7.0.0-alpha.42":"2021-01-18T17:00:33.115Z","7.0.0-alpha.43":"2021-01-19T00:19:16.081Z","7.0.0-alpha.44":"2021-01-19T14:22:21.177Z","7.0.0-alpha.45":"2021-01-19T14:30:05.535Z","7.0.0-alpha.46":"2021-01-21T14:53:08.981Z","7.0.0-alpha.47":"2021-01-25T16:46:26.584Z","7.0.0-alpha.48":"2021-02-01T17:25:09.136Z","7.0.0-alpha.49":"2021-03-03T02:02:28.800Z","7.0.0-alpha.50":"2021-03-03T17:25:37.117Z","7.0.0-alpha.51":"2021-03-12T02:23:09.805Z","7.0.0-alpha.52":"2021-03-12T02:37:31.794Z","7.0.0-alpha.53":"2021-03-12T06:09:10.357Z","7.0.0-alpha.54":"2021-03-12T11:45:09.321Z","7.0.0-alpha.55":"2021-03-14T05:27:50.622Z","7.0.0-alpha.56":"2021-03-14T05:28:45.865Z","7.0.0-alpha.57":"2021-03-14T07:33:02.254Z","7.0.0-alpha.58":"2021-03-14T22:50:40.974Z","7.0.0-alpha.59":"2021-03-14T22:53:46.003Z","7.0.0-alpha.60":"2021-03-14T22:59:58.182Z","7.0.0-alpha.61":"2021-03-14T23:11:20.217Z","7.0.0-alpha.62":"2021-03-14T23:46:50.668Z","7.0.0-alpha.63":"2021-03-23T03:08:37.252Z","7.0.0-alpha.64":"2021-03-27T16:05:39.597Z","7.0.0-alpha.65":"2021-05-11T16:28:52.329Z","7.0.0-alpha.66":"2021-07-22T20:19:40.575Z","7.0.0-alpha.67":"2021-07-23T05:26:32.961Z","7.0.0-alpha.68":"2021-08-03T09:31:03.188Z","7.0.0-alpha.69":"2021-09-20T03:12:40.869Z","7.0.0-alpha.70":"2021-09-20T18:52:13.014Z","7.0.0-alpha.71":"2021-10-14T06:27:11.710Z","7.0.0-alpha.72":"2022-02-07T06:59:57.585Z"},"homepage":"http://bigeasy.github.com/destructible","keywords":["async","promises","cancellation"],"repository":{"url":"git+https://github.com/bigeasy/destructible.git","type":"git"},"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"bugs":{"url":"http://bigeasy.github.com/destructible/issues"},"license":"MIT","readmeFilename":""}