{"_id":"state-switch","_rev":"93-df53f6fa41d91d4c4a25a82600aef471","name":"state-switch","description":"State Switch is a Change Monitor/Guarder for Async Actions.","dist-tags":{"latest":"1.6.3","next":"1.7.1"},"versions":{"0.1.3":{"name":"state-switch","version":"0.1.3","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"bc5ead6fa0bbc8dabaa0b3e571b3f36a2974f7d9","_id":"state-switch@0.1.3","_shasum":"be1d296726ca438268cddc894872ec79d0167c3c","_from":".","_npmVersion":"4.2.0","_nodeVersion":"7.9.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"be1d296726ca438268cddc894872ec79d0167c3c","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.3.tgz","integrity":"sha512-Wx4rprMSkviw+i/rDixdhzejrfd2EGVN377ymzZOJpIhHNBTFfqj2cSGe8veCbnI/cbkVvNo1vmz1XW+0/P2Lw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCoFFIL5UB4xKuB5aSVNeMjjgiyC2AuoMRDBhBSVJPuHgIgYUcSM++u/1EPbWu8pWtwZfCAgBEW90TCslC6H7pH1yE="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/state-switch-0.1.3.tgz_1493735130883_0.17609341884963214"},"directories":{}},"0.1.4":{"name":"state-switch","version":"0.1.4","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"e52562feefbbff9322301d432f6b6eceb6afb360","_id":"state-switch@0.1.4","_shasum":"30591f9bd063b390dbaf4978062a741fa1fb1d43","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.2","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"30591f9bd063b390dbaf4978062a741fa1fb1d43","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.4.tgz","integrity":"sha512-a8evMFz7hrGmNP5WBESgyK6Ya3nmzloJV7ETyx78FiBdtc5K0fgQ8jRN8G+NEfUP48FuSWaE99wDb1bVixVztw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC826Iw6Tiy/4Abrk07vjBOPHSoWKvj/risKj1rwYDNaAIgGLPmdXh4xH4AhjJwXRq92w0JpE3/MhTU85QV6dfRxJQ="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/state-switch-0.1.4.tgz_1493735530941_0.7326578730717301"},"directories":{}},"0.1.5":{"name":"state-switch","version":"0.1.5","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"cc868266316313b401114a1a123371a57fe71bfb","_id":"state-switch@0.1.5","_shasum":"736fc9b0c627fbb0c7f92a29b7f8e1731ead48ce","_from":".","_npmVersion":"4.2.0","_nodeVersion":"7.9.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"736fc9b0c627fbb0c7f92a29b7f8e1731ead48ce","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.5.tgz","integrity":"sha512-t+6AG4b8JivGjTx42PIjoTiJ3zDgPiObmiR+7/NrwHIHbEj1s1NlHPV4V3WAgk/rAbFts9B9Tin1Ij0m8FZANg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD0HyH1v48ctTCCClsTS7hAddjAsSf7eRbtn/iFuah2cwIgP8/VqZc1ouLxrfzZBQjWe7M6lI7xgZcYN9BAYLxqw5A="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/state-switch-0.1.5.tgz_1493736138639_0.6954566752538085"},"directories":{}},"0.1.6":{"name":"state-switch","version":"0.1.6","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"614dddf23ff36f0378f668db04f578c08ca03a31","_id":"state-switch@0.1.6","_shasum":"bc4b473ddbe681875f0b7195c27c379b8d931d5c","_from":".","_npmVersion":"4.2.0","_nodeVersion":"7.9.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"bc4b473ddbe681875f0b7195c27c379b8d931d5c","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.6.tgz","integrity":"sha512-SDD7+3pptSits9rnX6eRSPSxnZccLslV52Kme7NhaMkL//Ra4HoSSVZZWHqdyDIIU36KXr2NPqNolkYA8v00Yg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCjJM2PlgBT3Z4OfddWLjt+TrQGQccsXv3lqFkP7xKAQgIhANYYNxYz3az83eZQ1GelNhd0q3QAswIlSUGd2d+31Va1"}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/state-switch-0.1.6.tgz_1493736186651_0.07051519094966352"},"directories":{}},"0.1.7":{"name":"state-switch","version":"0.1.7","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"3bd74e91a66d95de45602a2c28ca53f826a3b084","_id":"state-switch@0.1.7","_shasum":"913e7e7afce0eab82069bbb5600a668ca69d270f","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.2","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"913e7e7afce0eab82069bbb5600a668ca69d270f","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.7.tgz","integrity":"sha512-t63YkwUA83B8ZgxOkpn5nQQwoE/Rrjyr3A8nr121MsfZvasHsG+mv9K1yKK8U6a4upgbfs7uk2GaFwWiMeJFJQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCo84NCvqahX++5ZwSswWI1uX8NOd6aO6tIy8bjyjEQDwIgCtPsg27b8hWngJytXL6/F02cABzDieTuIi6OrKbzRnc="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/state-switch-0.1.7.tgz_1493736547504_0.9142217773478478"},"directories":{}},"0.1.8":{"name":"state-switch","version":"0.1.8","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"cacf4b0b18f8d644e26a670006c18c1f0837f1f9","_id":"state-switch@0.1.8","_shasum":"a4092dde3a46bbbd5ca7e34a739e8217085ec4b6","_from":".","_npmVersion":"4.2.0","_nodeVersion":"7.9.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"a4092dde3a46bbbd5ca7e34a739e8217085ec4b6","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.8.tgz","integrity":"sha512-m5hu0va0WSgGBgb6ahiGrOAH/01sxICvUa7rPqYUBRKVDmzPeXUIRJCMUZ7+MRGL1wRRa3OE57fOZBPNRvLd5Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCDsrkY3TKZTaRrEY7/X/r/3bpe2TJtSRiX3h0vTujPwQIgfXin1xPDYzaeUOwHbl3EXfg0lKYxnvkG7388bqyWWFU="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/state-switch-0.1.8.tgz_1493741359476_0.14783615595661104"},"directories":{}},"0.1.9":{"name":"state-switch","version":"0.1.9","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"c295886b7602ad846433626aa8a60f89cb6596eb","_id":"state-switch@0.1.9","_shasum":"05db80004bca1259ab84662ab42e8e21e982d1e6","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.2","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"05db80004bca1259ab84662ab42e8e21e982d1e6","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.9.tgz","integrity":"sha512-bTLwFHkt/3Zn44OizfUZT2uWCwU9AwIgDJFdSuZQTRftNtJTo9+XS1VSgdqbJJ3NNC6xqIiAj1BUo1b/M9defw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDAN2t7314NhmInkRtVcKzQFWsulgg1di1JKKDZPfn5gwIgUVNfw2IXFLGx8omHuKsqT/uvwUcUynWHrbwozECjIcA="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/state-switch-0.1.9.tgz_1493741525235_0.38405592064373195"},"directories":{}},"0.1.10":{"name":"state-switch","version":"0.1.10","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"624d35f80450c05559bf9afac61737e31282268e","_id":"state-switch@0.1.10","_shasum":"209f98ccc41f3e50209c51be5ed8c7a9eb415faf","_from":".","_npmVersion":"4.2.0","_nodeVersion":"7.9.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"209f98ccc41f3e50209c51be5ed8c7a9eb415faf","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.10.tgz","integrity":"sha512-dN3o8cI9wXtQHGjfRKXrjoyEylA/oexFim6ClTOVrQEFtA7oVVigKohkNSN2xwEucu/7L1KliIJaPafiQfcvBQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBkSQzPsBNgAkKesCIWO5idfOIxgZ1In2z2b+w0CjlZQAiAQfGqmZF+EMLgHHFsJiXf93TNtpPPYrXNrgbRb0ouHFw=="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/state-switch-0.1.10.tgz_1493781745832_0.9415823223534971"},"directories":{}},"0.1.11":{"name":"state-switch","version":"0.1.11","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"ef71551d6b37d9e83bf3798abd5f771b02152b26","_id":"state-switch@0.1.11","_shasum":"df4a6b6df9703864559eb04bcd1870a4c1c47feb","_from":".","_npmVersion":"4.2.0","_nodeVersion":"7.9.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"df4a6b6df9703864559eb04bcd1870a4c1c47feb","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.11.tgz","integrity":"sha512-mA4uI7eL2tydAAM+D50bbB1fh69eXKJyzjqzJXd6uaApWPEyZx1/aBOaEsDngvt8CyrQuO1PgR92pQwlOJRrWw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICzLRjw0NAfzw7oF1pdE57QRZeXCLo/BU/BbfMBq9xYdAiEAui0Q4fWbn+d2XKNIwv7z4epXITvZSJOuKre9JAbmARo="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/state-switch-0.1.11.tgz_1493782947441_0.23135470738634467"},"directories":{}},"0.1.13":{"name":"state-switch","version":"0.1.13","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint --project tsconfig.json --type-check src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"03c27b18725555dcd773452f92d6c1829f022a86","_id":"state-switch@0.1.13","_shasum":"6b8fd5ddd46f85caa385c0144b783c8a599a0f75","_from":".","_npmVersion":"4.2.0","_nodeVersion":"7.10.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"6b8fd5ddd46f85caa385c0144b783c8a599a0f75","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.13.tgz","integrity":"sha512-2ldehEjp+VSNlvpr/fPSYvO7GdmiCtGaN0CS2UY+i8O58N5HOP9/FEM54E8ocqUUZoSNm68Krh7yKdqnjTjiGQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAwyCGHKdTsv9fEko24m1CbwcwS/f7fw+5RIO4nVD/QwAiAZElf/FTIRi/L+jErsNWat950HATJxDjo6fl1hqZoMYg=="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/state-switch-0.1.13.tgz_1494094738273_0.22808541543781757"},"directories":{}},"0.1.14":{"name":"state-switch","version":"0.1.14","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint --project tsconfig.json --type-check src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"ed0127f2fd0b2b4e22c537058110e255a0666ead","_id":"state-switch@0.1.14","_shasum":"7e8a407c2bb21cd94d52ea8f7de03cac9fe4166f","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.3","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"7e8a407c2bb21cd94d52ea8f7de03cac9fe4166f","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.14.tgz","integrity":"sha512-IKdyC/ThYiseTOIRQoAe0CJxjBXgNYATUURB1vuMdW8Bn2iBAmonsTqP/P7AeI5HSrzr65yHDq2aYzfXC7eghw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFqWzVGSY2qeRimojTp+wakwPfOEgCKrn3uMoKxEy8I0AiA/a3xWKux+cI80G1mDhMZib6eA3KSnAxJflZ1deivGpw=="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/state-switch-0.1.14.tgz_1494095348891_0.20974712376482785"},"directories":{}},"0.1.15":{"name":"state-switch","version":"0.1.15","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint --project tsconfig.json --type-check src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"fb09d75b063f03c272e6e0fe5c0aa6d6864a2d04","_id":"state-switch@0.1.15","_shasum":"497d3b9ca1528f281aaf94696a1afb4d7ab9fce2","_from":".","_npmVersion":"4.2.0","_nodeVersion":"7.10.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"497d3b9ca1528f281aaf94696a1afb4d7ab9fce2","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.15.tgz","integrity":"sha512-v2dUTuXFmP1hLJlv0zRvPNi8V2LzguIAx7rF6Z6AbOgw7L8ej1WWB0qjhvJIbLvAxIQUtQIEFrvGw7IZFqIVJA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGyaSFRdS0B8XvOr5LTNTNWeQurKue/zuG1jxvHO5/NFAiEAzV3D4a/OmFYlLBMSmLhVXITAngD4osO8j9jKPZhioG8="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/state-switch-0.1.15.tgz_1494095387282_0.9776890273205936"},"directories":{}},"0.1.19":{"name":"state-switch","version":"0.1.19","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint --project tsconfig.json --type-check src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"6e730163e810c7dc5023bfb5931675360b81c020","_id":"state-switch@0.1.19","_shasum":"bacff6b03005692d40c991edfcc053686685d34c","_from":".","_npmVersion":"4.2.0","_nodeVersion":"7.10.1","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"bacff6b03005692d40c991edfcc053686685d34c","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.19.tgz","integrity":"sha512-MY17WbErZWzVb00e54JtZ+pOy65zexoI4kZICTIaO4myx0S7pRhefyR0OGcWThNqACeul5cXtaawiMND5NhoqQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIB3R8431nVWR+zRkExV9VC3D1MBa8OC9/AaoWh/fFDfAAiEA6mXQAlMyHiFlbN86hgaJg+B0CRnRwpqpUUV1k+ZySfA="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch-0.1.19.tgz_1508520146963_0.10176479048095644"},"directories":{}},"0.1.20":{"name":"state-switch","version":"0.1.20","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint --project tsconfig.json --type-check src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/"],"gitHead":"a7b484ce97f6ad1f9376a52472d5c5a9c4c6ac9a","_id":"state-switch@0.1.20","_npmVersion":"5.4.2","_nodeVersion":"8.7.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-/Hi25uWX1Z6G7x+tK8lkeLFNUp0eALZ/MhLBLxbLZSVzw33pZzzQ9+0jNVb7ZzukYWc2/npw7dZHXrCcJLAX1Q==","shasum":"77b10230e218995ecd523b58590792be15a6318a","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.20.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDfoSmdIMf40D2gfOjfkGw/78l69heoex9JOTBIVAguOAIhAJ2875TvE1ZX8MstKvRzXRJfdFJBUSsfnMBPbCegL8mk"}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch-0.1.20.tgz_1508520178988_0.08773512253537774"},"directories":{}},"0.1.21":{"name":"state-switch","version":"0.1.21","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run tslint","tslint":"tslint --project tsconfig.json --type-check src/*.ts && tsc --noEmit","test":"npm run lint && npm run dist && tap dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"tap":"^10.3.2","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/","src/"],"gitHead":"75991bd7343850d61d368a45ae768e650f2568c4","_id":"state-switch@0.1.21","_npmVersion":"5.4.2","_nodeVersion":"8.7.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-lp+EpKKr3yXjlDTFaYWrGWeVXc8KPLv4+aXzmEGZflGIHlBcsjrtZjvU80xBWXUNdct/71pRXBN2jcS4U42ZQQ==","shasum":"74b6d5fdf66086fc3107675ef1cddc8bf22fcdcd","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.1.21.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDM1HcBywTdXPhsA/N2kib6ZeI/P8hZW+BY2mqdAvHq2wIhAOJnw5tGYTDBERy84D2Si1RXf0ILwdFblkfIp8N3S1kH"}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch-0.1.21.tgz_1508596466877_0.2555464790202677"},"directories":{}},"0.2.1":{"name":"state-switch","version":"0.2.1","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run lint:ts","lint:ts":"tslint --project tsconfig.json --type-check src/*.ts && tsc --noEmit","test":"npm run lint && npm run test:ts","test:ts":"blue-tape -r ts-node/register -r source-map-support/register dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","blue-tape":"^1.0.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/","src/"],"gitHead":"a4d1ece7b7668d26dc97f0bf3710502a8c6360d2","_id":"state-switch@0.2.1","_shasum":"27a5e1924881c4c8bf3c9fe37832df3508a298cd","_from":".","_npmVersion":"4.2.0","_nodeVersion":"7.10.1","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"27a5e1924881c4c8bf3c9fe37832df3508a298cd","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.2.1.tgz","integrity":"sha512-ipUyAN54fBO72Ev6I35JFPpG8FHulvT9urAfNBFqs1ztwOCF/0abFKlGjOQs1cMk+StILgnx5Y/DG5ezMKa4iA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEzyHvR1mpfYuUJuL6uMd3ku0G+8RjLDrRXJD/pnwzyVAiEAvFYpeHAhnLm9rp7qytOzFkzS8TQaUmqwil6dOJJtkL8="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch-0.2.1.tgz_1508676745067_0.7505400958471"},"directories":{}},"0.2.2":{"name":"state-switch","version":"0.2.2","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run lint:ts","lint:ts":"tslint --project tsconfig.json --type-check src/*.ts && tsc --noEmit","test":"npm run lint && npm run test:ts","test:npm":"npm run dist && export TMPDIR=/tmp/npm-test.$$ && mkdir $TMPDIR && npm pack && mv *-*.*.*.tgz $TMPDIR && cp tests/fixtures/smoke-testing.js $TMPDIR && cd $TMPDIR && npm init -y && npm i *-*.*.*.tgz && node smoke-testing.js","test:ts":"blue-tape -r ts-node/register -r source-map-support/register dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","blue-tape":"^1.0.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/","src/"],"gitHead":"4409abff41a5e86dbfe2708edf6299fa8774bdd1","_id":"state-switch@0.2.2","_npmVersion":"5.4.2","_nodeVersion":"8.7.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-rxTGMmst4P04k4Cw4/ndqEZob5YbHeHZF8v7+SAH4jmLpaZ/gBV7JialIUE06cCzKgb7FvmOIsua77CzfYSBuQ==","shasum":"fb98068d7739ad6a42d2b5add89a115d62d2a03d","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.2.2.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCeNjILyFKeWKT3pus78jNsbudCQU6MJ6LWcdb+A148KQIhAJlxuC3DupOSTQ2uQ3rgRaI32xocXxMJoE9pR1BYmBzj"}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch-0.2.2.tgz_1508678006379_0.6469772316049784"},"directories":{}},"0.2.3":{"name":"state-switch","version":"0.2.3","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"dist/state-switch.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/","demo":"ts-node example/demo","dist":"npm run clean && tsc","lint":"npm run lint:ts","lint:ts":"tslint --project tsconfig.json --type-check src/*.ts && tsc --noEmit","test":"npm run lint && npm run test:ts","test:npm":"npm run dist && export TMPDIR=/tmp/npm-test.$$ && mkdir $TMPDIR && npm pack && mv *-*.*.*.tgz $TMPDIR && cp tests/fixtures/smoke-testing.js $TMPDIR && cd $TMPDIR && npm init -y && npm i *-*.*.*.tgz && node smoke-testing.js","test:ts":"blue-tape -r ts-node/register -r source-map-support/register dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","blue-tape":"^1.0.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","dist/","src/"],"gitHead":"0e80708a066c5d3691bec3cf5520640d3a930d3a","_id":"state-switch@0.2.3","_npmVersion":"5.4.2","_nodeVersion":"8.7.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-9FWDZA/Ob457StT1c/6HKZK4fzybZYyV5qVV2nUVKW+NuSVHW6uDbHbUvQY9/Kdl3tqGM2eJfi7jAE1tfCe0rA==","shasum":"a3b05973befa1820f970b6bf1cfb42b3cb84695b","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.2.3.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDsGXny04HyoonvYCZW457svt0ESaPLmPRXzaVnRlW6WAIgZL6A97yug/nrt7zI1tr2ozNt36jDGjzxt6/uBb36Y9g="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch-0.2.3.tgz_1508679181881_0.6668688016943634"},"directories":{}},"0.2.4":{"name":"state-switch","version":"0.2.4","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json src/**/*.ts && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:npm":"npm run dist && export TMPDIR=/tmp/npm-test.$$ && mkdir $TMPDIR && npm pack && mv *-*.*.*.tgz $TMPDIR && cp tests/fixtures/smoke-testing.js $TMPDIR && cd $TMPDIR && npm init -y && npm i *-*.*.*.tgz && node smoke-testing.js","test:ts":"blue-tape -r ts-node/register -r source-map-support/register dist/*.spec.js"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","blue-tape":"^1.0.0","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"gitHead":"8b9e793a583ed9839e107858697ce36e3e1d9040","_id":"state-switch@0.2.4","_shasum":"87a27c5f0f5bcaaa716f4743e966e251072d044d","_from":".","_npmVersion":"4.2.0","_nodeVersion":"7.10.1","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"shasum":"87a27c5f0f5bcaaa716f4743e966e251072d044d","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.2.4.tgz","integrity":"sha512-HZEI+gFjR8ntzIHalqn3K1GWE+ShhL56GHzyGc6jLVOOKAGKHpPcIQXBwqvGzTsIFeIP3q2oddIxjZY6VAoPCQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCw+jDeoN+/aFK4mDmX9dEkIkSL/VMdcTnpr4ecJ+cxHwIgN/p1UBOA4QbBZ+tBph+UxGj27DxHrhnOlDTnxwUxn7Y="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch-0.2.4.tgz_1509247063670_0.7575421661604196"},"directories":{}},"0.3.0":{"name":"state-switch","version":"0.3.0","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json src/**/*.ts && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:npm":"npm run dist && export TMPDIR=/tmp/npm-test.$$ && mkdir $TMPDIR && npm pack && mv *-*.*.*.tgz $TMPDIR && cp tests/fixtures/smoke-testing.js $TMPDIR && cd $TMPDIR && npm init -y && npm i *-*.*.*.tgz && node smoke-testing.js","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"gitHead":"0b9e11cef6032261a63320a0a47ea3661f33dba1","_id":"state-switch@0.3.0","_npmVersion":"5.6.0","_nodeVersion":"8.11.1","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-lPuuBtgew64CoBMuCJc469VyyLrXjoh64tVd8QRbPjBsrXCBuGAPh55AfaUCH5R7fzPIDm/SnQ6MHcG4OgSkEw==","shasum":"c6ab08f5184b12a52ccc0fe063090f35d63d3ec5","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.3.0.tgz","fileCount":15,"unpackedSize":68223,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDuct19c7+elAQFOIwf+oSQ1s5DH/uqe2Ui/X5EBC8EWAiB9ZoinNC1evvBAAjrL35c7ipRUObv54T+sV/uNpTkl2Q=="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.3.0_1522690692880_0.5480573434595193"},"_hasShrinkwrap":false},"0.3.1":{"name":"state-switch","version":"0.3.1","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json src/**/*.ts && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:npm":"npm run dist && export TMPDIR=/tmp/npm-test.$$ && mkdir $TMPDIR && npm pack && mv *-*.*.*.tgz $TMPDIR && cp tests/fixtures/smoke-testing.js $TMPDIR && cd $TMPDIR && npm init -y && npm i *-*.*.*.tgz && node smoke-testing.js","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"943e2c9adf55aea7369006b0b014ef39dbdf8723","_id":"state-switch@0.3.1","_npmVersion":"5.6.0","_nodeVersion":"8.11.1","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-Eg2gNwE3DE2y1qMVZ2T5Rx5Ua7EHmkD5Oedy3xIXL8DrY1OSwDc7bbuN6URT1j09yZkDsKTQimGbvmNehXvFtA==","shasum":"7ad95d86f3cd37d44eaf8a7f60ea69db4c9de79d","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.3.1.tgz","fileCount":15,"unpackedSize":68336,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCN3hwOABdNWALuAsYSe7O88m7Mg0n2MbTkimMGJGI0SgIhAI8bl5joiA7KYO8x/BLPmwRkxCu46n0xhYO2xVdxHjL4"}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.3.1_1522690828590_0.6873707349744993"},"_hasShrinkwrap":false},"0.3.2":{"name":"state-switch","version":"0.3.2","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json src/**/*.ts && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:npm":"npm run dist && export TMPDIR=/tmp/npm-test.$$ && mkdir $TMPDIR && npm pack && mv *-*.*.*.tgz $TMPDIR && cp tests/fixtures/smoke-testing.js $TMPDIR && cd $TMPDIR && npm init -y && npm i *-*.*.*.tgz && node smoke-testing.js","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"20fb8c36fcc9ea88f846fbe5be5358a918d43d22","_id":"state-switch@0.3.2","_npmVersion":"5.6.0","_nodeVersion":"8.11.1","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-Tt69iDvA0JJtxSDiMFzmGpE2FtBxlt53QBr2yTFH2GY06gnGjm8eUhsYdHhQtC30jAtnm8dWnxxq0HKVbfIRIA==","shasum":"b052cf78c740c5c918490ff4c270e83e62d5e4f9","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.3.2.tgz","fileCount":15,"unpackedSize":68442,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC+Tn4DV39+WdlXTUiS2q9wSaZtQ62InHKzec8rcTRn4QIgFUqN9qKtapixgDka+HhJ9riLJFykXWqKnHSEZ33sIug="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.3.2_1522691210786_0.05482375356705704"},"_hasShrinkwrap":false},"0.4.1":{"name":"state-switch","version":"0.4.1","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json src/**/*.ts && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:npm":"npm run dist && export TMPDIR=/tmp/npm-test.$$ && mkdir $TMPDIR && npm pack && mv *-*.*.*.tgz $TMPDIR && cp tests/fixtures/smoke-testing.js $TMPDIR && cd $TMPDIR && npm init -y && npm i *-*.*.*.tgz && node smoke-testing.js","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"569e609dfd52b2a2b3f92fa4414a634e2e2dc306","_id":"state-switch@0.4.1","_npmVersion":"5.6.0","_nodeVersion":"8.11.1","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-VO+0Mi+qZSXSCHGtCmRsUjoNb21jmI+OW/jM/SP3nfTXrQw635Ag61xkKVMe3/gXaIqzjR0JWAcDNhP0yOk7DQ==","shasum":"0820572082edfa8c7de5eced96655a12cd109d4f","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.4.1.tgz","fileCount":15,"unpackedSize":68884,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDGhxrYyMlVJ/JfdaxciXdHXVynvFkuzW25X7EFJ4LozgIgWlLGbUduSwA/ZTB+uMVlbHK4lddxOkdVWjVTCQUQi+Y="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.4.1_1523253191285_0.8365015947303633"},"_hasShrinkwrap":false},"0.4.2":{"name":"state-switch","version":"0.4.2","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json src/**/*.ts && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:npm":"npm run dist && export TMPDIR=/tmp/npm-test.$$ && mkdir $TMPDIR && npm pack && mv *-*.*.*.tgz $TMPDIR && cp tests/fixtures/smoke-testing.js $TMPDIR && cd $TMPDIR && npm init -y && npm i *-*.*.*.tgz && node smoke-testing.js","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"51e29db5971e91de465fa31505969cce8e65f4af","_id":"state-switch@0.4.2","_npmVersion":"5.6.0","_nodeVersion":"8.11.1","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-A2H1xgtt97R6fi9gga7ew+3M+sx9GdtQzjQ/n0/wWhGn83J5MF/ayEHFakMZ+o6K3YuZthFg3KHop2p5nLMSZA==","shasum":"74b889569bb8ff1f6663fa40560aa574e8d886ac","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.4.2.tgz","fileCount":15,"unpackedSize":68913,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIE2fZCbf4UA3LUb3tWatH0sx9W3Ua+C1V3+Ew0RqiTthAiA6kLOhA3VDxPpZSszyVha2uWRaV1WvRXTk/y2+kg8MAQ=="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.4.2_1523255566320_0.9345391192627817"},"_hasShrinkwrap":false},"0.4.3":{"name":"state-switch","version":"0.4.3","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json src/**/*.ts && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:npm":"npm run dist && export TMPDIR=/tmp/npm-test.$$ && mkdir $TMPDIR && npm pack && mv *-*.*.*.tgz $TMPDIR && cp tests/fixtures/smoke-testing.js $TMPDIR && cd $TMPDIR && npm init -y && npm i *-*.*.*.tgz && node smoke-testing.js","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"eac0a60fcc8d656f0e7dbc73eb503ce380fca0af","_id":"state-switch@0.4.3","_npmVersion":"5.6.0","_nodeVersion":"9.11.1","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-HWpq3nSv2qBtGp/xAK1TLdiqHEr3OdMgGDkO40ZoeVltOOnIpZi0/JU7czPy52YnaDE3LraCe7XokgQvGd75HQ==","shasum":"ea17786b79e473a78193f3be990e296e2bbd974f","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.4.3.tgz","fileCount":15,"unpackedSize":68885,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDNH610Trl1EA7FNPnAMde9c1nZ7HYf64gR4XVM8ZQlHgIhAO5oyGmSnybXQKCVOq9mMDh7cCvZos6QOfsPNjtj0ft4"}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.4.3_1523296185804_0.8130855859565349"},"_hasShrinkwrap":false},"0.4.4":{"name":"state-switch","version":"0.4.4","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:npm":"npm run dist && export TMPDIR=/tmp/npm-test.$$ && mkdir $TMPDIR && npm pack && mv *-*.*.*.tgz $TMPDIR && cp tests/fixtures/smoke-testing.js $TMPDIR && cd $TMPDIR && npm init -y && npm i *-*.*.*.tgz && node smoke-testing.js","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"6190fb116ccc794174166820fbb0506ba4c03fad","_id":"state-switch@0.4.4","_npmVersion":"5.6.0","_nodeVersion":"8.11.1","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-Bki8nlMHd3ALQHPd2L6dSdCE2uE+1Xcf4WEZ7EAd70+xf2z4pm91Z+YahfdG2YiEqID+WI+IEYD9XYQ3EVYbhg==","shasum":"91d71297ab53ad4bcc2a97a87096bddf1eba3077","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.4.4.tgz","fileCount":15,"unpackedSize":68873,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBURAs1Qp4adKvzJs5ohoatDg+ozIKgqzjrs5eCJ3UOKAiEAgIxRpno3S6jkikM8PIxEIvHewJGRBWq+lMlVrw5LqWk="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.4.4_1523297158169_0.001711621626571569"},"_hasShrinkwrap":false},"0.4.5":{"name":"state-switch","version":"0.4.5","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:npm":"npm run dist && export TMPDIR=/tmp/npm-test.$$ && mkdir $TMPDIR && npm pack && mv *-*.*.*.tgz $TMPDIR && cp tests/fixtures/smoke-testing.js $TMPDIR && cd $TMPDIR && npm init -y && npm i *-*.*.*.tgz && node smoke-testing.js","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"40e453861cf396255639e940c5a1127f722766c7","_id":"state-switch@0.4.5","_npmVersion":"5.6.0","_nodeVersion":"9.11.1","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-KNhArmqFJ5oOvkRUSDSaQYF5ijf/zMibvHJ5tXgI+XlHabiZfRD6tIdQujw0QGQ1dqqFkHO8sZ5ty0/u4mka7g==","shasum":"ed8a3b41ef8732a39876ff7dfa4dc037ef6d4ffc","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.4.5.tgz","fileCount":15,"unpackedSize":69477,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC/GuIaaRdQo+3Fw7kshbaET479GcjOh8sUN3d6z1Nt1wIgEH6QLybFgMIQF4Vd55VZxsCH3xOGSEIoErTOkWOtWV4="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.4.5_1523431180142_0.4965263395700321"},"_hasShrinkwrap":false},"0.6.2":{"name":"state-switch","version":"0.6.2","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"42106531ec92e41b0591c7f4726fe4b285fe3cdc","_id":"state-switch@0.6.2","_npmVersion":"6.1.0","_nodeVersion":"10.4.1","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-Egnrw2tVi6xmbKMUVDAEfpe7GW1b7J4eikeTlNfmCyR+Rqe+14LNp8yv87cwPQcRNwYn7SDk0LOjywWUk4+Wfg==","shasum":"4572578c80f906e84ac77f279ce1b471dfd14dff","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.2.tgz","fileCount":15,"unpackedSize":69818,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbJBGeCRA9TVsSAnZWagAApvQP/1AVxAgrprOq5eUREjF6\noNvpkz0nZ01TOav9ua+3G638UEjnxXvcmTs+6i6zJ1Yg5bATRblxarwEeY/2\nOp2JEj2TyJZOPsqq21G6v/M2sU53VqAMpgQAUNenXV9JgKUPoEScWoYmQDN5\nj0IWiR5d9y0ub3L+YXlMrGHSjZ3VVfua+h8qOTPPrPluky8sizXU6YhxkEfk\nxitZes1u7HT1KJb2f3OJhy7kPDnhxcOO77aYh9qt5NMQhijAZ89BTbXaEXgF\njzWZwglkBmSnSqri9MiZ6cR5UneACwglNNVKdgUHhGSLrZ0rCMxNB8CvP6YM\njZ6C1YGKNhtgdgj/G3d/Tn9WlFDopxNgPQbkphyo/RDg59zD76i+T2RI6jbV\n5LOFncOGqQ9xPQQ3vumWUrJXpMwY5dM3pm0xKOjB4FtNEc5Sw6PxEd7shENv\n9f1eF4z0YF44gjBfsVPBCYhf7fHSilP3G66UiK3JOhPK2qDNZ9I1hYCl+Sdd\nPNvSwdpM+WPDf770SiFmp/2AqOwKNPQUXMYHiCWs6fil3+8FJ8AqhCX2cDII\n/gYFcdRjMQTk8Lxdx6WmL9ugFtpqdAu9SAGKAKAnPmp+GCwCco59UwPEEmG8\n+4Zbg0GIf7n/ISi9OTNmq+ljQvXT3OI8cy/evxvczkMBGO667SdsUB3p0Ht7\ncOQF\r\n=2Vdx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDBfsO04MX7N4c+hg+i8JinkFs1t6yfQLax+EIMH8BQNQIhAJ2plzVq1BNUG9U4WutCwGJG2PgMlx2tcY7IhrThIxxU"}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.2_1529090460976_0.16186851904428434"},"_hasShrinkwrap":false},"0.6.3":{"name":"state-switch","version":"0.6.3","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"befc64704c3801b89fbb17e5e038d4b2cd1df17a","_id":"state-switch@0.6.3","_npmVersion":"6.2.0","_nodeVersion":"10.8.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-o/qCbOXORQYpV6uA4RMTD3Utk4jP7gETrfH3MeL+IxDRNcehNaAdAYIXJYASvAN9j+qSlCsm9QnNyyhd/zSevA==","shasum":"1b3c744ebe3992f052a29ea2e98ec9431d61da93","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.3.tgz","fileCount":15,"unpackedSize":70028,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbZmjaCRA9TVsSAnZWagAA3GEP/1hF2PkmF8AIYiZq2amG\ntzpAP1qV397XjGPrGRK4zuy3z2vzVnwPJUru1aNg2saE/eLqR94VEs4jfETu\nXe8trkLtjhh5CPvppSKqNrak4aWj9xnVou+L+9NB5DZI/I4Z4siHctykE/F8\ns93+YN4mTgwYHmSBm2MykLmHfzswajjcrF7MSfRxfHqkiKY7PFqXs/NsFzDt\nU8QNt+VAKljYY36woyp/TBUMtMXfSE8KhgCsc29vzIz19rMau6f5nuzdPWdL\nePwRacd33q/EXJaCSMG7Wa8OadnVxR99MbGEtVeBXLdQO9osmC+h7Y0DAU6n\naovvp8cJTFzFxzbXJTXBFY1CeS+VVr5rgneWD2i4cims1VZpDrzubMXhex1T\n1wyqR209qKvfvmxs4AJM/KfKTHJYSbJA5Rr2GXV7wx7aP0eR1RKyZjxr8Eq8\nX8dUlocOgOQqY6OyoCbGKUFshH6Ig6xpFcDnsw9owygU4XfSWbZg4N65c0v6\nXyoQufr9TciVU+5PaX3va+jKomT8j4qpjmaN/FBqZamFokjhiyWyO+1cmDP3\nnEVcL+oTGxS02zOVMbG9y/WwuqfjnmokwY6sYk8tmNu/zVdKXgy2hDgksjLY\nIdnrBb+lYNEzygx8kOzyjBY4dhpebgdjQzAEZT2Jq66Qoe3H4RjjEuIMa4mq\nd0dY\r\n=CMlh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDWlTz4+X0ff4rIYogJAD3Fz9FlcitrJL53noKztETPzgIgd2EkCDcjGuyxPX/DAsDwOiO2rMFKwal4MXDiUki1fTA="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.3_1533438169929_0.3187832513162694"},"_hasShrinkwrap":false},"0.6.4":{"name":"state-switch","version":"0.6.4","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"3d72978d4d24b419eb338b5c6835e8544bb6e93a","_id":"state-switch@0.6.4","_npmVersion":"6.2.0","_nodeVersion":"10.8.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-GyIekOyANaNKuIEADRm4Px2dAfwr3uv8zUWWy8b7L45Y5PNKaxds/My/fBGMyN3RPCRbuijTKdbfwNnjK9CXPQ==","shasum":"5f0d6b80eb5b43ebfeff88d799743500721eb937","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.4.tgz","fileCount":15,"unpackedSize":70028,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbZmj5CRA9TVsSAnZWagAAaqEP/2fQwQrJkJqHRFJPdE31\nWRsxXrS73opChgX8GXcW9IMhMq+GAUmnv0/wdGNadnI9h4GssbY0mH+jAbjE\nXSuPMNUON8v0GltkLNiPXYlg9RB66EuSzhXSIrRKXZ70pon7D6H2VLgoPvqu\nx25ZVeoK560pprRouvy2ZDVvaN2RMLMB1aLBVLbeJVbG8+Tl6zPVR1hfRIhj\nsZP8jOrULxosHXyBIJxPXDE15fIdblGW4gN0rt2dXd3nkvAU6b0YzI0as4ZB\n6F4iU1gU0OL0jCv69wWgp1dgPM8FuRLtNZbLF2JNpizGDiit3MTmDp71hj6q\naRpOAmnLsgJjcLGqvMQq9mIYoMly2hGcCF/mw7KN+yGoDEi4p6iBl4USOqr0\n9/oo7SFU9ht3vzaXurHcUVd8xPS3o82wJlr7ccKYc+NI1Vji1zac9+uya+Th\nTj7Bre/dJxkzZp3WUbifBl6a9MbV4rnAiJgE10FwCojZB8Ooady/Z4szG61v\nxuW3sEPD2ftj2NTOZBT5EN+Ncw3haxmgLg2UJ4+/AWu2Y6ofOM4+0D/o6OoU\nzFT/SwK9aCqGsy6WfYmO2zRPs9rwvPKrZzcKYhYIGDtzTIz0bTxBHDxi+XFW\nugyArOMUdomQRJUY3eyR4PftBD5RSNdaT+tccEo9fkNaXbI2Fv2LlX6RzIhv\nvWEG\r\n=vo4k\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCXPQPnrmxpiVVzxHK+ZXED6YMHm8dHHcI8HJihaGfJVwIhAIMjYYG2BalbepR63R4DqGYi1iBsOb6/nSNNsmW0ZSEL"}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.4_1533438201222_0.9156886924647056"},"_hasShrinkwrap":false},"0.6.5":{"name":"state-switch","version":"0.6.5","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"53f0ff8b6e4f90396a4db86c6a7ae21278ffa28f","_id":"state-switch@0.6.5","_npmVersion":"6.2.0","_nodeVersion":"10.8.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-02mtMha9/onKvMhFG+EYNiwmuHIZTGZ4y6bgAM3I/zjvPzbj8skUjTKgQ9ZtNE2o4ziXeXJ9SYSrZjIo2bGIjQ==","shasum":"ed680e6212d5f102689f51b2ed6523e12cdb829c","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.5.tgz","fileCount":15,"unpackedSize":70026,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbZmnDCRA9TVsSAnZWagAA4xQP/jQ17SCib0WlUyBTnEI4\nafd6gYHctZIdDC/IqZuYi8IheMSVQUET3HucbhwUCrKOFaif9foWPwE5Uedg\niA6rI8JowsyRA+1yVxevBaPjUnL0DmUIIJ8Q48e9fT/DMSjfV20x42KbSAlf\nxfyjQxEnWvGI6DH2Sfo+p357hw4sl9Nf9JmJZqFn6qqWFaKicEMmhzhjQGzZ\nJFn8SWRWT1nL65RoStXzsB72I5dP1H/CcQSyDY7M3E1aur81PwRzDMkzb7Cx\nfk7F1xlMqlqwQpVrUjIfX1ofbHS6xx9NrDuHLEY+RqiEreHaROUUbGT2idtT\n9sGc9hlyvD4YnkU67h9hT6EIm4kMtIXEq6WjmMJlUkzl2/F+6OBIq16k9ZUv\nd6atghOWgqbt7cS47QkLCKAJBXMxnsD8FOZFesZW2OJjjUNtE5L3eM/ZHqow\nEJW2TiktnIhEoOZ/q4XqHl0NOhjLijzKb+VqMpYVMzIjleBG/dAvh/q57Bi5\n74QasNdDc1kF3LKWUPKGQY8Fm6R21S+vRgUMRNyXGEWykKrOyzJOHpFx/kRu\nm0yC0vVy7n7miow/bnqQE9wv6nkO/b1VzLHFb/daNXwSoGNN0Aoqd3NRIH2T\nerA/izBj2DQVLM4jB9p2bg49w5pLBz5Flu8K+qXPnAt/aU6ReheFMT3rzxFA\n6YN4\r\n=Hik7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDwuJBhMWdIk854UjGjGHv3VrVaur3y7YR2IvqoXICT2QIhANLwC2jVteRZ21fquVA1DsDA9nmeANTEbpFo1YjcrZO6"}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.5_1533438402922_0.812955202388314"},"_hasShrinkwrap":false},"0.6.6":{"name":"state-switch","version":"0.6.6","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register -r source-map-support/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^4.3.0","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.50.0","rollup-plugin-json":"^2.3.0","sinon":"^4.5.0","ts-node":"^3.0.2","tslint":"^5.1.0","typescript":"^2.3.2"},"files":["LICENSE","README.md","package.json","bundles","dist/","src/"],"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"d03e1850201c71afc29ed6f48f12abcb1bea4ecd","_id":"state-switch@0.6.6","_npmVersion":"6.2.0","_nodeVersion":"10.8.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-3IcUacl1JywU/2FCPiTa4mQt6BQSmLJivg98ioU/FEIkfjUWIL6x9bNgJVR5cZAz10pvC++6vQAY6Va/K9wuuQ==","shasum":"440f52f2be45131f27b81462e063308a9396d365","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.6.tgz","fileCount":15,"unpackedSize":70091,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbZmpYCRA9TVsSAnZWagAAuCoP/2n6/bGR8Cqo9N5ohJFR\nLu/0/J/yQxnt04oSARcgpYU05N2F02CSRMdQ/wNmLXqoU3IY0Y1LGM98kqEF\nJsBok5CBVHuXFvIg1Jn1zpqKr9IkKAjA+Pcz/TKpgwwrACS618AB5flgVJga\nCokiHdMW8F1rbIJeDH+R3kjJ4zQWZcv5PuY7cEbFA9AK/RnA+Og7UpBOmgyy\nHRT5IYHVRNJ4thYdxUCWE+xPl7NXohdwb0Im+jNGsP9c74jxDehCxrzX6COC\n8waI33ydG+XMxaxEJhMpqNZUiLOXCaK1gPgrQW0mEE9noV3EMl5Y9zjpkvCr\nz08mVXO2CbojzitTKk3+l+ml7WxOfykl/JOirdSwKJj7roSAMS355SbCQdss\nutC7OEmbgqCnKS0fSdz0Errl9WvNROEVGMv4QRV4DwT2f/LIglpeG1/KlWNo\nEEBlZtNA56B6Bfzr3gGTBpT7ZtE5tXZURO/DToYLm0l0ntrreTzmYC1vSQ5K\nhwRdzylQEX7zJObi2aEVR2WBEQBlNdbFU4H8bKIg3dYE8iCjC+5ptAs3wgB7\nfLiUvSyRBIJXzexuROeLZsxFhCgJnyYxfRqd+BF1v9TMGeDvzvTCiRuiCFAB\nbhtezeM989rFWrvS8l5Kee5Hf59M1viwb1x7LOh8b6UWIevXb+SzjhZ3EWbS\nHmE7\r\n=EZyh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCiCALNwGtsIqxt30/NVXe3YRNgz7wMcr8jqusLGAg9PwIhAONoNV1lkMTFxfOmMCGxIxtNV/wRtKQvUGlDOewe2hef"}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.6_1533438552166_0.761527284225149"},"_hasShrinkwrap":false},"0.6.10":{"name":"state-switch","version":"0.6.10","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/zixia/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/zixia/state-switch/issues"},"homepage":"https://github.com/zixia/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^5.0.1","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.65.2","rollup-plugin-json":"^3.0.0","sinon":"^6.1.5","ts-node":"^7.0.1","tslint":"^5.1.0","typescript":"^3.0.3"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"ad35e82dfe13ab321f1bd220c025b2b1d81d0acf","_id":"state-switch@0.6.10","_npmVersion":"6.4.1","_nodeVersion":"10.10.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-FrXf4DMJrByrFsi+V3hZI63C4U5AFd1ZARdh1h6E7Nv/Er42gPI9VMgx8jZn7bqtKhiyd/489A6z0c1+dC0P2w==","shasum":"727645cb6449591d7b20f668daf552034a7919ac","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.10.tgz","fileCount":15,"unpackedSize":73908,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJblAYvCRA9TVsSAnZWagAAlwUP/R1k9myjPwBzyIP86+h5\npCYubFVvLd4agEroYRRln9bm5LDWA+BOA5F09dyh8K8rgAPqQqvHtUGI0egb\nBnzpelkohGsP5rW1SV2AqKM76PqDAZD48vHCuLQYmofzNIqO+5/qHxu0+N68\nVRXK441g97CRkP0IGBN7SVNTbKqKjuTct83YaAwiGPYlxQIc1v4XgAhhbmLb\nkgKAeASqhwgjPUz9OAlmrv7uyrFTzHsOZbxhtEaTKHxzkAB6Kw7d8FANmdr0\nFgPiyy0orHrWV7MSc/fAC6NlhEa+wLd9SMCaGuYldjCvTWmzuD+lRe8NaLIe\nCfWFbDcE6R2GpsuLXPK164fWmxA6ZH01v6vfh0ZTW44CXBBiP3LvBH6jxhDG\nvk/jXVOLi1dgQY1q6okH8t//gVv8mDpiovhJlDgscFYECn12hSa1dDzOFcDa\nNM/TmRxI2soDhXFmsusJVy5E0ie7igblhhYUhLHqTzFevq+A6P0pm6QrrNmB\n4nm1wUOhyCQm9HJSG1QshcfuCsrjiQddOchiu9BZytPnoHUurHvBjOVtHuOO\nc1oxz4SVJ0qC/lOxGmV67mm1Kx4OVHR8e9EOu4iNgwnBVbEGJWZiidGpTzEp\nHh+VMsVroJVfs/qfwVD9eOhTl1Bsp3WM1iaH/1HkqrVHKJo/itsOh6hNGqHf\nSVy2\r\n=t+ts\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD/yuN0ZSCe52klH/EHhIPQTb/NXNN4QxwILHFeiTP8iAIgCcXI6R8kuXgycxd5Kf6y33B49pAku5bAXKEmQjpO8U8="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.10_1536427566886_0.37942390035127604"},"_hasShrinkwrap":false},"0.6.11":{"name":"state-switch","version":"0.6.11","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^5.0.1","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.65.2","rollup-plugin-json":"^3.0.0","sinon":"^6.1.5","ts-node":"^7.0.1","tslint":"^5.1.0","typescript":"^3.0.3"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"0279d8aedbb7ca4beec76ed94745bb276aad5718","_id":"state-switch@0.6.11","_npmVersion":"6.4.1","_nodeVersion":"10.13.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-/xN1NwmkorKrUmt18ogzWVbHHPg6/nShGFOERok5xE5N3r/As/lVcc5G2uZXG4ZYgcOSHKdAsfS/eYfcZGHfXA==","shasum":"193f2796dd56cd2f22aa8883c6190ffafb4da380","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.11.tgz","fileCount":15,"unpackedSize":73895,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb/XGxCRA9TVsSAnZWagAAKlUP/3teWWYP8q538hLH++fJ\nVjdBqNGabfX2OkTLGoEE7enESxipn2kYVtCp2cGxkCTm1f0n6OKlBqh/SJ/g\npua/TJfRgWwUAsK1ZH+ZrGRea3I6PFAR59r+Qkr+TiFYhG/KkVhnMyMlUlTW\nAqLogWaGkZVgxvaB6VV+YiKPh0fHk7YxwOqPzdvGb6jFgVmgMaD1MFGSe2j2\nitdvMTzpR8IfBk1lDeB8NJ3ji1XdeK0XR8rGYAPsu5wR57o4AsgahR+LtGYV\n4QyTSSJPUZe9Pu2C7t+Xtu3T2oAjAgX5jIPqWvACnPa28dmPoXbgxieOEqu0\n3dNjtdldpkbvu1rmFz7DBxLDyUks4it26SQdjBP0oKZOdG57TAA+YU4SJUue\nZbS3ykHRT10FCHtTwnEXBYTBx3wV+axBtLCc86/YFuB6tv6fbgmPJ3Z7m/dQ\nZvi9gOM1vm64qTplC86VrHGKgQN9cfFh0qW94t/gKMQ4DSJA0SI8Lzaw4Hqv\nd41XTxuWVO2cwpVKd9zMobZlhYgJPt1AS6fm+ocIk34fF5GDEMdDvRgM4RW+\nvYtk8sSq4U402I1beAK4sTBRDTNX3mYLxL2lEAb58kFqbxZJK4wjVt2ncM7v\njqQiEgxGo1XBoSpqv+nEU0Y/Yuz15E3RmvdVQDeKZ3N6FBUkDS0Ke9NzDxmr\n8arL\r\n=x4Lp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDSq0b7DJp/OBN1SDMqko2g5R7lOq1IKdxqWd8HOMdvFQIgGrI70S7hz1crgc3SwsmobTE60+S485nd+7eoAiXf/K8="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.11_1543336368268_0.2765382813711712"},"_hasShrinkwrap":false},"0.6.12":{"name":"state-switch","version":"0.6.12","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc","lint":"npm run lint:ts","rollup":"rollup -c","lint:ts":"tslint --project tsconfig.json && tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@types/blue-tape":"^0.1.31","@types/sinon":"^5.0.1","blue-tape":"^1.0.0","git-scripts":"^0.2.1","rollup":"^0.65.2","rollup-plugin-json":"^3.0.0","sinon":"^6.1.5","ts-node":"^7.0.1","tslint":"^5.1.0","typescript":"^3.0.3"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"bash scripts/pre-push.sh"}},"gitHead":"9913610d887c90f516d8a8854ef825edacfa75f6","_id":"state-switch@0.6.12","_npmVersion":"6.4.1","_nodeVersion":"10.13.0","_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"dist":{"integrity":"sha512-JVIEvfsj6Arw8qwHVzWtAmltoIufMLUchti1iLWu+4a4UCZ8vwLFiDuudQHZpcQ+QWf5rchlFnCy/9G4AHBiTw==","shasum":"bb94f39a88c246c6a705559c3ae240fc4c0b872f","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.12.tgz","fileCount":15,"unpackedSize":73893,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb/XNaCRA9TVsSAnZWagAAth8P/iEH/Gmd2uCDRiYvoF69\nUq98G6QBQ1TTosBPLMewWAmkzm3g4c0Bmn1aHYd0GrCpB0FyPWkoa0Y7tg+6\nsFBdajPYc9dGBRGDDNDz+Dj2vaRTAyCKVFkSi6+wVxVjFeTi2H8dXhrguorq\nAYXdcobEHWCtTDWFfRYKmVjDkE1qcHs9PdfW7rpytsNTODwukKwrHbhwM2AN\nM9EeUc1M5qtWnKhu1lCdsYeZDFjdZLwE3LWfia1JNK2DY40NEWX3wZ5J19n/\nxNfAjqH88Mns0dE7PRiW1iNLc/IvKk3otsHr+5pKCvFm+4d3y0ZbdqMyw+lP\nOjkXf9C6pFvZPxHLHomsHwt4UbRSHr13Io51KQSceyI1ivAZVNt50kvyxKye\nYTPPibJgVoM67wct68Cq/fyIU0+AFdwSweF1ti0lg3uaRMCosCdWQ6u4R3vU\nh+8faJWv44p23tOq0AG37BJR9HQrIGyZUskpd67qRRC6UCWYxoki4nOJNylN\nSGuJ7piLSODNUVY3B/ky1PLbeIH328OCNwNJjE24G2gQctoGqFmlwPW4EsFN\nRndKofKAuFOTeRUseeLl7a2hOSWd7ULtJapdvfRS4toKGXt+m4DlCdDW/bC9\n/yNpnFv2S0TOxGerj9LNAzkG1KPt0bj9yeP3FGkql0/td57zzwCb9FK1aG9Y\nNDBg\r\n=QizH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCw7FpWNejN4fJWLh1sBznxdky9U2rc6IfLZKpmlUMMXQIgTRXdalBU6pPMoR9g7pRisb0dPPoS32q2kvM145VnQCc="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.12_1543336794141_0.7375513950663144"},"_hasShrinkwrap":false},"0.6.14":{"name":"state-switch","version":"0.6.14","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.6.18","@chatie/git-scripts":"^0.2.5","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.6.1","pkg-jq":"^0.2.4","rollup":"^1.16.0","rollup-plugin-json":"^4.0.0","tstest":"^0.4.2"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"0ef24562460bbe907e1670e7f24f94de535ddfa6","_id":"state-switch@0.6.14","_nodeVersion":"10.16.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-2XGBdF/qWVTh/+ojRzkMfzleRcqwDn1CfeRwOX+1hSiZQgGSMc93eClO1gs+D8yf196SOn9MprTezb3sWBR7KQ==","shasum":"4b6dd2ad206d0ef6fb38b065996e455381554a29","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.14.tgz","fileCount":27,"unpackedSize":74834,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdDdduCRA9TVsSAnZWagAAX4YP/RXIR5O9sDmuNMShjUvJ\naEOeuyTviJS5OF76P8dYjzLZ97bfkpxmPbb3qsnzMLvgTTWj9Ptj4TV0yqjp\nJ2Nwm50OwqbKr+2szqYfutOPFyUkmAonIg4Mu7Kei8vMhWXDnjCUFCv7mpYz\nH87FrlThI1NB+czgObb2PpJhT6+xjy5jeIx3Cv2opG6wfCHnE2/aJkwTVVMs\nZlUV1idF7hPQC1ffiOgD4x/UyYW1EQqBdQM4WmpthIGSPIN5wHiiS5L43+nO\nplO2anquq59Whzwx1CmkriPjbPdDB3Lp8TSweVv3wZ9ZHFZmrGizcl1sEK5b\nWPsGxsyK56iw/q9xJwlBVwnOH/pmIFwhMQI29RnMpVLv8GCd/lMrNfLVoahz\nKl8U1Vji8MLMLiVBl1cUI+uNgJhmKfvW8N/MnfaHozSFuHqYfTwhQrxTXDW1\nmDg6XOtYDTz77Y+KtuWMWX7fpeGsdYTzY9h/MI+HogcRt4Xn92SPiMhRPgD0\n7A9tIrSVFgjwVnAXE8FoKPcc3s10tFwtJIAxY1qLqznpyuYOy8pbHr7te48C\nQXGADSz7o2PjYjybxsDauS90kXVkyrYyR1Tk6DJcSKmSlXpHIFUZ5hd1dF3b\nB6XAOs24YGR0ELIZ/uPYm4LciC0uzo6FX/B1Q0Z8LuLc8FMtNxJWVAiUnnM/\n2ds8\r\n=UenN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHmnzmr5XgGpcKS5OpmhzNjRQnhYtfv2ChNXp7x536ySAiBdwv9pSdGRjIzxu9naVlj9GCMTnDkdD4FxtsVHgBg5sQ=="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.14_1561188205814_0.1736948390994062"},"_hasShrinkwrap":false,"deprecated":"state-switch@0.6.15"},"0.6.15":{"name":"state-switch","version":"0.6.15","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.6.18","@chatie/git-scripts":"^0.2.5","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.6.1","pkg-jq":"^0.2.4","rollup":"^1.16.0","rollup-plugin-json":"^4.0.0","tstest":"^0.4.2"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"56f422e561f960b4e31a3b28d0a96a5d68771d3e","_id":"state-switch@0.6.15","_nodeVersion":"12.4.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-BdsPHey7SwrXxRbsI5c62BeZbYtEnAbYyd5FpFEu5bOFo7WEhxS2yG50K8cIPafh4pT/w2JwiglvI7upN76WlA==","shasum":"73540afefe686cb03531a20ff458d137f9b0e7a4","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.15.tgz","fileCount":27,"unpackedSize":74834,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdDdfZCRA9TVsSAnZWagAAxQAP/jBYgHJ//WKShTyIG4SN\n4Zd57SZp8ZIFFS6MssucRmBR4Mz0mM1rOwFZKx/TagpNLw8hxNHMJ0KLx9c7\nLuFn2Aqjp2nJ3VIwVFi+RtMgkYmptyemUbTQV8W7Myd7HAiHRCtECutNmqvb\niBEeEypTBwN19k64eVDITPIlkz6VzttYmLQKORceRYa6ejHxIMnDmh/7D/2L\ncpUfQhZ3Amq+r75bLnnG9A4C5mXxURE82n2SopeGvWYBfWQHnnXE2BbrAde1\no4xYu8e1LkOk7kxcztoDM4/h9wk0N1I60aZCkb6f1Y78Vv2QYUGUs9l7kqAd\nnoC8ciHs7nKDrdfXEYNoSZwtBQZNR948deRqcWi/b1IKV23Dzca4PHb9OHve\ndzh8FT8XqKlKZByZ/fq6hYZR09/Q4lWOH32qTRkVgDYRWMob2Tp6Xxa6vn8V\nb0KfmNYEEqlmuqgGp5IENrzi4x9tPa1D0ydW9XrXYHWjxdoGMOjxoO+UE0FC\nQS33lL0XT4+GXGxi3QxRxNkcgHP+ceGLfgkQCJw8hS/RVhjYS3k48mWDveh8\nBzMfPh9QHRq3MsH7aGzhQcyU7to8zhGCPL4I0+0QL+2r1e1SjpBqIe3CDFpJ\nL0zoom8ZppV9YlIJnDNDFpOK0Jn/hdzjFSebZjd+buKmJC4LlDmyZuhjwqMx\nkt6t\r\n=SYV5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCTu3sWF0oMQ7QyRliIqyZV1aDhxRQBxdmFLPFzhkdehgIgNBXcHP1Xk9vf/YKltLCnzobBViX3R6qAwYlJEEqnPfw="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.15_1561188312405_0.5965677465728445"},"_hasShrinkwrap":false,"deprecated":"no default export, buggy, do not use"},"0.6.16":{"name":"state-switch","version":"0.6.16","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.6.18","@chatie/git-scripts":"^0.2.5","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.6.1","pkg-jq":"^0.2.4","rollup":"^1.16.0","rollup-plugin-json":"^4.0.0","tstest":"^0.4.2"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"5d2a9234aa1a7d587f3d05b9d63f31092816354c","_id":"state-switch@0.6.16","_nodeVersion":"12.4.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-TUeGiAI/RVSCUYhcu5W3Zeah9TCA7wc+IrXerOqD1CcKy7D+lp6YUrPOCIOKfDbQdbwymnG2C0xj4VAw+f1MxQ==","shasum":"d8e9cd2dcdc1d89728f36cafda0ec548c761bd17","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.16.tgz","fileCount":27,"unpackedSize":74834,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdDdjsCRA9TVsSAnZWagAAo9MP/1guGFH3vXUg4W/0R0hG\nf70Iv6rXuFIWIT+eg34K3znnLGKMnhWBD9pdWUY/gfw1WvA7YnIpsSZHhRe2\nkqjyv91HcUvf70Rmm4D7P7I93QpGfUqnRa9CDi+HsOfCLvj/56/4/c40IB5g\nO4kPTivgBUgR8qkROLcqIS4MYflj+BwuVOf3y8Es2MB+7BR3Gp7fH15/h3HX\nc6Pi/jE+isoL1/bqANDoX10YGB6fDJJNZVWZdwQ9j3k/m+Ga6up4TK3wprTh\ngvLd9bXOC9hE5eie/gWGodIcvqxNBv68beNX9aZpeO9wVuIHgKPxH4rIA3T/\nuKurn13M3Pim7y/65u+vm39MGWivV6HVH1jb5pKM08xJhFgiixEHPNKGof+6\nR8NbeQehpmoxXPRUTalL1gj1r1V5SEy5PFnX3TckSp7Lfnk69dVirQhATp46\nUAx0O97fwfj+W6pCgTZ2Gq1oWFzyXBlWOceL6mE02cDROvfyCcAB9TUGHhXL\nG6TRfsIGM9C+KCLHR+zDzz427DRX5tLlWNGkU1Y50Yzz64xb+lPCgv/aM59K\nePM/THh3Br7GyIrf04Z0NLb5qrzUvX5H4EtcNKvBTdSEtq7/7pLpyMYOkyx8\nK7F8rLdTw3aXS7DMo0+a9Eh7cq2efNv2/3HdXOqNlhMa8SmtoTzJ0wl5S6YG\nuVjb\r\n=bukD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGtXsf+CL8PSpoTuRoLmUrMmyRvdysyhFlHkvRISGN8eAiEAwbkrB70RaH8sZwOtc94XPoVf9Rbyi+tB9HpfW82cKZw="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.16_1561188588175_0.5203530259086935"},"_hasShrinkwrap":false,"deprecated":"no default export, buggy, do not use"},"0.6.17":{"name":"state-switch","version":"0.6.17","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.6.18","@chatie/git-scripts":"^0.2.5","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.6.1","pkg-jq":"^0.2.4","rollup":"^1.16.2","rollup-plugin-json":"^4.0.0","tstest":"^0.4.2"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"8665f8d1af199acc9d728333526fec3e96954982","_id":"state-switch@0.6.17","_nodeVersion":"12.4.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-PBk3GWM0GL3Qpxw8wSmBAFH//A4apDF6UpcEqbItDB4gMn6OUns156WcZwXkRo9ChS1nhEDM3z08ptsP6qN45Q==","shasum":"04403946efb2bd761ae2d878587ce621ee5792ff","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.17.tgz","fileCount":27,"unpackedSize":75117,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdDhbeCRA9TVsSAnZWagAAX4EP/iA3dwWHeqVcrlOFt6XQ\n23ME3lkqkGksiMfCRbYQ2taR84uto5nKlp6DzmMmaUDclWlE0dpHRsjKSluU\nzcovZQJn4GcnXNBzsBWL/D1ljQH57wUHlEyx0fo0afQhUrV3LofUbsuJ2IW+\nK28AP7yO5BXXEpy7riTtOavvyFraA59g3/SVsJDjnOj7X+WLAIUCw1pBN6UV\nA1BW7yBRBqL6M7Ita/tiYJOMOrQS/b4PeudK3s+NMTzhq4LV5G2Zz7f0Ejay\ny4bY5850qBm9tDsVRgggflsFe+PyfZg/jys2Ao4+n7HwpOfZTONmzH+RZn3E\ndL39dku/e10OO3Rd1pNIOOqCPH7LdoS6kDyhE6MhhceRL4kAKqhD6tr4KhcR\nU7FcQ/ZdSnKwVoj0hryK+qP4Cbi4t5Br2Srn1QND3FP7yRSw3Duqccnf2lAN\nsqNIqCjOEB+7rr3XEAamr5207QeHONgbEz6jYmz2GPgahr7pVuWcQAVCw52N\nbCWBQDSrQdPdzAGp1CMfOnY4PhuE5neGX9rmgEKTIwqN2NclKgk2EUCE/P7D\nOo2PCcKdiblE7CxkfWShj8ifgFCZg0qQFSnOlpEZZWBDSbdurqPojilMXRTW\ndeJqu8a1LF1cBJoaTpxs6TemfOmDa2fHKfv1edesq5DGT37Bh2w/tD6Kbk6s\nk9oC\r\n=R++f\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCq/OTpTUOJka7pZckLMJpenxWopOql+MGi4QDJcvla8AIgQI68M6Quf1NC3djO5MWGocuwl8WH4PKGGFLeSgdCjL4="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.17_1561204445315_0.3319934891328691"},"_hasShrinkwrap":false},"0.6.18":{"name":"state-switch","version":"0.6.18","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.6.18","@chatie/git-scripts":"^0.2.5","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.6.1","pkg-jq":"^0.2.4","rollup":"^1.16.2","rollup-plugin-json":"^4.0.0","tstest":"^0.4.2"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"7eeec39ac9d219e1739100f5228847863e1c8f29","_id":"state-switch@0.6.18","_nodeVersion":"12.4.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-xjANLlh3CHtC5Fk1W1HT7RKNUu+4u2o2QVzD/droEbDSKtTP56he7JaGZETPUR85qor4+fyTur89P+oqB4pCfg==","shasum":"6891050d832ee580b456851958dd590eb219f12b","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.6.18.tgz","fileCount":27,"unpackedSize":75117,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdDhmJCRA9TVsSAnZWagAAvjgQAIISUXATegzf+eY/oJvK\nn2kl+qRuDzEe4qR1hxFsMdYPhxaPF0W/o3ZElRWSs9Ukd4iAD82MehlgUyws\nE1ia0oHiNJh/R7gW6//OxQjn17Td1we9P//rlXPYar+Fbe++Fnr16njIWg41\n3Zgd5fYtiYlW4pWtJLXxEafQcqu60Rv+MN7PRIN8O1fTOe45VTSKzcvmhgXC\n6BOc/lC22Jt7bnkqrr8kKO7PmWfV6hnaiZ1By2P8opTrxkbhYI8jAZEHSjHx\nJhCS8sDvymJ8MhqhyJB9fhAHPhOCO5bn8uCJHQOh6TSTEspFct3Tq9O85ss1\nLfKV5Bi/E6f78pA+J+hWqC0nRQiJYdwZ4z4OEK/2DzWpLN0UECZd+BmISuT1\ny/gYUiDPRjgvW24lQnyUo51EU3UPhQ3Cb/r8cW9AH3zKUJDvx4qDz3My3yL0\nt1tSw9VsGo+9Y/pyLSJU1mFrS231SgVoofq1OixtX92SdOCYfwSRgw6iI7Qu\nTCVdIIAz3Ay8d6c8xK/1oK3vCrp+e3Njn78j7C1lcjC2MxjOEaMniPmz8iC0\nhXvpglppOsOlvJ2K4VHOJX0VFbgzNMAU6SK/yHLtfy5JvltPlBpKIl2Lj+RG\neG7OMuqDCe/ULawBDuwJvrUdh7igjbkomD/eHLnKbDKyXfFxL/tNu3LdgwsK\nM887\r\n=Yzcq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCCemvs6WpwoTCfOrCGBRBPcv6SICfyYNraXCrXPa4eVAIgCVmyEwU4XOjtGSFQrR19XVS4+Qhg9odgQYg5KYY8OMY="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.6.18_1561205128734_0.8087327535611686"},"_hasShrinkwrap":false},"0.7.2":{"name":"state-switch","version":"0.7.2","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/state-switch.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.6.18","@chatie/git-scripts":"^0.2.5","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.6.1","pkg-jq":"^0.2.4","rollup":"^1.16.2","rollup-plugin-json":"^4.0.0","tstest":"^0.4.2"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"gitHead":"671dc8751cdf1ff2da1d9d5c5c12356f88c000a4","readme":"# STATE-SWITCH\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n[![Build Status](https://travis-ci.com/huan/state-switch.svg?branch=master)](https://travis-ci.com/huan/state-switch) [![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch) [![TypeScript definitions on DefinitelyTyped](http://definitelytyped.org/badges/standard-flat.svg)](http://definitelytyped.org) [![Greenkeeper badge](https://badges.greenkeeper.io/huan/state-switch.svg)](https://greenkeeper.io/)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from '../src/state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### v0.6 master (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 master (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n\n","readmeFilename":"README.md","_id":"state-switch@0.7.2","_nodeVersion":"12.4.0","_npmVersion":"6.9.0","dist":{"integrity":"sha512-0kW2Minacssdv5w+KPI0eiIOg+SzkZvG2Boav7zYn+OgqkM1rsAGvCzX96sTG9hOHfA4BNmqDj8GaGia//9dxw==","shasum":"bf27dad2423a2aa982facedd59334f7302f96115","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.7.2.tgz","fileCount":27,"unpackedSize":75107,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdDwBxCRA9TVsSAnZWagAA1qMQAJgZLGUyJ9kMYznnJKhk\nI7IIfygEHWMJIj9NqZvh+CLwSNsvWXySueyMin2PQ3Lo1wDg2RXSfHQNiEV0\nzXzJpbHfZNoUFCrDS3PsW2IE7fnrH0zqV4HYZXpgpVx0fovyVS/Y+oMyH/EH\nXG3geO0VI6gp45L9crHgr2NIKlEUEK62bIc6fHJc0lAWPxNdYt5Bn41+411+\n3UNkvmxGs/WvQAhAT0tO8l5ULVzSetl/beEseqEc9J6RWVwh+lPWVT43fb53\n7Z1BFXUcANrenxGyzbARPaLzyDiNZZjJ2ocg7ORXq5lPSPjevH8ZY+kTdn6f\nJEGP5wxewYcDTjLebWx2ntAZE7iP1Fch3HBqRA8yDsJo3KzGwv4Y6UoJuNB2\nhg0vP4t34FZsuvcU+Zn+c7u/Un3BvIUHo1VNnciFrbAqQxcTegzpf3icML51\nLWhYp+Lm+jvcOv/88t0DyngWQRJAQ84zmvQgOC1XMdaLp1KF1z2/z4CL2QhV\nQS8ShLvTs67geHqzFbW7AtMq82vp9IvhsgGAqLZzCeusTwuVfxpSv+zPCRAw\nM3dxFriNoTENfDma7ksVpsh5HjEA+bAgZsImfG9zJd+8yIv+r1wDpdquCVVH\nCxOQwAnUByCRCU3SZ/34wk1tYReYkGmm3Uj4IH9+yM2jYczgoabRTUqpj0om\n9HM9\r\n=8ICU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH+/q9muvEz0cbKzkqVQxWPWVNPM+CdIWSlKQN12RfwnAiEA05CWhsEuXXWsmPa3UKKUS5xGkQam3RckmZdbxWo9f4Q="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.7.2_1561264241091_0.8054231431426424"},"_hasShrinkwrap":false},"0.9.7":{"name":"state-switch","version":"0.9.7","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/index.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.8.0","pkg-jq":"^0.2.4","rollup":"^2.3.0","rollup-plugin-json":"^4.0.0","tstest":"^0.4.2"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# STATE-SWITCH\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n[![Build Status](https://travis-ci.com/huan/state-switch.svg?branch=master)](https://travis-ci.com/huan/state-switch) [![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch) [![TypeScript definitions on DefinitelyTyped](http://definitelytyped.org/badges/standard-flat.svg)](http://definitelytyped.org) [![Greenkeeper badge](https://badges.greenkeeper.io/huan/state-switch.svg)](https://greenkeeper.io/)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n\n","readmeFilename":"README.md","gitHead":"361e2dcf9c2ec7805d7238633b641f272fff9cb8","_id":"state-switch@0.9.7","_nodeVersion":"13.12.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-SkXMHNp9DFX07xrUIH6sUadaonjSc0GMkSju9/8zlJD82NfsSC+45VJnWBrBOjzKs+0OPrv+P1Sm918vZ8Wqaw==","shasum":"e59e989b9f420ccf5d25b0cca6ee77c063a0d7f0","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.9.7.tgz","fileCount":27,"unpackedSize":88753,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJejCCNCRA9TVsSAnZWagAA7uQQAJY4iysJLkxV7PgT5rey\ncdONHJ0IUtnHUtaKfIt7+C6rqikB1dlNH++PWHjDy7c7estd9DdT0muY/IEb\nNHxJg/ZxL9+gdbLaVGwILoq+lVPdiHQ/14iz8LWghQ0yKOa/4fkA8jnR1sva\ngObg5+uiFcaMMcXY/tL2pltxU+ING5Cf6flH0X9pTqVlPDdaw7Dleoc7oLg2\njOTfGlzXUyHuhLmQOkJe123ZFTa3o9gKfZborG/XwNDmbIU5Le2Idzg96/3/\nbGfv6PTCtOm/Cs/UzSIlmHvIDcjbuDuYpGoBZMzAAGQJLSQzz6Ebr7WOgKHP\nxq2SWv2AsW3jUD9INKyDuPZu3z1022dPaFojIeRBvQcWXMhQy/7XdYiME8dp\nhXtOL0spXMJ47iRLvpiIn2KbdWwtWplc+45cO9V0TM0epOeaZzXBLfe/4Sj7\nLVb/BxDYCt7UATp7HmerM38FRKF8dTyq79fd162vJeeju6er2Yq0JuTOwQel\nSJT3we0kSZYZGDPsQ/iV0QsS5E2Gssgz8KSqwYsNNm432AHfyqVM5aLIP0qB\ntZqOcLeDFDE+ulDzry2W72/RhhNo0ynfXd3v3m99CEH/D7MctquWvjK8Fzy9\n1qBxeaSC6BIOxfVHlGcD9JSskj4c3orptLHkjKWVdH3EhFMYPX5SjeDZNvJ3\n6TNj\r\n=8JIX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID3cLMttqHdkj13ccWBFa4NpJE3Xzt4SvLF6mZgJDkZtAiEA9+2iXJ1G21Hd/EWlrT0Rg4wVfT8wvf/Zbnc5y9xS3KE="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.9.7_1586241677141_0.641238546840152"},"_hasShrinkwrap":false},"0.9.8":{"name":"state-switch","version":"0.9.8","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/index.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.8.0","pkg-jq":"^0.2.4","rollup":"^2.3.0","rollup-plugin-json":"^4.0.0","tstest":"^0.4.2"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n\n","readmeFilename":"README.md","gitHead":"d2c6d624467a142e33d7c8fd10c97b75be5a82d3","_id":"state-switch@0.9.8","_nodeVersion":"13.12.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-Of80rptifbmB6XEdE/xK5HELOvZnLTITmXDxLVaeOgKWMZfyh68y6Le1mLd+s5JjVY59fT1n73WUkzqU0UUNnw==","shasum":"a02866a9b4dd07b401984572715ac206d4a82040","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.9.8.tgz","fileCount":27,"unpackedSize":88654,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJejCGqCRA9TVsSAnZWagAARicP/2WlEESadYFT4+6mPm5P\nhiyjOPu7YrFLffFiMNgLuW8UqaoOV1q4dTHfau8tFTOWsVbVB6+BdwPXcG8N\ndk943P236pnqAzm90CUc/GyN9DEj3v29pJwPd9+4mztK+Q47Ke69p1MkICia\nvPKh/qJG+mDQWHuYz8VGZaBdmtYuKupirHJvBfoftnduJ2MRUUdOV8L/cjVw\nwPsb7+FknPXHqjXOOrV4/LNzVzhbWE3pxma1u7+lIr34e4aw58wu1/+bQra0\nHkV/Q3UpNrYP5dWvZI66OMJYZoR1GaLtkuHNpufA3NBuXmaAQqL2HMmJknh7\nq9GAlvOMkZ9yjz4zH5pg6EoseYuOkk18iKlI9vJKcQ1j50l2d6JrjeqxEDoc\niRXCwbejMxU4ElsNJebdQg1exkEsjJMnN3FsmIFVu7Wu39UO2W16UIG5NGZU\nV7vHZO9hH/uP6Tzk87WMtoV5R7opavKTWBMXJmfuj9UMrVyt/CTXvu8KeT3x\ng3iyEy8gPXU0Qeb1H/MnKEI0O3wft0Kco+zAKriq8LbxfpwojxtFo4H6PO1f\nKr6+2ba194gtXBs89NslES86yYwEkUvg1rs4WCNmM2O2vLYWue/PGBHPniW3\nV/dWhcoiQ+5EaCLCvsu0OBPxweeOCrrB4AtyD22SWzPF/yxopLiN+D9qheKE\nnCN1\r\n=ZDtO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDa+iy+S/8uKsBWSJ6lotSpaNHoZ6l8PW+6Rp59hOYqVAIgX1YUwtd9T1ll/PfehUlYk2Kw3KCeDU3DVhDmVNdh/z8="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.9.8_1586241962147_0.6997219757439532"},"_hasShrinkwrap":false},"0.9.9":{"name":"state-switch","version":"0.9.9","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/index.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.8.0","pkg-jq":"^0.2.4","rollup":"^2.3.0","rollup-plugin-json":"^4.0.0","tstest":"^0.4.2"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n\n","readmeFilename":"README.md","gitHead":"c372e3953d434887a09e8a3165a37a1fd8c19282","_id":"state-switch@0.9.9","_nodeVersion":"13.12.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-BrsACn95ghmxaFxvK0W18UclYbb8e6FM8Pk3yL977HqanjfPCClMXdO3FhQzN4kPBkZvQYykWbYep369QhNzDQ==","shasum":"e4fce0196daa94498444af0d2ff90c1deed794c1","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.9.9.tgz","fileCount":27,"unpackedSize":88654,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJejCQdCRA9TVsSAnZWagAAfpMP/jfZOxLDit+TJfYMxaTl\nEY9Q4mLz5doZg+cAds+Y5uA9gnd7w3hwtdzzBlE3Exi8Z+vAjvRHjRRrFc8M\n7hepoFlYZ4lAH6vDthQo5/YM9h7bxiW868fRpZ3Bz7FvGI8GjKwOLmwm/7fb\nSCgSzJUq4XW38KCsnaKFcl4gahx8gUTR9W/w98M2J8nivZZdkNuvmgHPsgYx\ncwTLvLE4QmuQ1SM+szGZb9nJ7dNH5PpcVlJHMuqmUK6R0/a2pLQJ4a5QCO2q\n7vVBC6MHJvAduATEtuH5/Zl/NtC2TIvwht5d6p84c6vdbSOX4XWiyp3EVoxT\nq/4KTVpIovD+xZMn2Pnbni9zrDEu10d6Wjy21R+WNrcnWzPvv4vsGrBlHYiR\nQTr+oj59pkc0LjVf+mC4hDsfLMYPJk2o6izwK0OUSM4fHT8CdxEMqApk1bqZ\n5u2CZjRaWmQsZVPCn/4J7/735X8o6kTZquVnxfVPxYR6VaPvC44L8uIJsmpY\nR56DpJwMExpgpL62sS2qpwNIWpLtZ08vfNFq536Ne+a8KAUqo9e7iIRsvwYm\nDNns0LCbtdIcU+kpkLWrZD1m3PtjkvmzIWzE+yyrl32Th012t8ry2roBH10C\nDR7cMAm1lwb421+sSKzuZRbA0HKcT4dH+jJ+kqIVFDNmMu84NrjnxDxHOAKM\n0yIG\r\n=Wz/q\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF6E5I2u0Yg5xkunlKhsYGxVfOAfXN2ap+whRrQI2XeWAiEAi+m8sZDtIoOD0D0MFcpV8VKlS6/bvLuMcBUMoc8DW24="}]},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.9.9_1586242588797_0.9733119386391762"},"_hasShrinkwrap":false},"0.11.3":{"name":"state-switch","version":"0.11.3","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/src/mod.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.12.3","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.16.2","pkg-jq":"^0.2.11","rollup":"^2.50.5","rollup-plugin-json":"^4.0.0","rxjs":"^7.1.0","tsd":"^0.16.0","tstest":"^0.4.10"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `OFF`: state is off\n1. `pending ON`: state is switching from OFF to ON\n1. `ON`: state is on\n1. `pending OFF`: state is switch from ON to OFF\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'on' and 'off' events.\n\nThere have another `read()` API return a `Promise` so that you can wait the `on` of `off` events by:\n\n```ts\nawait state.ready('on')\nawait state.ready('off')\n```\n\nIf the state is already ON when you `await state.ready('on')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### master\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n\n","readmeFilename":"README.md","gitHead":"061d58c1de7832abe480f9acb7d7438450b6439b","_id":"state-switch@0.11.3","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-gKD1P5HtDIp+x7rkluz3JgCk0kOvC7nEAa7kyOKyqc8zPlBTtIu7I4I6c1c04/ayHT7Mwal+s5Ct8nxg8VSexQ==","shasum":"80322b2c9753ce17303213ee7b5e8012c33e4f77","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.11.3.tgz","fileCount":30,"unpackedSize":92584,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtHgACRA9TVsSAnZWagAAMhgQAJ6zws//xUlBS7yl9MP7\nvYAsQRN6QPSJdC0Jp69r/EPNoE83S3N0fTpPRm5pyVUoZqbPJ0HKpQl8sgK9\nA18vdXCfGixmlQ+OsoQ9j0IGSMDJ3VJJlTSA68FVEwBbkRosh/YTzt7ms2Z5\ngqa0q/iEDJ7TVMylcrpDuUHllXOEdhO+3mTZdP0y4diGC64MpS/fXcG4H7Bf\n4251VN8kwCdtEpBIN4AfCSAYVMjTlFdcdft/4x5/U0KLQsQa6MaZGOESa+tV\nFLsVhNgr/8V7ByZR/0z8hW2e79zP3jrz55Dp7gJJ1RQwJx1ncvFd8db6MmA3\nIB002p2ucuhIAADf7kXKCOMHXXj8nA8lwe9pzmPLz38V9nVXvugz69Watejc\nBVG+GBApHACZVguV3buAlBzFU9vYlx8nbGNTKOWWs41zXojiHi6YgFLrGmWl\nBMB4MeI1JCv4SwMYT2MdCUOnskC0QNh2bZCqOQ+PdpN9liGly9m57fmA9hx/\nxA5qBUgG+HZaQfcGEwNU63RyQh1QzVWCTttNVWTYoPWL+pA49HhSN702SpH6\nJr+cYVTI6c5eGSPPowHfeWdm1hKqkFvMXuUbqjNCcVvGiAHW7GvHy99fCIM2\noFxPJOxQIy+PBeQ4Mpa21Y5PvtzHBMJbgdu9izVwYBxpraNNNGbCxMm/20zm\n5W6g\r\n=wans\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDJYwYssOdsEpB6OLspF7YadYQ3Pm3BBghLnyu6vkC3mQIgShLRfLbEWkIn1YVr+qAeklEU4r9xm+Hq5LdLLf9WLm8="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.11.3_1622439936074_0.8046654870779808"},"_hasShrinkwrap":false},"0.11.4":{"name":"state-switch","version":"0.11.4","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/src/mod.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/**/*.spec.ts tests/**/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.12.3","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.16.2","pkg-jq":"^0.2.11","rollup":"^2.50.5","rollup-plugin-json":"^4.0.0","rxjs":"^7.1.0","tsd":"^0.16.0","tstest":"^0.4.10"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `OFF`: state is off\n1. `pending ON`: state is switching from OFF to ON\n1. `ON`: state is on\n1. `pending OFF`: state is switch from ON to OFF\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'on' and 'off' events.\n\nThere have another `read()` API return a `Promise` so that you can wait the `on` of `off` events by:\n\n```ts\nawait state.ready('on')\nawait state.ready('off')\n```\n\nIf the state is already ON when you `await state.ready('on')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### master\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n\n","readmeFilename":"README.md","gitHead":"0b7a1c9c32a41bb2770529af439f9495cabaf38d","_id":"state-switch@0.11.4","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-PkSVYghwaxnmqIhgSL5GTA1Ip5PIFsViV58CJQeEBZUDshFxAjC8LTX/mLTjn5RDOc5jNNAAJF/wkIvlHNcZkg==","shasum":"82bb86b734cb2807ae1ce4f28973580af7c8bb46","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.11.4.tgz","fileCount":30,"unpackedSize":92321,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgtSV1CRA9TVsSAnZWagAAqsgP/3i8KkDspu8DR954lULa\nDIzn5XHMmEtQUuNcIjdAfvZZx9alnqhtO4IEujG6Ao+R73JHhVmesy3oFeFQ\nQ6jZrrp6eNVS8uHxe517Y60JPNJbIjepFWcbOGM7zzd+HhrDLJM+T3VlXrCW\nff336brcVDIPIXQFTqTW2w4+TVrLsj2+ryRJ0gEbtwp7/DsKEIwmWwDA6JCC\njieX3itVRFEZZXhlB0TC0MOChLqWovMcOrFrZLy0bSQ9KzQiy14n1hXBABDs\nlzxhmeNW0QPG081EnMsc0Dm/frMa+8/Rqexbgt0XbkqYj3D6Oqihb/EQ97TN\nDeHZWZ+CD7UqABqDp8gKQZxjSNpSkaO638IsyswbbTPQ4lzTnIEm5i8ZHFG2\nEIqNBu5/CrM+0VNrVG8Io7dhOZIqTaM+EH4JVB20K8sLaO7VqIJou68uNajU\nI3l6mLfH7MeflnyVQS/d1OsX6awh5k0jpD0KthrHCE7Fpmzw+pDx0w9qVmJV\nwACqzaQyIuINxOjsDxxmDwJwrrpuoTOb8xEQM2A30uzf/tUBHqRwH2tPA1UC\nxalHjXq385Q9ZNHnKag7E4dMq7Rj7G5oYQQlgMq6BDaiNMPdYOXWm6Twhha7\ndJ3/t9r95HQ49McSWzbyEjzdAdQ6BlRJGVL0Z51PDtNYYIo0gwOMVPRKX4Ph\nTviI\r\n=khY3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCTnLaOpz+ChUK4s/0ptZbW6LygCHSlW6qnOpJiCCymiwIhAKPAL4q0tuWVZ6I6YtsydtPNU7rMRCIIhmUuwMMpdzNa"}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.11.4_1622484341184_0.06291613728787415"},"_hasShrinkwrap":false},"0.11.5":{"name":"state-switch","version":"0.11.5","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/src/mod.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/**/*.spec.ts tests/**/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.12.3","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.16.2","pkg-jq":"^0.2.11","rollup":"^2.50.5","rollup-plugin-json":"^4.0.0","rxjs":"^7.1.0","tsd":"^0.16.0","tstest":"^0.4.10"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `OFF`: state is off\n1. `pending ON`: state is switching from OFF to ON\n1. `ON`: state is on\n1. `pending OFF`: state is switch from ON to OFF\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'on' and 'off' events.\n\nThere have another `read()` API return a `Promise` so that you can wait the `on` of `off` events by:\n\n```ts\nawait state.ready('on')\nawait state.ready('off')\n```\n\nIf the state is already ON when you `await state.ready('on')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### master\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n\n","readmeFilename":"README.md","gitHead":"9d8b8a23a76f9d1c3d192c24dcab16a7fe13b104","_id":"state-switch@0.11.5","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-YIORjAcCD13IxuECKRzlpWYPZGfpFKAvKZkcZhyamnMhPZJm5zuaZB8ixKSYyKRZ+vCl3b33wLzE+BPv2JA8Xg==","shasum":"66df3c3d653e3c5b87b036f1649c199ac03a6d3d","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.11.5.tgz","fileCount":30,"unpackedSize":92361,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg0dyiCRA9TVsSAnZWagAAVbIP/2m/lJv6/ZUtWNR5oCI1\nd820dpFmU3Eh2Tvd7How16xSqDtnCPe+eu73XXZ2RW0VydA5O5LWwmQZv7bv\niUuCaaAhg43xIpjhdr1JURCArUB3hxdugoL4iF9V5G1Trsehy22KtbsVw12X\n+lQdz3xTDmWoIlhOCaXhHxmlD75BJAVUJBKbE5GE585Ch2sZska5lM+/GpuE\nvUtySe0uEsBsVBF+lWIlTHvQqVQbvMDSHiTmEjE0PD58rJ6rRDy6vFHqzoP6\nVKjK//0h2x5m1+0gGIzRh1h84JD3gvtHvSGKEJqgev1e4X+MElztYeOatcbK\n35IEaRYM588vaCgZP9DUr5dVKQ8wSKyPMPv/uvKc6rgvOLkegKdL/s2PyjrD\nltlaym8H7Js0nQCsIX/bvt9dBitr8k/nU3m3MeaoRMn+5eCwF+CDGCpM3EI0\nCb4Pm3P+3QGT2Y2HlPeJPwfTHB8gmOweYL/nB2VlZy1xsQr65Z5ri7HmdXzE\nfYLcaIhTF2t7Oh3cpDIX1Qq842A3JRSUAKCQxCnKD+7AKpQv/Jm9GDyywjea\nWcpFLTxSIq3QI/UNk9b2mCwH1VOMe3X3KqlywFv/jruladX0kCEIr9rCH0Y0\nL7rJ5jjm/dr4bziGu5+ju62LAvSaWWzmJGj5Sv9UdZEqGJKmSsh+lj9x/FNy\n44Q9\r\n=Q3aK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD4PICx4VFm9x2mIdSUqtlO2Bekj9eOg0xIosl9MtiUiwIgQ2JLLHiHgc7Z+cvzgKE3icrKWNUE+3aQzGXN0KUTIuk="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.11.5_1624366241675_0.7270907770482089"},"_hasShrinkwrap":false},"0.13.1":{"name":"state-switch","version":"0.13.1","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/src/mod.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/**/*.spec.ts tests/**/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.12.3","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.16.2","pkg-jq":"^0.2.11","rollup":"^2.50.5","rollup-plugin-json":"^4.0.0","rxjs":"^7.1.0","tsd":"^0.16.0","tstest":"^0.4.10"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `OFF`: state is off\n1. `pending ON`: state is switching from OFF to ON\n1. `ON`: state is on\n1. `pending OFF`: state is switch from ON to OFF\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'on' and 'off' events.\n\nThere have another `read()` API return a `Promise` so that you can wait the `on` of `off` events by:\n\n```ts\nawait state.ready('on')\nawait state.ready('off')\n```\n\nIf the state is already ON when you `await state.ready('on')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### master\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n\n","readmeFilename":"README.md","gitHead":"babc8633191099cb5f5721dd8bde5367adcd1966","_id":"state-switch@0.13.1","_nodeVersion":"16.7.0","_npmVersion":"7.20.3","dist":{"integrity":"sha512-bLb382RLgYXqySLnII459G3xUFd2cPHscpdp2sNxi8Pze5SHIT2ruqeVItV9PfCB/vv/Qu2F1QuKKNhuCbDQgw==","shasum":"318f41c5f98a23f92236743dc5433033a7872bfc","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.13.1.tgz","fileCount":30,"unpackedSize":92367,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhJi7qCRA9TVsSAnZWagAA+zsQAKTEGPcCxoj41A7cUp2e\n1vFkRNKrvu1b/LLBTNzmS5szZNE9e+8QK4TSy+p55S+hpFHHVdiMo3WWfx6C\nn4VncG32BzA5zP0spw4HTOd+phJG3cSObVw01GDz/Bu+6fHUNW342ZDr9llU\ntm/CpFXmgN130jMCqkvfJStuK0QS3woH7elRsCnCu7Ypwjj0h0ECN9tunWOt\nPrG3AXCmkrPKK03YgyDb1BsYtaPyBGEJnw0ZsKv0fwg6i+ry+k+9UqPx+QA8\n+nd+vS7MJpZYAv92weMcgK64+lW6kQZb04zfjEOydClpvSGBwkW8sFjx8yTD\n6UOx8LsFimtzycMvOztYe91gm/xTjpljn29P2JOE57N4ZeC/5Th7FSHJwOq4\noiZUWXIXfuMQn0hHHxfMUTa5C2clLqQx17GKnO++mAPEcEWYYXIEuLttWP2/\n14s9tpl2by4dpFdBBjBkSRvP9JokVOaO/V68uOwLImSe0Ol3E2QTCG58y+7f\nscdrCV2VUnNwmYivPmIKvosmySoCkC5GPDczLTKlRJCtEomennoIE7qjL5hL\nMjNqqGX9L/r58OKD8uUNh9scD7Q3QDYBfX2U5DGNQAALl5MwMrBdmTg4W9r2\neaMrYq/k+qviUssk/qsb59wh1lkOcBnhQhKJX9tM3b5erjA8UnaWsqU0Rnuz\npKNp\r\n=uJf+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIB3e9mCUSyODqos1GXLpf4D1ZQtgmgde+wHORERRRTboAiEAnpObynkZI6m6d9vGMbZAYo2Umv95cM0yT994F9UtoDs="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.13.1_1629892329925_0.24837796099463216"},"_hasShrinkwrap":false},"0.14.1":{"name":"state-switch","version":"0.14.1","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"bundles/state-switch.umd.js","types":"dist/src/mod.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run rollup && npm run dist:es6to5","dist:es6to5":"tsc --out ./bundles/state-switch.umd.js --target es5 --allowJs bundles/state-switch.es6.umd.js --lib es6,dom","build":"tsc --module es6","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"blue-tape -r ts-node/register src/**/*.spec.ts tests/**/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.12.3","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.16.2","pkg-jq":"^0.2.11","rollup":"^2.50.5","rollup-plugin-json":"^4.0.0","rxjs":"^7.1.0","tsd":"^0.16.0","tstest":"^0.4.10"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"48ae1e0b24b64407946453b85e4063550755bdde","_id":"state-switch@0.14.1","_nodeVersion":"16.7.0","_npmVersion":"7.20.3","dist":{"integrity":"sha512-jjrfbEginodItuMpma06LDWQKPQBIMpEZo8qg04NtD2qU5eIC1rrr6UUDGKPYtLT5VvR3HK12DNx7IQr4A+eXQ==","shasum":"00a6e2dcd0cfb57bbd3d138d612730646227f728","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.14.1.tgz","fileCount":30,"unpackedSize":92410,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhJi85CRA9TVsSAnZWagAA5eAQAKJeWm0EToJRPIzk2Cdn\nS+vd//cLg4QvSYG9NcMC+M6ZLV0iBix99BvtLPP7RryRkaw1nRy4rFXZ84bF\nYw5P+M3L4iJhqpb2qiezQbqvDkCIzJ6wvLCH1BRZ2aQpWfCRVha06p2Cb53v\nk1V+lwmCVkdc138xnDdV05D2yg4+xiKcmFm6Voth341FLebgi38tQenjmNEY\n4f6HxLgv59A5azOGKm2D1JMe6ZtFq0zG9JuDZ27TgDlF5RRocyGFdu/19jez\nSpnHA6Y2cWQ5CEFVNfuN2Th3/ETwjTK/bjnQyrd5P7s2PyBmIijFDmMpVKhD\nem1lGbwLxB1k0KsQjli/XcHvc9FCh+CiRNFx0HOkRln9/kSZ6A5dmq6xw+uH\nbkiQVl/la0hZ5dROcGkhTiHYVhyaJT/tCQQ/ft+fnZzRQm6nzhCNxzWrd3F5\nnhtom2zNRokM5qm22QIJfFAyXlTX6E0igE6Wl2/l3AHfRpbe6YyFgWbsv4Vw\nOIWvhOTga1IlRSyQLNzVboTfYfEkFVr3PiOdnNwu0qhwm0EH7MIauuBp78MT\nlRuv07MQCoxXaMfm+cFsUF9ojh2aZzVHWNNx3yckbCH7RpgQ3M8OHJLp1N/C\nWHGtGei1x5tpsMjFRXddYCQFxb5/Z1gH3gpUALK53202lDYrc1tRPUzI3kQM\nVgaP\r\n=7JCm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAZZOdpbXCazUa5LuroFH+htvCQKy+Sbr1aXzpdGrcB8AiBsTLLn/Nw4le9WRbF2Ocf2UJskyX7SqmaE9rmN7Ef/ag=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.14.1_1629892409793_0.9660247012775678"},"_hasShrinkwrap":false},"0.15.7":{"name":"state-switch","version":"0.15.7","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"./dist/cjs/src/mod.js","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && (cd dist/cjs; npm init -y > /dev/null)","build":"tsc && tsc -p tsconfig.cjs.json","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"tap --node-arg=--loader=ts-node/esm src/**/*.spec.ts tests/**/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.13.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.16.2","pkg-jq":"^0.2.11","rollup":"^2.56.3","rollup-plugin-json":"^4.0.0","rxjs":"^7.3.0","tsd":"^0.17.0","tstest":"^0.5.16"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `OFF`: state is off\n1. `pending ON`: state is switching from OFF to ON\n1. `ON`: state is on\n1. `pending OFF`: state is switch from ON to OFF\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'on' and 'off' events.\n\nThere have another `read()` API return a `Promise` so that you can wait the `on` of `off` events by:\n\n```ts\nawait state.ready('on')\nawait state.ready('off')\n```\n\nIf the state is already ON when you `await state.ready('on')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### master v0.15\n\nPublish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"902fbae69f600a5531d361ee756cfb9a03a766fb","_id":"state-switch@0.15.7","_nodeVersion":"16.7.0","_npmVersion":"7.20.3","dist":{"integrity":"sha512-hsIHe+2gHxltSceCJ84m68TozAy92EdBgyQYgcw+H9Bas1GM8xoLJNSGiJYnwes/1mnxZs6eYUmkF5kYRd2lGA==","shasum":"e4fc810df5604f2d0b5f5ff9965a39ac1dad7547","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.15.7.tgz","fileCount":46,"unpackedSize":85405,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhJnelCRA9TVsSAnZWagAAUKsP/jK3WpRSFTKfrr939mEH\ne49Vq0eqmKCkBz5K6XFfqkvekV5+AIjFinYcRcr0L+F22ql3Z/RpcFQl1vo1\n9Ck65GynJoGqnaoHb8tT79BQ8gYQ1PpficSZNxUkEuDxfJSYT1wT6CTvIQqr\ne+c0wrKyQjHG0GIs7rz9MlKZ0Je9ImLPqpCfy3vsbYgakLDm74MhYZzRf5Rt\nGVcNmYnBU4Igb1n9OV3/3yvGBTr9JGHG2vKVziQg1ad9Cp0I5aOFGetDQqsA\ni6gRq4yur8ukdjnDCYdvnaGUzXu0qWzCpIQDX4VhkFKssDuFftDnJqy4BBVq\nFPpIl7O+nWFLxK8xTsOWyQC6wvaumEokSPuFuWrty23vRhb7lISYsaCPij7Z\n8iEY1cG7tY22EitBqdiPX+z5Z3bVmbCttc4TbUkpTFQipQUkoSS3gHm1uS8r\npyHLa0G0vNwKgwpR/wgfqGxNBDN4K8v6iB12+iHCxQQgKh/k+L0Acg5DzXaw\nydxLAwlQpTG/SxVjlOuGmlvmMxFeDxG5zbyjQ7/1W1WNKlRFMw5UmVtPgmHw\nT7mksMqWszbWSPeigszy5V4hFcgD3Vu+Q+4HZm8VZvh+a4FwAtnhmbfX4MUN\ncTxvw9a+8iwq/eDD+WMpvV+mNv6OZX8kCs/o9AuXs30fSHbntBmZC/fMrdPJ\nIGqb\r\n=B0CR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGM1OM3hgnNe/II7AywDT0ceHusXUjfk2rLafKI6ESdCAiEAyoLjKs/M/OlMbvmlKqPX67n/JmtMziVJV2GxJg3Z9Do="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.15.7_1629910949127_0.3081334915185805"},"_hasShrinkwrap":false},"0.15.8":{"name":"state-switch","version":"0.15.8","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"./dist/cjs/src/mod.js","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && (cd dist/cjs; npm init -y > /dev/null)","build":"tsc && tsc -p tsconfig.cjs.json","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"tap --node-arg=--loader=ts-node/esm src/**/*.spec.ts tests/**/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.13.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.16.2","pkg-jq":"^0.2.11","rollup":"^2.56.3","rollup-plugin-json":"^4.0.0","rxjs":"^7.3.0","tsd":"^0.17.0","tstest":"^0.5.16"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `OFF`: state is off\n1. `pending ON`: state is switching from OFF to ON\n1. `ON`: state is on\n1. `pending OFF`: state is switch from ON to OFF\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'on' and 'off' events.\n\nThere have another `read()` API return a `Promise` so that you can wait the `on` of `off` events by:\n\n```ts\nawait state.ready('on')\nawait state.ready('off')\n```\n\nIf the state is already ON when you `await state.ready('on')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### master v0.15\n\nPublish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"b53b2fe35a63e554234fda5f5719534478688da6","_id":"state-switch@0.15.8","_nodeVersion":"16.7.0","_npmVersion":"7.20.3","dist":{"integrity":"sha512-hJK+mXZCJuwygV7cxVZtq1+KkUTbFraq2DM0G8/zAvHmRorLQrte4EYH6q7HQznuJpQVHtYc93MixrLve/ciVQ==","shasum":"20e4ee77ccf97dce4cc26b4c6f864a2421c4707e","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.15.8.tgz","fileCount":46,"unpackedSize":85405,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhJnoUCRA9TVsSAnZWagAAFiQQAIyYoFoTlS0X8/ofv/TY\nFPOWn1Eltc7uIGw6TPpkRnkv23ahtDyKpR2yRWStMgMgUX+ZuJUVLfVzrEou\nuxcxPHwpr2uWNzkIpf+v7ay+AuFx4HKhxcK5mYs9y8MD0/L0rwi+jAt6ai45\nFP5o0X8L9hg2Bzs8TMw/zV4087XQsMDzy2EnlGsiikaq6/hSeQNC1reIWJix\nbbxuKrWd4vCwHsLCQLN6Kmlt54knMHXkeQeqBqWU26MvzYnI0dZTU8cdCuky\niuTA6ztfhN1xyHp/MJO11N74vEIXu7swtbgB1jPwZPslLyZ6zVTsnC0msIvx\nyooS/Jh2XokKzMmHE5PAWxInBqJorCXq44HOc5eoX2FtlLcdULyCDEL8kw7e\nrlvcs2JqA2u6dapEm1DVXTpvrVuhxe6v23TqsHVb5ZKfGkZlE1lF+KjUDLEp\n2ZKqTI3SDTvy4KP2fVE0VhrrwFAiQHyzyQH1BWPeFMnsPHPSrG/+v+p/zst4\nxPzUfRlJ0R1zLVHU8fvcWdpq8g7Mg11ULLecZ0zSX8D4Uq70+dcgPNyKUfKw\nvDslJDW0u1USTOdCr1dsUVo7P+ItiCz433wBiSprhitAcEcQndKvR3aaomq0\n9aBt9QQ00xEMVbWS0gwzSLIiDR5IeSiSP+YcZz2bJ4WonjvEDFjqRIeB0dwH\nzoU/\r\n=vTQN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD/k31nAiwhCsX5AMClw1L6uydycroyM0xqIbgEK+gfjwIgE/hfM1zZgE4tlq4dYh/lFnSsefuiWZqz8/HJ2cYGl50="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.15.8_1629911572716_0.3084447306483"},"_hasShrinkwrap":false},"0.15.9":{"name":"state-switch","version":"0.15.9","description":"State Switch is a Change Monitor/Guarder for Async Actions.","main":"./dist/cjs/src/mod.js","typings":"./dist/esm/src/mod.d.ts","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && (cd dist/cjs; npm init -y > /dev/null)","build":"tsc && tsc -p tsconfig.cjs.json","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"tap --node-arg=--loader=ts-node/esm src/**/*.spec.ts tests/**/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.13.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.16.2","pkg-jq":"^0.2.11","rollup":"^2.56.3","rollup-plugin-json":"^4.0.0","rxjs":"^7.3.0","tsd":"^0.17.0","tstest":"^0.5.16"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `OFF`: state is off\n1. `pending ON`: state is switching from OFF to ON\n1. `ON`: state is on\n1. `pending OFF`: state is switch from ON to OFF\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'on' and 'off' events.\n\nThere have another `read()` API return a `Promise` so that you can wait the `on` of `off` events by:\n\n```ts\nawait state.ready('on')\nawait state.ready('off')\n```\n\nIf the state is already ON when you `await state.ready('on')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### master v0.15\n\nPublish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"e3ef4fbe32fc14fd62f4e0244851833078eb1ea0","_id":"state-switch@0.15.9","_nodeVersion":"16.7.0","_npmVersion":"7.20.3","dist":{"integrity":"sha512-Em4Xnm4JvB25MPoZsEQOKXUSQNITpgp5HZiI1KzRFpl7qFM2Gk9B/+I11F77nnfPAk0Nvp9fWaWcLHtaOe2NVQ==","shasum":"98f0f6055cf6af0e27bbc89dd316916315534363","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.15.9.tgz","fileCount":46,"unpackedSize":85405,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhJo5qCRA9TVsSAnZWagAAtuUP/jQ6Kcc3yaCl+aKpBWKU\nwbfvyCTq1BEyHVicg6avhFf6XG6/3poRLHc/JZjaU3ZPc+Wz77wmGP5hYBc8\nSxgp8tO73Ni7d2YhWI1iPWx+duU9sCuKuQTvTgOAObjPgtnG7ynfhqJwWcbL\nJAHkuhUa36r2Romvmgc5hwx6UD28MZg7uLoznGbDq1n8o19+p3tAj/TM17d4\n9XeDyDaMkHBGOj6nQGr3gYo0OTvBrTgNmPafib5LD4mOCPb+xjdP+1KSWZNJ\nvBOtsmtLlu4/t2sslrIMVGGdIOIjWO5JN+4O84eYCmj7odul3lmH3/50Ixx4\nJhH6SVLHibYCQlMgABrQVWLfRBs4XfmWwS7XDMT5ANIWQcHFF7HSEm7qPfr7\nQpXapzkHdyRRlBJgN8jYAmUM6KnbQhz9JArXNIDPEjpvi8ZzEhMNreTMjV09\nBX+8JuuunjbZ8qE5qbwQ7T22x18KoP5xJkvFNjHKAqpm5/iuWWvZRLDBsbtY\nJ2yyK9dETFsgJjrNWym43Koml/MfM/bV+gT9Ks3oT2rgWHlEmQ0Hm84yfaFP\nxYJ6qpj2wkd+xAp2OYlQET7w9Dgz3NJJkA5Otjl/FNBmlhRwI3c3PKkBWWQ3\n1cS8aYnVPcI96yP6N9bksly/p0oc4ggZzx2gl+qUxFuM2yBfkIIX3qX5a0+7\nfiwQ\r\n=zWG6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD+mnaZ+VAMaUMwIIBqCOoK3VQL8wpeBgwDch20ykxWPQIhALKx0yUkKGI2i5JRvAxYi+qmdvK6bP+bWxtsOVHJcXJY"}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.15.9_1629916778545_0.27821698717414667"},"_hasShrinkwrap":false},"0.15.10":{"name":"state-switch","version":"0.15.10","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run fixup","fixup":"echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json","build":"tsc && tsc -p tsconfig.cjs.json","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"tap --node-arg=--loader=ts-node/esm src/**/*.spec.ts tests/**/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.13.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.16.2","pkg-jq":"^0.2.11","rollup":"^2.56.3","rollup-plugin-json":"^4.0.0","rxjs":"^7.3.0","tsd":"^0.17.0","tstest":"^0.5.16"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `OFF`: state is off\n1. `pending ON`: state is switching from OFF to ON\n1. `ON`: state is on\n1. `pending OFF`: state is switch from ON to OFF\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'on' and 'off' events.\n\nThere have another `read()` API return a `Promise` so that you can wait the `on` of `off` events by:\n\n```ts\nawait state.ready('on')\nawait state.ready('off')\n```\n\nIf the state is already ON when you `await state.ready('on')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### master v0.15\n\nPublish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"fc430632603c34739fa3fb5ef2d018e06d7e4f89","_id":"state-switch@0.15.10","_nodeVersion":"16.7.0","_npmVersion":"7.20.3","dist":{"integrity":"sha512-2pe2RWJjjTrnU/4KudPs7qjkqCWNF7FThRGtEj4NFG9r0O6TpaygiZO7WA8om6T3lPPO1QvkYicsBxIUDmXXmA==","shasum":"7f8552f9fe4063db11afa2a3108b7bd78ab23df3","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.15.10.tgz","fileCount":46,"unpackedSize":85181,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhJwNaCRA9TVsSAnZWagAA6z0P/2O3+71IYGg4WGlv0dts\nQof7t6wNXngE/5bM+dgNuMEdNMTJVPBoW2HCtXv+jEYDCfDkNiiih3kKn4z9\n5ERD4JLgSQPNpinSjBOyGWDTSwsUO0ytuPQAP//hrik7lhjQQJxCjkGSEfEU\noKgzxtc4HwJPnpqnkDe7Y9fNiC4Yun7VDu9Ow5Mc2YW8tjrUEDgoJMdW/meA\nexwHSiUVWidtPqz61Reer8RbDStH2pT6VI69Ix8gjAsNkSA/zVd3kBKoYNqs\nc1eMmNZGLrBasTkltIDoYlgWuQlWnKWtuLElL7Gh+PoJdkLASCnt5WFQYKlm\nw70fQqq2giMbI9Fu/MF5C+8nnlx9otkcsAg3EsPLtQAFVAVcmlgzJEAGoxeu\nJO+V8q1aK5N9aHXEjyIhZRQ18LQdFlCgQFQEQmp+0wSG0YKJ32zott55a6P6\no3C/xddOLfrrCIyBmzdoc8cjnR9NiqHAR5oPRShh73mAmKqyC5Ngzk8mrSw2\nJM/j0TAm9PtIJZ1yw8Ma14avEhWllSlplXmxSiGc6Yg8oZw2jRxcx41hxfB3\ncJrwhnutSUIMFeHO9oM/WCU33tWE+EKnkGnwh7fB8Sk4nP2KJLDnSdihT/5v\nW1gV1QSxwp4MvLAr392hOCRCaOasYL4FkL8bnUokaQRVZbQBHWgf+jGfl/WJ\nbvli\r\n=OmEy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEZXXohtBi4G5BoWfwLVvaQFfBXMqCnWltF8F3/J9Zf4AiAXoxR/5aJc2oEKO+I5TzFDjsnjuGX/8pN6S76J9Ysm+Q=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.15.10_1629946714544_0.00867515312045164"},"_hasShrinkwrap":false},"0.17.1":{"name":"state-switch","version":"0.17.1","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run fixup","fixup":"echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json","build":"tsc && tsc -p tsconfig.cjs.json","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"tap --node-arg=--loader=ts-node/esm src/**/*.spec.ts tests/**/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.13.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.16.2","pkg-jq":"^0.2.11","rollup":"^2.56.3","rollup-plugin-json":"^4.0.0","rxjs":"^7.3.0","tsd":"^0.17.0","tstest":"^0.7.3"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `OFF`: state is off\n1. `pending ON`: state is switching from OFF to ON\n1. `ON`: state is on\n1. `pending OFF`: state is switch from ON to OFF\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'on' and 'off' events.\n\nThere have another `read()` API return a `Promise` so that you can wait the `on` of `off` events by:\n\n```ts\nawait state.ready('on')\nawait state.ready('off')\n```\n\nIf the state is already ON when you `await state.ready('on')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### ready(expectedState='on', noCross=false): Promise<void>\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## CHANGELOG\n\n### master v0.15\n\nPublish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n* Before: `ready(state, crossWait=false)`\n* AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (http://linkedin.com/in/zixia)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n* Code & Docs 2016-2017© zixia\n* Code released under the Apache-2.0 license\n* Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"bec741e360081a67024cae44137b6931d41730b8","_id":"state-switch@0.17.1","_nodeVersion":"16.11.1","_npmVersion":"8.0.0","dist":{"integrity":"sha512-ScSgd5z1hbR4fO9XXNR6X8XLrPHUDA623RRWwkycJV837reCnxE5SKzdYlxGUwLEhjVWiqEeXL2ChMULSM5D4w==","shasum":"1448a2ebf5017b2b2551a2ab694b0a931c8d1711","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.17.1.tgz","fileCount":46,"unpackedSize":89943,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA8cLQwEdAA8GVKpwqEkP1cXrtI3fYSfD7dW2DsXDKQqAiEAwxCtJn2KbjwB4zpXmkonUYueem0vHPWtVLK+5QZCfU4="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.17.1_1634276496206_0.18601530082302808"},"_hasShrinkwrap":false},"0.18.1":{"name":"state-switch","version":"0.18.1","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run fixup","fixup":"echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json","build":"tsc && tsc -p tsconfig.cjs.json","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"tap --node-arg=--loader=ts-node/esm src/**/*.spec.ts tests/**/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.13.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.16.2","pkg-jq":"^0.2.11","rollup":"^2.56.3","rollup-plugin-json":"^4.0.0","rxjs":"^7.3.0","tsd":"^0.17.0","tstest":"^0.7.3"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"6a49f6cd932e6aacdbd74022b0ed907b0f179be2","_id":"state-switch@0.18.1","_nodeVersion":"16.11.1","_npmVersion":"8.0.0","dist":{"integrity":"sha512-/4gH0PbKsGdKHT3x997sWlGA24KnOkmjeY0T+NgzDztaarl/CsiLDtqUxXDV3fgTcpdjALS+OPvdGVZWLq9jig==","shasum":"0fbd97abf5b7c9bfdeb13eeace78df2f92866f96","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-0.18.1.tgz","fileCount":46,"unpackedSize":89945,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG0aFJQ6N92BnfEb+9EWIx1mIhxI580/WKXl/Ql2ycFjAiBCzPNFUZnXqswOdRS15y+MkBzEeFrMRwG701oqTt+eJA=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_0.18.1_1634397179468_0.8188197406967404"},"_hasShrinkwrap":false},"1.0.2":{"name":"state-switch","version":"1.0.2","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","scripts":{"clean":"rm -fr dist/* bundles/*","dist":"npm run clean && npm run build && npm run fixup","fixup":"echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json","build":"tsc && tsc -p tsconfig.cjs.json","lint":"npm run lint:es && npm run lint:ts","rollup":"rollup -c","lint:ts":"tsc --noEmit","demo":"ts-node example/demo","test":"npm run lint && npm run test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"tap --node-arg=--loader=ts-node/esm src/**/*.spec.ts tests/**/*.spec.ts","lint:es":"eslint --ignore-pattern fixtures/ 'src/**/*.ts' 'tests/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^0.13.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.16.2","pkg-jq":"^0.2.11","rollup":"^2.56.3","rollup-plugin-json":"^4.0.0","rxjs":"^7.3.0","tsd":"^0.17.0","tstest":"^0.7.3"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"4c73cfcb551739348628b22a1b91bdee3932a3df","_id":"state-switch@1.0.2","_nodeVersion":"16.12.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-25h9c1A6LYu4H0TPBNaVmsRJl1g60bDcd0c8FK+9w9V4IVa42AFBz1ANC17Fhcu/Megv6iMUgDRqesVAuxhiSQ==","shasum":"36140b503cee24cc50fd1641a156a506e1c1ebdc","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.0.2.tgz","fileCount":60,"unpackedSize":103463,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDX1P0NyOZx0FQMJR6pDBRLq+8OMXHIDCdCNQdIU7uXnwIhAM9wfas00Ng4iXKgFnt+aAgMnWKPv2Xl2BEsEaVpEajL"}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.0.2_1634972247559_0.4526773329086651"},"_hasShrinkwrap":false},"1.0.4":{"name":"state-switch","version":"1.0.4","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","pkg-jq":"^0.2.11","rxjs":"^7.4.0","tsd":"^0.18.0","tstest":"^0.7.3"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"81e4ddd69af7082ded150d05170e22871ccfa2cd","_id":"state-switch@1.0.4","_nodeVersion":"16.12.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-xuLEtLL8Nt07vFaBqjeZ9+L2xo/QEQl+glG+rHXlf8ZMALbtyPs1dAeg1AaAHRvsXfKwOGLwksnKVglvLUNZaQ==","shasum":"c710ae7ca86791c2bb5c27ffd6d5438870fd3777","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.0.4.tgz","fileCount":74,"unpackedSize":109898,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGS2Vbc8DXNEbsrOygNCyqTMnDeaKPrXZwxDu5oWfMgzAiAWOF38HozI+FayfWirl8f55nstdwgcUJ8+Kvh/F4P/Lg=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.0.4_1635013063885_0.8234832098072669"},"_hasShrinkwrap":false},"1.0.5":{"name":"state-switch","version":"1.0.5","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","pkg-jq":"^0.2.11","rxjs":"^7.4.0","tsd":"^0.18.0","tstest":"^0.7.3"},"dependencies":{"nop":"^1.0.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"f2aa2b4181924f8341d3ca82e92aebb260b313e7","_id":"state-switch@1.0.5","_nodeVersion":"16.12.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-ekWggoir0AlhEYk8ZpoLhUyS75T3eR3wOP/UUSH4IdPg7+impi0OU5mZj2+B9/h5c1SG1DdRfLNJpnCm02htgQ==","shasum":"877b94c29dae1d37c72e18e444dca3d8842c01dc","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.0.5.tgz","fileCount":74,"unpackedSize":109937,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDmjRvtswd/W5Gazt0zw0fP8GPpNzQFtj4kJ4ix/hbEywIhAIxkBs5EPuNz3QiBecAXAcipvfWm5reqIef4SoL+5aez"}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.0.5_1635013110966_0.3683624993478154"},"_hasShrinkwrap":false},"1.0.14":{"name":"state-switch","version":"1.0.14","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0"},"peerDependencies":{"rxjs":"^7.4.0"},"dependencies":{"clone-class":"^1.0.2","nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"7c8f02e0c1898eaaf203d32d76dba9659575c039","_id":"state-switch@1.0.14","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-D5ia+A4Gc0KTtMy5XiMsslYo2sDIiYCQGEOnQTMRANF2mG8m+S09S0wAU571qvPeKiYqGrCUJa3zMhcWX58GZA==","shasum":"da21b4ea73d133e85bda7042f2925b8b1bf2de94","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.0.14.tgz","fileCount":136,"unpackedSize":172806,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCUWV9dgzGX6Q+IbHcjEA+7fEq8n5mF7I5H9Laqf9mmRgIgbt8n+NJp+PA+AcVLGmubdV/GkpYOswPTTH436R6Kap8="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.0.14_1635270835625_0.657004171225047"},"_hasShrinkwrap":false},"1.0.15":{"name":"state-switch","version":"1.0.15","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0"},"peerDependencies":{"rxjs":"^7.4.0"},"dependencies":{"clone-class":"^1.0.2","nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"374d5449a750f26247559e18e9fdedff4c7d5db3","_id":"state-switch@1.0.15","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-9loIZ4Xkgw+3j+FgGVpSum+fiZZ9gdTuc9T8BbJrFZLKGBv/euZGMROdf6GRmo+046CEHeSoEoVXKOhYt6TJMg==","shasum":"c5d4186526a7bdc8d557bcf6bdfc6a03b95dbf22","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.0.15.tgz","fileCount":171,"unpackedSize":227946,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCqjV48hcrbFml4RMRZ4eJ47Bmk26vlJ8uuQ7mHnukcowIgC7XEjLyYMaISi7XJy+DCBsBAiIK58hI/o5USato/81E="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.0.15_1635275474123_0.7691520806230601"},"_hasShrinkwrap":false},"1.0.16":{"name":"state-switch","version":"1.0.16","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:ts","test:pack":"bash -x scripts/npm-pack-testing.sh","test:ts":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0"},"peerDependencies":{"rxjs":"^7.4.0"},"dependencies":{"clone-class":"^1.0.2","nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"6a3d854a530b3ef300c3eea0fb9369d10cda7d8f","_id":"state-switch@1.0.16","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-EHFgtzSxKRsLU/TuzWO5STL9sY8PQkTkRwKgqbk9gAxv2Q8T4yvjvkMHQo/99cAh7O4pT9xAs2G2vv1elerJlw==","shasum":"5397637451691ac1428f20eda6e98c694c0e770e","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.0.16.tgz","fileCount":171,"unpackedSize":227246,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDJYnVTCQ6auxUPAmrspqmh0+iWWovehXXBhlQSdLtliAIgLXpSf9tvCK5qzMild/9WZMAb70vK7uy8ssar6OCW8TM="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.0.16_1635276600971_0.43307827581321656"},"_hasShrinkwrap":false},"1.1.2":{"name":"state-switch","version":"1.1.2","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0"},"peerDependencies":{"brolog":"^1.13.3","rxjs":"^7.4.0"},"dependencies":{"clone-class":"^1.0.2","nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `OFF`: state is off\n1. `pending ON`: state is switching from OFF to ON\n1. `ON`: state is on\n1. `pending OFF`: state is switch from ON to OFF\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'on' and 'off' events.\n\nThere have another `read()` API return a `Promise` so that you can wait the `on` of `off` events by:\n\n```ts\nawait state.ready('on')\nawait state.ready('off')\n```\n\nIf the state is already ON when you `await state.ready('on')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.off() === true) {\n      this.state.on('pending')\n\n      doSlowConnect().then(() => {\n        this.state.on(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.on() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.on() === true) {\n      this.state.off('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.off(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.on() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.off() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.off() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### on(): boolean | 'pending'\n\nGet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process). `false` for not ON.\n\n### on(state: true | 'pending'): void\n\nSet the state for `ON`: `true` for ON(stable), `pending` for ON(in-process).\n\n### off(): boolean | 'pending'\n\nGet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process). `false` for not OFF.\n\n### off(state: true | 'pending'): void\n\nSet the state for `OFF`: `true` for OFF(stable), `pending` for OFF(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async on fly.\n\n### `ready(expectedState='on', noCross=false): Promise<void>`\n\n1. `expectedState`: `'on' | 'off'`, default is `on`\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be ready.\n\nIf set `noCross` to `true`, then `ready()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` when you call `ready('on', true)` when the `on() === 'off'`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(log: Brolog | Npmlog)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl (ServiceCtlMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nclass MyService extends ServiceCtlMixin(Service) {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'on').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"d95bd881c7ce9a1fb69580d0a9e833a0381851bf","_id":"state-switch@1.1.2","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-uPsmUwac1xnLXAHuK027Z/+17NneOwfRSibjjAOH1/d8FKJHRHVy5x8PFrV6VYjyfS72Wqoi+MOnF7pSwMsrzQ==","shasum":"7cc35aaf0970d46ad5304a44526083ffac99ae39","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.2.tgz","fileCount":164,"unpackedSize":233678,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIE2qFfe2lMGH380Nb82iGTQSl8knJRwT5sUbCJnOJbPFAiAj4NGLlSco+Fo5qkjJeFYTqMoIV+eyHAz7gfyy7Xyyuw=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.2_1635317085050_0.9195307108108206"},"_hasShrinkwrap":false},"1.1.3":{"name":"state-switch","version":"1.1.3","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0"},"peerDependencies":{"brolog":"^1.13.3","rxjs":"^7.4.0"},"dependencies":{"clone-class":"^1.0.2","nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"29c01701df9dc0ebfaa7a81ec79a2e9fe157e6ee","_id":"state-switch@1.1.3","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-93483kM/+P5cGPikr9JTyZIKLxXJe+YY2XBf2oChgOSB823Hu+NXISkkHzYJFGzju4pxqPX7pGXAyZvFi0oYMQ==","shasum":"a95e9005b3470f1581e28f6203b2b088caee659b","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.3.tgz","fileCount":164,"unpackedSize":234372,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGeCQ5kFYYWb0tU6Ic5UsJgw5bGWXMO8tqfbb1XsFkR+AiEAtoKRNkFTEKpGzrzrZKrVLUHXaOZ7Oe0Ecp4TyHw0gds="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.3_1635317860301_0.16685900102987183"},"_hasShrinkwrap":false},"1.1.4":{"name":"state-switch","version":"1.1.4","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0"},"peerDependencies":{"brolog":"^1.13.3","rxjs":"^7.4.0"},"dependencies":{"clone-class":"^1.0.2","nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"b32d88ead777db683e83071e9bb6ad4bc72c8d2c","_id":"state-switch@1.1.4","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-cOTuYtfwTMBGaJ6yjZN/xwgknVZ5Fo7Q3quxU0OEmuzRbvY6FYISRLaD62sPPCmXIK7uP0DpMAK6PeB4iG+Aww==","shasum":"d018352c88ecc0f7e92476c91be6ae378310a845","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.4.tgz","fileCount":164,"unpackedSize":235622,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDBNjxNwSJ7eb9DLdWgcq1o2qGEhmh0zRWQCxYzb9fCdwIgWpKa6B0xYpwmcqQfOFhHWcjomSwx6KbkgpcDS2F5/dY="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.4_1635318342319_0.08043896221988112"},"_hasShrinkwrap":false},"1.1.5":{"name":"state-switch","version":"1.1.5","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.3","rxjs":"^7.4.0"},"dependencies":{"clone-class":"^1.0.2","nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"f289d4d2e1f771c7498389e370db66629bd3aad7","_id":"state-switch@1.1.5","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-j7rELlaL5k6/1h8tArYWQ8SHgWogcP8cqoQJOPjcgNJfdbloUzHsFMGaP9Nra2c7HrBRP06hxVs+3/Xun2qg6A==","shasum":"ada5568176a1ff4b8c18fffd893f48dbb16f6207","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.5.tgz","fileCount":164,"unpackedSize":243132,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICITlpiygOtt4qFu6B1tyagsKwxI9fPswudkFfAI9dFPAiAPwkfQP/FrNmF7v0P1Q2nhZbMWSI20Pu88EBPKZhKSxA=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.5_1635319682954_0.07728732936006999"},"_hasShrinkwrap":false},"1.1.6":{"name":"state-switch","version":"1.1.6","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.3","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","clone-class":"^1.0.2","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"2b0e22e050b7c0fe7d002dffabf67f941869cf18","_id":"state-switch@1.1.6","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-KBpjOXApDI+3TYLHD1ySgy6SqPNpN0fxJpUFMWO0yafAYV3CJFL21vQg8P3BMZw+nYGEgajmTdBPQwpIrZKvtw==","shasum":"79e0066d1e29ad381635efc233fabea55f548db3","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.6.tgz","fileCount":210,"unpackedSize":266171,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIElliQCCo4abheUBKXmE34Xncluou/ecb6rChu7h7gBQAiBAnobJTcXSN/4g+4rOY1vQ51UzE2JAIdYQ5y7OJdOcfQ=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.6_1635330334383_0.1956983874538587"},"_hasShrinkwrap":false},"1.1.7":{"name":"state-switch","version":"1.1.7","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.3","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"e908b8e229523f88f579d3e113cfd36d0babc413","_id":"state-switch@1.1.7","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-yMPkYl6h/Oxl/BDUgfPH//3sCh5klJoz5dcj3PxqbUGkQq/56lv/RJUhxI+o0X6xJSEpddlKQ0JR2PrJ7uB0bg==","shasum":"a3a83e5751e4b05ec462a6222f5460345ea7423f","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.7.tgz","fileCount":210,"unpackedSize":266486,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIF1IVCe0W/Tb45038tkihLzpUIwn59GqOLX0+pa/3q5UAiBRTGBR3IfvZtFzGpaLFmhveGTc3wMPMKspkgdWnyirHA=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.7_1635330732270_0.9398139658802402"},"_hasShrinkwrap":false},"1.1.8":{"name":"state-switch","version":"1.1.8","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"012bb7a4ad1754ca662e4cce83a2530a16697278","_id":"state-switch@1.1.8","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-SL4eyygR7qsqbfDki/xdkVnMM/AYg6SUBg0C+j7YglY1Vxg0gNC9ZZB44CvrYnM6DJD6Hf4WAJTrOLmpK/k8PA==","shasum":"40f5e203efe3ba9d1f6fd44125150f6d2e3995fe","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.8.tgz","fileCount":201,"unpackedSize":275666,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDtuSpGZGc30vAaSnOahQH65PZPsqFnCmwBwcnFwhbhzgIgfiUo7EadqgSeNpO2FZJueZlkIJhVDetsl0xTeEBA98s="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.8_1635335414045_0.7550094459131069"},"_hasShrinkwrap":false},"1.1.9":{"name":"state-switch","version":"1.1.9","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"eaccc80a74a72cbbd0d1ac8b6da16b85a0ceae7e","_id":"state-switch@1.1.9","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-DghD5l3sl9AGBDFhGIa2fGDHJRsWYeLVe+jeNrYj8rJZG+0eBG50iAjcl+bYkw9ueidE8j2eXCoBL0zlK+ZHLA==","shasum":"d02063bc02c929e0f4ebd28d9d8eb76a1fbe4b3e","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.9.tgz","fileCount":201,"unpackedSize":275716,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCT6qnX6xruoQ/O++6JecxnVzqE/pbq9HmopoTzc3EDLAIhALbCIw88o7obCr4ab0RXyiAimOq0dZ9NyP8jh2KSogHF"}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.9_1635394137676_0.496565981450255"},"_hasShrinkwrap":false},"1.1.10":{"name":"state-switch","version":"1.1.10","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"0aa22ef8cab2e788e08980fee4ec5e86248d0e62","_id":"state-switch@1.1.10","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-fS5yEJ7eqLlQ9qXY7rnM3yJJdnZ4tJV02X+Xi4Evj+EGHXDurwgDiIf0JvHyc3Q2n1b/FGVG+Wj/yvyNcVkFdw==","shasum":"0014a8dab7dffd48f1fae91df090c9bf19e2a9f9","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.10.tgz","fileCount":201,"unpackedSize":276444,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEWLgy2EIKJCZxknjheugEh42eM75ciia/NcVM3c8gVgAiEA0OHjUZXdJDbw0S1olATGsK/u1C8TUBgrewEIiZWljhw="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.10_1635394660083_0.9491162764123708"},"_hasShrinkwrap":false},"1.1.11":{"name":"state-switch","version":"1.1.11","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"8ec00d499a47bb4cb4dfbe9da81c99427875be53","_id":"state-switch@1.1.11","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-6WY6Ov53YssGqFj9imzpRJ0ksPCsTdIXbITAsw087suD+WxzRsGaKVeiLplOV8ZYB38Yyo2MEsQ4Bkq7X03KQQ==","shasum":"a1b28dca34397c63fe78bf7a36556f6f0cb8d99a","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.11.tgz","fileCount":201,"unpackedSize":276498,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC8ZLMKcuKg322nd2LNX8wOYWxF9XZyxBO6x60hS8wA8QIgS6VoS0YMhF4uiog0pSoiUOFzDagbcb1ueq0FvOyp8b0="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.11_1635394795135_0.9289170199714019"},"_hasShrinkwrap":false},"1.1.12":{"name":"state-switch","version":"1.1.12","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"0d98620b1253a8d4a0390ac714cd6f7313847bd8","_id":"state-switch@1.1.12","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-20JaKYT+xqvm/N1ZlbtiaTLkjfiOGvt3ikB3gBnu+ZM+Yrrn4WpRLCH4ogIZIlvJtCR2K3FX++1FYt16bpOW2g==","shasum":"587cb7cab3137d3517b730c211a16979e363058d","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.12.tgz","fileCount":201,"unpackedSize":278136,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGKp8l5Z3GwbeE7qn7hnJStVK+dDMf+GSPoBIzVUFTKSAiAfyW1qDIKFYubXpTQtDo+TFD0eTLmB6A0NSWXFV5VQLA=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.12_1635394895483_0.8239283457786613"},"_hasShrinkwrap":false},"1.1.13":{"name":"state-switch","version":"1.1.13","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"d0eb25f67ab624411b4fb0625991be2c2af2aeb3","_id":"state-switch@1.1.13","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-gXYT8LJPPpqy3TE5pOgexHOg1PCmwenE9h4Whv/i0qs7yv7r6HfrQoOBUQOd866RnHGBOnMaRYrWc3okMN1pGA==","shasum":"41e08dec85eb945135a7768a6ed141f6b46fa4c8","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.13.tgz","fileCount":201,"unpackedSize":281255,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIA53dN34l+gPB4PWNU+z1eIx/xI1azXfFGZdsMXV9Dq1AiA9p+ueZ7WD9XSFX2HiursmqGLYSRCVZogWm6yNdEkBgQ=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.13_1635395861677_0.888443069021214"},"_hasShrinkwrap":false},"1.1.14":{"name":"state-switch","version":"1.1.14","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"2400754e6db4f0ef769cc736167130d2e3988c5d","_id":"state-switch@1.1.14","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-1aUh4NM+5+gXDXKBMWsPoBwi/c6Efn3WdlAK6aYnyobsVgX47PK7vMX8kXNDm7nYmW8NrulmZMQaDXavFsCq4A==","shasum":"6a0ac0be883ba8c9f1a29da09d508f2aca308ac4","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.14.tgz","fileCount":201,"unpackedSize":281802,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBsOF+NO2Ro/LvhY77zUcVh4J7j97nzrCjfKb4VYNa36AiEAm5yWkGPWgQqmw8ybYyLaWvVCD4gTFTBFTVY96M8dR5s="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.14_1635399752351_0.3639814684892939"},"_hasShrinkwrap":false},"1.1.15":{"name":"state-switch","version":"1.1.15","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"4a93f3dba742fb0fdceb04a60ccd24e8f2467099","_id":"state-switch@1.1.15","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-Sn9v8yCqwzACvrI2uZV6EdHNz6Ex0lzhStJC3kSm3XQNoG7MvmDMqtnz9oY1dIoK5+NTPTByY5XufJqEN40rJQ==","shasum":"fdc101c541b177c2439017834813846732694cc6","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.15.tgz","fileCount":201,"unpackedSize":281892,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD+R9yLrNM/cPQr5FOREHY/oYOpNfpLw68xdcqbpG8KZgIgVbrnL9m9ZXYW34zuEuODVopSBJyp7rZT6aN8XYpr5eg="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.15_1635438035834_0.5884896002032278"},"_hasShrinkwrap":false},"1.1.16":{"name":"state-switch","version":"1.1.16","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"5cd082a7ae3a52aff70b2d9dc9378f73fcbd8fba","_id":"state-switch@1.1.16","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-vclcfsZDBlePQhNR62QamFuZf0X2nHQEXgeIn15IBvip9ap76LTIFkfp7eUhawQBkoy4/gpwxaTN7/qIgX90PQ==","shasum":"fbdcb235a17628131288205054a0888436aaf806","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.1.16.tgz","fileCount":201,"unpackedSize":286337,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD4Ogn1coWp9DRRLWinD78DSqZuvpi2mSw0KZnm81eHkQIgLaU2AeWrD2VdKKxK4JSQTr0urwpmNMBk1oHVKURq464="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.1.16_1635650744004_0.08843905647591122"},"_hasShrinkwrap":false},"1.2.1":{"name":"state-switch","version":"1.2.1","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"422d6a91a882437417b7462b83e3393704aaca05","_id":"state-switch@1.2.1","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-6wvItwQVkS5TNMPTZOio6cQSKPeQUiLaMCYUqEinAvZMRzWcrVOEhWJf4Y2LVWGUEbSWS7D3JpBkzw3LBoK3qA==","shasum":"aac0a3571d7509fdd5684aaf858a990fe3bdd557","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.2.1.tgz","fileCount":201,"unpackedSize":286335,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIClMo28LbWnaVZ3KJlRkc20hOdTj52hkPmcoekxcu1/mAiEAxDIpyKfhYeSQ1Wr/N7wd37f4rtoMpows9xXoVo7L1tM="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.2.1_1635650772348_0.9053417078268537"},"_hasShrinkwrap":false},"1.2.3":{"name":"state-switch","version":"1.2.3","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","gerror":"^1.0.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"ea70aafab7b699a88ce59b7d99860df0216069d8","_id":"state-switch@1.2.3","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-0mB8seK0FZhu3+iuMdOyDABz6qq4V90b1vJwPnixRLPQJa4Lb6O+V685Z6KbSzn0uLsll4kLJ2mpyuEN4uVVSA==","shasum":"89584f1d731409fe8fc6591cce135e69fbfbf91d","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.2.3.tgz","fileCount":192,"unpackedSize":280003,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCID9J88gBtcSuQotPWCY1i41zq3xVjVhDd+fdXp5yeiKiAiBSaz1LQpbSBBCDp8f9eZaDycOnOB9zbFr3R5YPE+a24g=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.2.3_1636169160302_0.5324110063937533"},"_hasShrinkwrap":false},"1.2.4":{"name":"state-switch","version":"1.2.4","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","gerror":"^1.0.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"edec9d16409046a864491bd4933b489d3f8db4d6","_id":"state-switch@1.2.4","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-N2L9R4uY9Atm9dpmWlfa2yh185WGcR5ebHAE4FfRxucw/jhR7uV8+X/zV9adiugQfJEuKTAyOm2r5JPh5tWmbw==","shasum":"2b89452ce50a0d263ac3b57ac90c873e94003c9d","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.2.4.tgz","fileCount":192,"unpackedSize":280087,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDZj8Utl14uWvFC44P/3MxnIijAHjQX+LqoC+MAarqG2QIgMWeJ/ElrZQpjqiP2da57IaDDkl/rCwMA/RHFuYujcz0="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.2.4_1636177673597_0.7918722574204218"},"_hasShrinkwrap":false},"1.3.1":{"name":"state-switch","version":"1.3.1","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","gerror":"^1.0.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"8615a7609caf143857c9277470350132e7e44d4c","_id":"state-switch@1.3.1","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-1coHs4IPF53jETLPvgeX+p9lQSr6RZ9c1w74RZD6DluYCDF/ZqMWFczICEt3UUqgEqU5me47W9sDCfruHcL1wg==","shasum":"92aaa52b9ccdc877ad265b3378dbd1356f7be56f","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.3.1.tgz","fileCount":192,"unpackedSize":276184,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCFpGcNO4MUrGGdvTZp2qDkLdsQmkVqswXD3gMqRdH/5AIgDXrZHylehD9HpgnQBLRSOBnWMNfskv8H8Bh7fC8NwGU="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.3.1_1636256765868_0.7521616676083551"},"_hasShrinkwrap":false},"1.3.5":{"name":"state-switch","version":"1.3.5","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","gerror":"^1.0.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"cdec3ae54731e4fd4b2651bf1d3b5d6d8b3ecc8b","_id":"state-switch@1.3.5","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-4fzXl7viRLrB/jI5po53Vu/hfF35AOHktFHno9f1XUFOnjTGfVfupX21VYhrYNdygMpVRbMtR4wXGoOmxirFwg==","shasum":"f985fb397c8d4f6a407f9d4e96d92811b0118790","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.3.5.tgz","fileCount":201,"unpackedSize":271615,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC9cofqIFz8UpPkI6pvkHxtiTuEXwGNwNE5ptCxHBqPWAIgdTr1F+1uAYLEvbqJ838NzAGjefk/KxEs7VKHs/zGXRs="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.3.5_1636474248254_0.46011646980328"},"_hasShrinkwrap":false},"1.3.6":{"name":"state-switch","version":"1.3.6","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.2","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.2","tsd":"^0.18.0","typed-emitter":"^1.4.0"},"peerDependencies":{"brolog":"^1.13.6","gerror":"^1.0.6","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.25.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"0c9375cae3cc57908e352754b4eb4a462f2e2cf6","_id":"state-switch@1.3.6","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-vW5JCjFKfsWJw18aqjfJ6FeGSTvrX2QnfRlJtGswj4QaAeUMajFNS3iiZTVioiciahE8XZN5dTR7TChh+9IgAg==","shasum":"356855e3c525314d03a69cf7160f350e0f8e743a","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.3.6.tgz","fileCount":201,"unpackedSize":273359,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFp33H5w4x36GasoR0fgoge4ss6tBjWa6Uu4K1xOrRFtAiEA6BdmjUjmL7e3d2pDvINuDlLu3Sq09H/1ohe5jW0aA0g="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.3.6_1636636464051_0.44805269869148345"},"_hasShrinkwrap":false},"1.5.1":{"name":"state-switch","version":"1.5.1","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.3","tsd":"^0.18.0","typed-emitter":"^1.5.0-from-event"},"peerDependencies":{"brolog":"^1.13.6","gerror":"^1.0.8","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.26.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BusyIndicator`\n\nSet a busy state.\n\n```ts\nconst indicator = new BusyIndicator()\n```\n\n### 1. `busy()`\n\n1. set busy or not\n1. get busy status\n\n```ts\nindicator.busy(true)\nindicator.busy(false)\nconst busy = indicator.busy()\n```\n\n### 2. `idle()`\n\nReturn a `Promise` that will resolved after the busy state to be idle. (not busy)\n\n> If the current state is not busy, it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.idle()\nassert (indicator.busy() === false, 'busy() should be false after await idle()')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.1 (Oct 27, 2021)\n\nBreaking changes:\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"30b6f3be3ed8e018b4aa78697bdd522d8e04d091","_id":"state-switch@1.5.1","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-HfH09WSKIMoSlf4JPnVa1KAN2/Dolag48GJ802q+Z+kzS4DfyVgIjHCXn88x7skp/MfJTy3H7NBM/bQZqxrurA==","shasum":"b599cbd96bb07d8c3170203b22345cab1694f6f9","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.5.1.tgz","fileCount":201,"unpackedSize":273490,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAE+7bqbbP2pzZPf0Trde4JOKJhqoRdP522ar2NiYVPVAiBYKXRZPJ0cxUVrCMM+T/oZWCgRvtMW8O4Xt913CXEBuw=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.5.1_1636906442442_0.14749489932086646"},"_hasShrinkwrap":false},"1.6.1":{"name":"state-switch","version":"1.6.1","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.3","tsd":"^0.18.0","typed-emitter":"^1.5.0-from-event"},"peerDependencies":{"brolog":"^1.13.6","gerror":"^1.0.8","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.26.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"6ac47694c11633077f4d2400848ce4e3a1d0a976","_id":"state-switch@1.6.1","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-+mvtmItCXb1DchMTVFpWDRQCZxCnSub7JYlmbx7wPcQmRVD3BuLZF3AHOYUTwc5ZzS/O5GmMd4zmSd10h4MvzQ==","shasum":"6f91a5713f3712e2d26b13b494b1af1a193b2204","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.6.1.tgz","fileCount":201,"unpackedSize":273712,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCSaAHTtyopkEwtkZSMM36oJ9o58/bKgohwlxIhrcLTHQIhAJlVran7FCWb3MFVdBG7ZObDUxybPxl6coR4ulQnq/QR"}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.6.1_1636950531740_0.2562770840946229"},"_hasShrinkwrap":false},"1.6.2":{"name":"state-switch","version":"1.6.2","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.3","tsd":"^0.18.0","typed-emitter":"^1.5.0-from-event"},"peerDependencies":{"brolog":"^1.13.6","gerror":"^1.0.8","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.26.0"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"34f7b44251180d105660af7559a5ee4da182e0e6","_id":"state-switch@1.6.2","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-B+XuIuzaSdrIOc3vfJEDxNa1OLd8At7F/lvnCSNoTzIQuPzq/JGGni1UTzUO+slW9YGdQKZ9KELU4wgpEkdgJg==","shasum":"88e36271478429b2b4a3fcaeca8ab2bc2ba55f70","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.6.2.tgz","fileCount":201,"unpackedSize":273080,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhmiLfCRA9TVsSAnZWagAAn58P/0nYkuRAND/aGq3No5zs\na8LdQgRjiLPE/kjdRnovqX6S2WRKUFn6KCille1uMoE3zPeiKUv6c5mVafpp\nBQJpsly0OqmR6cVSKF7DsATp8LPyC55XzgylsFmwe9gw+jnllLaoq82Vd6Lk\nlaUdxT9K8zNi2XBmgwNTa9Iy6VAaJNBkHW1bmjw3dO/7rY0meRoh67hbTc2B\nJm23YlJo41F678/qzG9D6mIgI6ifvmSfV8BPdOdRI0snq04F3DH0NFyVN/k+\nqS+udhxZjrTKisEBOy8VTupbFQzerVg27FV6I1pojAbMEjMiIj4UmVupQedX\nqL7joU54BmcTjGnzNDEYdkpIl1vOaOKaSa01bAywm3b0Urt3jnLSW1ykEoOA\n+xSwLb6Q7P0ursy9hc4tXgKA4NKIhF6OJbv/7N+jTCGnZUt8jCrexqQXBq+I\n8zcwgfCI3qtY3/qYKAJXsEUj/NWRVuwiXMJq3mLA4nQJyUvUQtbwtqzhu2Iv\nemSDULmt9s+mQW8TBPbBj3cgk/JpElcIxj5S/L/dvVhcDqQ0jCo/0tm95Zew\neBhH/+yVTR5AcDMWY8gFdISjc0auWjMvYW8rjJO5kiQDyW3gynr39Cgt0d6H\nXhRO+aU1YyVBdYCMTk+T7mwl7KSGpdRoe0N5yLpy0uIwjrzRM6ChIhqVq9ym\nKsP7\r\n=RhhT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCtlmaCSAVnnxVX0emaUYQbvSYreuooFxMYEYZGtOIR4wIgYlPBOgvteCJ0Rn9OlWTdA/fSIZx+E0Cl7VQWihkRoXo="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.6.2_1637491423361_0.3220538032724398"},"_hasShrinkwrap":false},"1.6.3":{"name":"state-switch","version":"1.6.3","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^4.6.2","tsd":"^0.19.0","typed-emitter":"^1.5.0-from-event"},"peerDependencies":{"brolog":"^1.14.2","gerror":"^1.0.16","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.26.1"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"1b14e623226e5e901db58313aa6aa4495aeefbbf","_id":"state-switch@1.6.3","_nodeVersion":"16.13.1","_npmVersion":"8.1.2","dist":{"integrity":"sha512-D1SwjaDbR5FAivty3SlpU/rD5B9PtnfDkR+BKLkYYxJRUmFqGSD96iwi6t8rIby9vBJJH9CTZyZO/aYzGBzMPw==","shasum":"6afd00820b78afec12202895031f5bb62be545c7","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.6.3.tgz","fileCount":201,"unpackedSize":273081,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhwDqmCRA9TVsSAnZWagAA0boP/RNxogCTxg5vGaKl3CGA\ncPutZp09t0IIXJhUiWcoTJNH24vmXTuNvvuPjeFyVQe3iV01YPaCzNJWMqzw\nZb/OKMh9cvJOL8rsGxO8jnD6db7A38TNCVV0uONmMEjRPVYmd/nbfnPStd1P\nf8NlhQ+9zTGZXrHRCiz3q/YC1HCvTYHXB67HqjsUGjEGeStABtrvZ7qVpk6/\noWElTXeCFVqs7mPNYFyUYfDHKigankDWEmrY9hJfQInSmSXojltoUrf1R2Pw\nIFhJTj3/MdXbaNbtX09My4Zfi9w7TemMTgsMBOzct1aXOeeI69su2cI6QgIR\nemI4gpZECppzZ6LExFA2I3Vj5Nw67QDtCHAQbmPa9jOO5mu9sK/U4z8BLmIk\nVRvKnWIxzYuwCLuv0+s6ZdGh54OCpLUH8arRbqbx+At9xb2m0Cv6dxDUCCcL\nI50zLNQlDNyQ0EstvXaYtJjBWmc4RscIvCDiP8CVokP+3QDwOtsLovI8HyQk\nNuoaR/F3CfxUYBzE0SxT8au1zhw3/vSVZievg3Rq1pj4AlnMsq1AMnfJ2mq3\nFYBwHqJVZuGIaW+QAlu4NhGLdZDoV3fzzQSbVhCa3f3Xa+Bgkmyee3eVByte\nWuioILyEeGnUyiLp5SqjI1WMvFUChPY1MnUoxCE+/4EczSfh93PgPqPMNxTQ\nRf0W\r\n=uq3T\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDb/87VSW5CrFzODFMFcburF3ggal8zjONrNlDibozI1gIhAP+PT0pnFl/nmJKjjdGCz0VNlxMm2yOmzOs1l6cWmcQk"}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.6.3_1639987878437_0.7163812159416818"},"_hasShrinkwrap":false},"1.7.1":{"name":"state-switch","version":"1.7.1","description":"State Switch is a Change Monitor/Guarder for Async Actions.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es && npm run lint:ts","lint:ts":"tsc --isolatedModules --noEmit","lint:es":"eslint --ignore-pattern fixtures/ \"src/**/*.ts\" \"tests/**/*.ts\"","demo":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node example/demo","test":"npm-run-all lint test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"tests/**/*.spec.ts\""},"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"keywords":["state","switch","monitor","async"],"author":{"name":"Huan LI","email":"zixia@zixia.net"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/state-switch/issues"},"homepage":"https://github.com/huan/state-switch#readme","devDependencies":{"@chatie/eslint-config":"^1.0.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^4.6.2","tsd":"^0.19.0","typed-emitter":"^1.5.0-from-event"},"peerDependencies":{"brolog":"^1.14.2","gerror":"^1.0.16","rxjs":"^7.4.0"},"dependencies":{"@pipeletteio/nop":"^1.0.0","xstate":"^4.26.1"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"<!-- markdownlint disable: MD033 -->\n# STATE-SWITCH\n\n[![npm version](https://badge.fury.io/js/state-switch.svg)](https://badge.fury.io/js/state-switch)\n[![NPM](https://github.com/huan/state-switch/workflows/NPM/badge.svg)](https://github.com/huan/state-switch/actions?query=workflow%3ANPM)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\n[![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen)](https://github.com/Chatie/tsconfig/issues/16)\n\n![State Switch Logo](https://huan.github.io/state-switch/images/state-switch.gif)\n\nState Switch is a Monitor/Guard for Managing Your Async Operations.\n\n## Introduction\n\n`StateSwitch` can manage state transition for you, by switching from the following four states:\n\n1. `INACTIVE`: state is inactive\n1. `pending ACTIVE`: state is switching from INACTIVE to ACTIVE\n1. `ACTIVE`: state is active\n1. `pending INACTIVE`: state is switch from ACTIVE to INACTIVE\n\nYou can set/get the state with the API, and you can also monite the state switch events by listening the 'active' and 'inactive' events.\n\nThere have another `stable()` API return a `Promise` so that you can wait the `active` of `inactive` events by:\n\n```ts\nawait state.stable('active')\nawait state.stable('inactive')\nawait state.stable() // wait the current state\n```\n\nIf the state is already ACTIVE when you `await state.stable('active')`, then it will resolved immediatelly.\n\n## EXAMPLE\n\nTalk is cheap, show me the code!\n\n### Code\n\n```ts\nimport { StateSwitch } from 'state-switch'\n\nfunction doSlowConnect() {\n  console.log('> doSlowConnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowConnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nfunction doSlowDisconnect() {\n  console.log('> doSlowDisconnect() started')\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      console.log('> doSlowDisconnect() done')\n      resolve()\n    }, 1000)\n  })\n}\n\nclass MyConnection {\n  private state = new StateSwitch('MyConnection')\n\n  constructor() {\n    /* */\n  }\n\n  public connect() {\n    /**\n     * This is the only 1 Right State\n     */\n    if (this.state.inactive() === true) {\n      this.state.active('pending')\n\n      doSlowConnect().then(() => {\n        this.state.active(true)\n        console.log(`> I'm now opened`)\n      })\n\n      console.log(`> I'm opening`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    } else if (this.state.active() === true) {\n      console.error(`> I'm already open. no need to connect again`)\n    } else if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    }\n  }\n\n  public disconnect() {\n    /**\n     * This is the only one Right State\n     */\n    if (this.state.active() === true) {\n      this.state.inactive('pending')\n\n      doSlowDisconnect().then(() => {\n        this.state.inactive(true)\n        console.log(`> I'm closed.`)\n      })\n\n      console.log(`> I'm closing`)\n      return\n    }\n\n    /**\n     * These are the other 3 Error States\n     */\n    if (this.state.active() === 'pending') {\n      console.error(`> I'm opening, please wait`)\n    } else if (this.state.inactive() === true) {\n      console.error(`> I'm already close. no need to disconnect again`)\n    } else if (this.state.inactive() === 'pending') {\n      console.error(`> I'm closing, please wait`)\n    }\n  }\n}\n\nconst conn = new MyConnection()\n\nconsole.log('CALL: conn.connect(): should start to opening')\nconn.connect()\n\nconsole.log('CALL: conn.connect(): should not connect again while opening')\nconn.connect()\n\nconsole.log('CALL: conn.disconnect(): can not disconnect while opening')\nconn.disconnect()\n\nsetTimeout(() => {\n  console.log('... 2 seconds later, should be already open  ...')\n\n  console.log('CALL: conn.connect(): should not connect again if we are open')\n  conn.connect()\n\n  console.log('CALL: conn.disconnect(): should start to closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.disconnect(): should not disconnect again while we are closing')\n  conn.disconnect()\n\n  console.log('CALL: conn.connect(): can not do connect while we are closing')\n  conn.connect()\n\n  setTimeout(() => {\n    console.log('... 2 seconds later, should be already closed ...')\n\n    console.log('CALL: conn.disconnect(): should not disconnect again if we are close')\n    conn.disconnect()\n  }, 2000)\n\n}, 2000)\n\n```\n\n### Diagram\n\nWhat's the meaning of the above code?\n\nStateSwitch helps you manage the following four states easy:\n\n![State Switch Diagram](https://huan.github.io/state-switch/images/state-switch-diagram.png)\n\n### Run\n\n```shell\n$ npm run demo\n\n> state-switch@0.1.3 demo /home/zixia/git/state-switch\n> ts-node example/demo\n\nCALL: conn.connect(): should start to opening\n> doSlowConnect() started\n> I'm opening\nCALL: conn.connect(): should not connect again while opening\n> I'm opening, please wait\nCALL: conn.disconnect(): can not disconnect while opening\n> I'm opening, please wait\n> doSlowConnect() done\n> I'm now opened\n... 2 seconds later, should be already open  ...\nCALL: conn.connect(): should not connect again if we are open\n> I'm already open. no need to connect again\nCALL: conn.disconnect(): should start to closing\n> doSlowDisconnect() started\n> I'm closing\nCALL: conn.disconnect(): should not disconnect again while we are closing\n> I'm closing, please wait\nCALL: conn.connect(): can not do connect while we are closing\n> I'm closing, please wait\n> doSlowDisconnect() done\n> I'm closed.\n... 2 seconds later, should be already closed ...\nCALL: conn.disconnect(): should not disconnect again if we are close\n> I'm already close. no need to disconnect again\n\n```\n\nThat's the idea: **we should always be able to know the state of our async operation**.\n\n## API REFERENCE\n\nClass StateSwitch\n\n### constructor(clientName?: string)\n\nCreate a new StateSwitch instance.\n\n```ts\nprivate state = new StateSwitch('MyConn')\n```\n\n### active(): boolean | 'pending'\n\nGet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process). `false` for not ACTIVE.\n\n### active(state: true | 'pending'): void\n\nSet the state for `ACTIVE`: `true` for ACTIVE(stable), `pending` for ACTIVE(in-process).\n\n### inactive(): boolean | 'pending'\n\nGet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process). `false` for not INACTIVE.\n\n### inactive(state: true | 'pending'): void\n\nSet the state for `INACTIVE`: `true` for INACTIVE(stable), `pending` for INACTIVE(in-process).\n\n### pending(): boolean\n\nCheck if the state is `pending`.\n\n`true` means there's some async operations we need to wait.\n`false` means no async active fly.\n\n### `stable(expectedState?: StateType, noCross=false): Promise<void>`\n\n1. `expectedState`: `'active' | 'inactive'`, default is the current state\n1. `noCross`: `boolean`, default is `false`\n\nWait the expected state to be stable.\n\nIf set `noCross` to `true`, then `stable()` will throw if you are wait a state from it's opposite site, for example: you can expect an `Exception` be thrown out when you call `stable('active', true)` when the `inactive() === true`.\n\n### name(): string\n\nGet the name from the constructor.\n\n### setLog(logger: Loggable)\n\nEnable log by set log to a Npmlog compatible instance.\n\nPersonaly I use Brolog, which is writen by my self, the same API with Npmlog but can also run inside Browser with Angular supported.\n\n```ts\nconst log = Brolog.instance()\nStateSwitch.setLog(log)\n```\n\n## `BooleanIndicator`\n\nSet a true/false state.\n\n```ts\nconst indicator = new BooleanIndicator()\n```\n\n### 1. `value(v?: boolean): void`\n\n1. set `true` or `false`\n1. get `boolean` status\n\n```ts\nindicator.value(true)\nindicator.value(false)\nconst value = indicator.value()\n```\n\n### 2. `ready(v: boolean, noCross=false): Promise<void>`\n\nReturn a `Promise` that will resolved after the boolean state to be the value passed through `v`.\n\n> If the current boolean state is the same as the `v`, then it will return a `Promise` that will resolved immediately.\n\n```ts\nawait indicator.ready(false)\nassert (indicator.value() === false, 'value() should be false after await ready(false)')\n```\n\n## ServiceCtl Interface\n\n```ts\ninterface ServiceCtlInterface {\n  state: StateSwitchInterface\n\n  reset   : ServiceCtl['reset']\n  start   : ServiceCtl['start']\n  stop    : ServiceCtl['stop']\n}\n```\n\n### ServiceCtlFsm (ServiceCtlFsmMixin) Class\n\nUse a Finite State Machine (FSM) to manage the state of your service.\n\n```ts\nimport { ServiceCtlFsm } from 'state-switch'\n\nclass MyService extends ServiceCtlFsm {\n\n  async onStart (): Promise<void> {\n    // your start code\n  }\n\n  async onStop (): Promise<void> {\n    // your stop code\n  }\n\n}\n\nconst service = new MyService()\n\nawait service.start() // this will call `onStart()`\nawait service.stop()  // this will call `onStop()`\n\nawait service.start()\nawait service.reset()  // this will call `onStop()` then `onStart()`\n```\n\nLearn more about the finite state machine design pattern inside our `ServiceCtl`:\n\n[![State Switch Service Controler](https://stately.ai/registry/machines/37e4ce99-945d-49a8-8da2-1f324d04b574.png)](https://stately.ai/viz/37e4ce99-945d-49a8-8da2-1f324d04b574)\n\n### ServiceCtl (ServiceCtlMixin) Class\n\nImplementes the same `ServiceCtlInterface`, but using a `StateSwitch` to manage the internal state.\n\nThe code is originally from [Wechaty Puppet](https://github.com/wechaty/puppet/blob/e13b93335460baad0b3e5392f7eff62fef7bb645/src/puppet/puppet-abstract.ts#L139-L193), then abstracted to a class.\n\n## RESOURCES\n\n### XState\n\n1. [An Introduction to XState in TypeScript](https://dev.to/giantmachines/an-introduction-to-xstate-in-typescript-1pdn)\n\n## CHANGELOG\n\n### master v1.7 (Jan 18, 2022)\n\n1. Add `BooleanIndicator` class to replace and deprecate the `BusyIndicator` class for a more powerful and easy to use API.\n\n#### v1.1 (Oct 27, 2021) - Breaking changes\n\n1. `StateSwitch#pending` -> `StateSwitch#pending()`\n1. `StateSwitch#on()` -> `StateSwitch#active()`\n1. `StateSwitch#off()` -> `StateSwitch#inactive()`\n1. `emit('on')` -> `emit('active')`\n1. `emit('off')` -> `emit('inactive')`\n\nTL;DR:\n\n```diff\n- state.on()\n+ state.active()\n\n- state.on(true)\n+ state.active(true)\n\n- state.off()\n+ state.inactive()\n\n- state.off(true)\n+ staet.inactive(true)\n\n- state.pending\n+ state.pending()\n```\n\n### v1.0 (Oct 23, 2021)\n\n- Oct 27: Add `ServiceCtl`/`ServiceCtlFsm` abstract class and `serviceCtlMixin`/`serviceCtlFsmMixin` mixin\n- Oct 23: Add `BusyIndicator` class\n    1. Add `BusyIndicatorInterface` and `StateSwitchInterface`\n- v0.15 (Sep 2021): Publish as ESM package.\n\n### v0.14\n\n1. Add RxJS typing unit tests for making sure that the `fromEvent` typing inference is right.\n\n### v0.9 master (Mar 2020)\n\nSupport for using RxJS:\n\n```ts\nconst notPending = (state: true | 'pending') => state === true\n\nconst stateOn$ = fromEvent(stateSwitch, 'active').pipe(\n  filter(notPending)\n)\n```\n\nSee: [RxJS - operator - fromEvent - Node.js EventEmitter: An object with addListener and removeListener methods.](https://rxjs.dev/api/index/function/fromEvent)\n\n1. Support emit `on` and `off` events with the args of the `state` of two values: `true` and `pending`.\n1. Add events unit tests\n\n### v0.6 (Jun 2018)\n\n1. DevOps for publishing to NPM@next for odd minor versions.\n1. Add State Diagram for easy understanding what state-switch do\n\n### v0.4 (Apr 2018)\n\nBREAKING CHANGE: Change the `ready()` parameter to the opposite side.\n\n- Before: `ready(state, crossWait=false)`\n- AFTER: `ready(state, noCross=false`)\n\n### v0.3 (Apr 2018)\n\n1. add new method `ready()` to let user wait until the expected state is on(true).\n\n### v0.2 (Oct 2017)\n\nBREAKING CHANGES: redesigned all APIs.\n\n1. delete all old APIs.\n1. add 4 new APIs: on() / off() / pending() / name()\n\n### v0.1.0 (May 2017)\n\nRename to `StateSwitch` because the name StateMonitor on npmjs.com is taken.\n\n1. Make it a solo NPM Module. ([#466](https://github.com/Chatie/wechaty/issues/466))\n\n### v0.0.0 (Oct 2016)\n\nOrignal name is `StateMonitor`\n\n1. Part of the [Wechaty](https://github.com/Chatie/wechaty) project\n\n## AUTHOR\n\nHuan LI <zixia@zixia.net> (<http://linkedin.com/in/zixia>)\n\n<a href=\"http://stackoverflow.com/users/1123955/zixia\">\n  <img src=\"http://stackoverflow.com/users/flair/1123955.png\" width=\"208\" height=\"58\" alt=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\" title=\"profile for zixia at Stack Overflow, Q&amp;A for professional and enthusiast programmers\">\n</a>\n\n## COPYRIGHT & LICENSE\n\n- Code & Docs 2016-now© zixia\n- Code released under the Apache-2.0 license\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"dbd7ed805fba0d393715797e810913d1a1df5608","_id":"state-switch@1.7.1","_nodeVersion":"16.13.2","_npmVersion":"8.1.2","dist":{"integrity":"sha512-P8G42lE6JW8l9wbYSxRfB81qTGJw+z4fXN9jSRpOy5i09oonoFcOZGGObvYyiMz7pxatTzbWzhHi+ioKzflm2g==","shasum":"a0c53ee0642518efc7c17df26fb7160badcbbc78","tarball":"https://registry.npmjs.org/state-switch/-/state-switch-1.7.1.tgz","fileCount":219,"unpackedSize":289041,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh5hE0CRA9TVsSAnZWagAAFB8P/3okVGpP81b5bLD6K2bT\nnYQl4nGwV3ftlSsFYy2SQjaisySvr3ZiFwhp6BfNiH3QioI+UZib8hzRjn89\nfJlS2TzqaUuem8PmJ3mcTcW6RiXm3lDSGh3LtPXkd7fjmJcY53RBAh/tiJGL\nASWWwcZNJZJErL3+fbnyUm3QA9ydBK9EMu7oWvC0TYnHJQTcHOnn6gGzraXW\n/jpLb+Al6x/G5rNhqTiPtxPn9/q1X7ljwxOc/Es0W88Acrr+TRotHk2yd29C\nhuT4JwxY4UcCEIU+pE3BcziRWOI6kdAUHCFhk7g0iq/T9nwk8zPS9JglgDzY\ngdn65wX4r2wol/rG4bxcIePQfvop8NBpLLY8AkjJClVABqKfaK3v4Jfo38dk\ngMdhABuHBpJOojGT4fcDgOONksTrWDDb4ZM6LUY7J9PXnCq0DLnyFtA/cZOW\n7FF2DA5u+qQycbGoqKcP4Y4vfjSGDV8nRQG4ksWQ7uoB66Aiyy7LOeXdCIWR\nx/fviyaDcy+UiD9i6lZg4Fd40blOlF4c8pMmFozRjZX6G96kPMGCWz/Op+Vw\nwYlBJ1Wif7iMmZeOeiB/fa0MWNojnxoyYe5EqFoB17J7PFnFGxjOLpXMSs1g\n306Ri7TUD/5L/g9B7EPhtM47NxS2F23iofPkK2E43qYj51q35kW/+Czpm1Kl\nRIrj\r\n=rEcc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGF4Q77N5dUfgASZSqkjeeIrrJN+fwPZH2MB/Bx47cFEAiBzRIn959m8SS4SlflXYNltMINCWaflrN2wi7Y6Q0kGCQ=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/state-switch_1.7.1_1642467636191_0.8288227880553358"},"_hasShrinkwrap":false}},"readme":"","maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"time":{"modified":"2022-06-26T23:59:29.416Z","created":"2017-05-02T14:25:32.539Z","0.1.3":"2017-05-02T14:25:32.539Z","0.1.4":"2017-05-02T14:32:11.647Z","0.1.5":"2017-05-02T14:42:20.516Z","0.1.6":"2017-05-02T14:43:08.458Z","0.1.7":"2017-05-02T14:49:09.465Z","0.1.8":"2017-05-02T16:09:20.301Z","0.1.9":"2017-05-02T16:12:06.092Z","0.1.10":"2017-05-03T03:22:26.456Z","0.1.11":"2017-05-03T03:42:28.113Z","0.1.13":"2017-05-06T18:19:00.170Z","0.1.14":"2017-05-06T18:29:10.920Z","0.1.15":"2017-05-06T18:29:49.382Z","0.1.19":"2017-10-20T17:22:27.974Z","0.1.20":"2017-10-20T17:23:00.057Z","0.1.21":"2017-10-21T14:34:27.974Z","0.2.1":"2017-10-22T12:52:26.154Z","0.2.2":"2017-10-22T13:13:27.332Z","0.2.3":"2017-10-22T13:33:02.881Z","0.2.4":"2017-10-29T03:17:44.700Z","0.3.0":"2018-04-02T17:38:12.971Z","0.3.1":"2018-04-02T17:40:28.738Z","0.3.2":"2018-04-02T17:46:50.846Z","0.4.1":"2018-04-09T05:53:11.357Z","0.4.2":"2018-04-09T06:32:46.537Z","0.4.3":"2018-04-09T17:49:45.912Z","0.4.4":"2018-04-09T18:05:58.379Z","0.4.5":"2018-04-11T07:19:40.318Z","0.6.2":"2018-06-15T19:21:01.040Z","0.6.3":"2018-08-05T03:02:50.031Z","0.6.4":"2018-08-05T03:03:21.341Z","0.6.5":"2018-08-05T03:06:43.030Z","0.6.6":"2018-08-05T03:09:12.245Z","0.6.10":"2018-09-08T17:26:07.079Z","0.6.11":"2018-11-27T16:32:48.559Z","0.6.12":"2018-11-27T16:39:54.292Z","0.6.14":"2019-06-22T07:23:26.009Z","0.6.15":"2019-06-22T07:25:12.509Z","0.6.16":"2019-06-22T07:29:48.326Z","0.6.17":"2019-06-22T11:54:05.479Z","0.6.18":"2019-06-22T12:05:28.839Z","0.7.2":"2019-06-23T04:30:41.286Z","0.9.7":"2020-04-07T06:41:17.290Z","0.9.8":"2020-04-07T06:46:02.313Z","0.9.9":"2020-04-07T06:56:28.957Z","0.11.3":"2021-05-31T05:45:36.238Z","0.11.4":"2021-05-31T18:05:41.627Z","0.11.5":"2021-06-22T12:50:41.794Z","0.13.1":"2021-08-25T11:52:10.110Z","0.14.1":"2021-08-25T11:53:29.926Z","0.15.7":"2021-08-25T17:02:29.301Z","0.15.8":"2021-08-25T17:12:52.845Z","0.15.9":"2021-08-25T18:39:38.666Z","0.15.10":"2021-08-26T02:58:34.748Z","0.17.1":"2021-10-15T05:41:36.348Z","0.18.1":"2021-10-16T15:12:59.669Z","1.0.2":"2021-10-23T06:57:27.739Z","1.0.4":"2021-10-23T18:17:44.048Z","1.0.5":"2021-10-23T18:18:31.132Z","1.0.14":"2021-10-26T17:53:55.839Z","1.0.15":"2021-10-26T19:11:14.299Z","1.0.16":"2021-10-26T19:30:01.125Z","1.1.2":"2021-10-27T06:44:45.254Z","1.1.3":"2021-10-27T06:57:40.475Z","1.1.4":"2021-10-27T07:05:42.474Z","1.1.5":"2021-10-27T07:28:03.122Z","1.1.6":"2021-10-27T10:25:34.546Z","1.1.7":"2021-10-27T10:32:12.418Z","1.1.8":"2021-10-27T11:50:14.236Z","1.1.9":"2021-10-28T04:08:57.835Z","1.1.10":"2021-10-28T04:17:40.234Z","1.1.11":"2021-10-28T04:19:55.293Z","1.1.12":"2021-10-28T04:21:35.699Z","1.1.13":"2021-10-28T04:37:41.857Z","1.1.14":"2021-10-28T05:42:32.522Z","1.1.15":"2021-10-28T16:20:36.186Z","1.1.16":"2021-10-31T03:25:44.199Z","1.2.1":"2021-10-31T03:26:12.516Z","1.2.3":"2021-11-06T03:26:00.497Z","1.2.4":"2021-11-06T05:47:53.796Z","1.3.1":"2021-11-07T03:46:06.059Z","1.3.5":"2021-11-09T16:10:48.471Z","1.3.6":"2021-11-11T13:14:24.242Z","1.5.1":"2021-11-14T16:14:02.630Z","1.6.1":"2021-11-15T04:28:51.899Z","1.6.2":"2021-11-21T10:43:43.556Z","1.6.3":"2021-12-20T08:11:18.655Z","1.7.1":"2022-01-18T01:00:36.380Z"},"homepage":"https://github.com/huan/state-switch#readme","keywords":["state","switch","monitor","async"],"repository":{"type":"git","url":"git+https://github.com/huan/state-switch.git"},"author":{"name":"Huan LI","email":"zixia@zixia.net"},"bugs":{"url":"https://github.com/huan/state-switch/issues"},"license":"Apache-2.0","readmeFilename":""}