{"_id":"txn","_rev":"44-86e07381854230a94687aae2b6226b8e","name":"txn","description":"Process and update CouchDB data in atomic, all-or-nothing transactions","dist-tags":{"latest":"1.2.0"},"versions":{"0.1.0":{"name":"txn","version":"0.1.0","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn.git"},"engines":["node"],"dependencies":{"request":"2.1.1","log4js":"0.3.9","obj_diff":"0.1.0"},"main":"api.js","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"_id":"txn@0.1.0","devDependencies":{},"_engineSupported":true,"_npmVersion":"1.0.90","_nodeVersion":"v0.4.8","_defaultsLoaded":true,"dist":{"shasum":"cfbcbbb7def265f195aa9ab0738e69cfe60dd915","tarball":"https://registry.npmjs.org/txn/-/txn-0.1.0.tgz","integrity":"sha512-s6ApfmDrG625EmO/8wSwDO7Pmtj5liQX+JxHj9DUELCdnKXqdmQ6v5pBNOefnGIJJF9hbYpHToAx9kpO7jaOsQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC2vg6nceM73wxhzMxqUFM4WP+uCTOlhrDvzsG/9e/bgAIhAK4b82T7DyiDVxYuWnXtsZGBlJAAvzoQGQRAG8Wug4Y4"}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.0":{"name":"txn","version":"0.2.0","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn.git"},"engines":["node"],"dependencies":{"request":"2.1.1","log4js":"0.3.9","obj_diff":"0.1.0"},"main":"api.js","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"_id":"txn@0.2.0","devDependencies":{},"_engineSupported":true,"_npmVersion":"1.0.90","_nodeVersion":"v0.4.8","_defaultsLoaded":true,"dist":{"shasum":"dd288387ad3a9324e00ef33270f29978445331f2","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.0.tgz","integrity":"sha512-deG+smAarKiC1ujPDlRF9It/+P0K/JMQRMt1ty2XwNlQptjPwGdrFNEcUCwYQOb1Px82r9lcV+2A+Vju0WTzIg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD6ObOHR3cUidY4yZjV6LY3/MZWmQR5I62N7HhwiYcyXgIgf2tP+vDcblGAu7zXfLHIM38wPRdHlMvur/tA8qx8GH8="}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.1":{"name":"txn","version":"0.2.1","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn.git"},"engines":["node"],"dependencies":{"defaultable":"0.4.0","request":"2.1.1","log4js":"0.3.9","obj_diff":"0.1.0"},"main":"api.js","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"_id":"txn@0.2.1","devDependencies":{},"_engineSupported":true,"_npmVersion":"1.0.90","_nodeVersion":"v0.4.8","_defaultsLoaded":true,"dist":{"shasum":"4ac11bdf0bb8c1249d8ec7767b73f1cc27ef09b3","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.1.tgz","integrity":"sha512-u4MsUF9csIkfKFlT+sMeAR3texZaFQlUOPp9KgHoSZZgD1F4MkCZZauvn0EbIlXC4L83yIHmj5Eh6h+6dR8IRA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE05zZ38R6yr73PfhwJlBzBtNcrvnhuG+i6xGUDItHdqAiEApIp3qd+n6lPv4xGukQf6Up/3ie4Pn4B8PNB7JBM061E="}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.2":{"name":"txn","version":"0.2.2","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn.git"},"engines":["node"],"dependencies":{"defaultable":"0.7.2","request":"2.2.5","log4js":"0.4.0","obj_diff":"0.1.0"},"main":"api.js","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"_id":"txn@0.2.2","devDependencies":{},"_engineSupported":true,"_npmVersion":"1.0.104","_nodeVersion":"v0.6.2","_defaultsLoaded":true,"dist":{"shasum":"16cc0796575126f926d7be171567e83e0c811196","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.2.tgz","integrity":"sha512-A37AUH4Wzu0h0KeOJ1b/bPW51rNSt+iwAQ+q/5f4rj1am/Uj155lwZzpyo+MQ8cbbfiQ8W6+lna/5qjmryVt7A==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFGkFYdbQmafWrGqiEXZH2Exxqy73uWOCDcWcVUepr3YAiEA1s5tn7GV7FelnDItHcy0WO5sDps9Fi1u30lEiNL2s8s="}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.3":{"name":"txn","version":"0.2.3","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn.git"},"engines":["node"],"dependencies":{"defaultable":"0.7.2","request":"2.2.5","log4js":"0.4.0","obj_diff":"0.2.0"},"main":"api.js","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"_id":"txn@0.2.3","devDependencies":{},"_engineSupported":true,"_npmVersion":"1.0.104","_nodeVersion":"v0.6.2","_defaultsLoaded":true,"dist":{"shasum":"9ff479b12fb40a7a56243d8fdd721d6cf5d3fcf8","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.3.tgz","integrity":"sha512-L2s+P0xcclW+wTK5Z25jcYz//X5N2SdC5/e2LtKBX2gozPEk4ov2GnoAlsN+UBr1oC7hcboKQCPdorhoQaTSDw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCPGT2S9pRICnnRzcDQoTX3vY8RLiyBDbuIl6q+Pkj5FAIhAK7IZvb5RVt01C1ACOYmmeaT0n6OBCF4AhI3a6cmo5c0"}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.4":{"name":"txn","version":"0.2.4","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn.git"},"engines":["node"],"dependencies":{"defaultable":"0.7.2","request":"2.2.5","log4js":"0.4.0","obj_diff":"0.2.0"},"main":"api.js","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"_id":"txn@0.2.4","devDependencies":{},"_engineSupported":true,"_npmVersion":"1.0.104","_nodeVersion":"v0.6.0","_defaultsLoaded":true,"dist":{"shasum":"48716b419fdd4f6c67bae69b04db36c458251a14","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.4.tgz","integrity":"sha512-UevstebMr8jbjcZy94dUhdENu+gKDqEfSf1dSsZp3GHdpffJzLts2H50z761kqqAjeJ9WyYCplGTbC18SmfMqQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC4pfc2vBWW38LDtv98ZwKoDTDeCfkUehlADr42KObOFQIhAJWodf+voabGL/8uF/UDvhrnn3AbVT2g9U2cB23yOHSD"}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.5":{"name":"txn","version":"0.2.5","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn.git"},"engines":["node"],"dependencies":{"defaultable":"0.7.2","request":"2.2.5","log4js":"0.4.0","obj_diff":"0.2.0"},"main":"api.js","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"_id":"txn@0.2.5","devDependencies":{},"_engineSupported":true,"_npmVersion":"1.0.104","_nodeVersion":"v0.6.2","_defaultsLoaded":true,"dist":{"shasum":"691c462c07f215970caee5cc7582f0677fdadcb4","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.5.tgz","integrity":"sha512-try9b4T/szWNedTEAg5WydHSOiRWpgyjlSQdRqAEssrEdTGjermrO2lN3s3Rr7iPUXBRSYD5kFrsMVYL0KEHYQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDGZmF3DXZW8Z1yU6UakrStB47N2whL4Ix2oUwMReSv2AIgSWT+BBhXgyvLt+euxDv/uWDbFvBa4s1Z6PH/dLbtmWE="}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.6":{"name":"txn","version":"0.2.6","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn.git"},"engines":["node"],"dependencies":{"defaultable":"~0.7.2","request":"~2.2.5","log4js":"~0.4.0","obj_diff":"~0.2.0"},"main":"api.js","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"_id":"txn@0.2.6","devDependencies":{},"_engineSupported":true,"_npmVersion":"1.1.0-beta-4","_nodeVersion":"v0.6.6","_defaultsLoaded":true,"dist":{"shasum":"9833bdf0ff1c4637b51a35cc795cafdb5a45d9f3","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.6.tgz","integrity":"sha512-2wc+U85JcGwHO/CRanvoIVlwmoASCfxktkLkYilXJDW6mQXCGsKjzUcaYt4XIa2z700TayyrjQFnuhfistvpaw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHuvRWGpBYDlvCfmyzxp1TZuHPh2+DpE4RAJ7928aIqvAiEA/zuaXKj7jyz1/YfFpGxXbkSq592U8RSYQAqOFvoX1Fs="}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.7":{"name":"txn","version":"0.2.7","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn.git"},"engines":["node"],"dependencies":{"defaultable":"~0.7.2","request":"~2.2.5","log4js":"~0.4.0","obj_diff":"~0.2.0"},"main":"api.js","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"_id":"txn@0.2.7","devDependencies":{},"_engineSupported":true,"_npmVersion":"1.1.0-beta-4","_nodeVersion":"v0.6.6","_defaultsLoaded":true,"dist":{"shasum":"0f1615456522d78533eae54d47278e11f70e43b5","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.7.tgz","integrity":"sha512-7ZZ+lrMwoVmGPEhFvICZFmGBC+AjGjxUvfJ609kbl9+4a8FxYFV0C+OhYX8R8Q8rUHsn6pQ+XDqy1lMd860azA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDOKQeVm6UkWClRKnnDpWKmQdje60vama1yNZ24p7edgAiBgv1WqHdw2XNZRGtUr1jviX5xvmw3eZlhYpIbs5anysQ=="}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.8":{"name":"txn","version":"0.2.8","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn.git"},"engines":["node"],"dependencies":{"defaultable":"~0.7.2","request":"~2.2.5","log4js":"~0.4.0","obj_diff":"~0.2.0"},"main":"api.js","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"_id":"txn@0.2.8","devDependencies":{},"_engineSupported":true,"_npmVersion":"1.1.0-beta-4","_nodeVersion":"v0.6.6","_defaultsLoaded":true,"dist":{"shasum":"8031ebf217b042410a5cc8344ff24961fda17b5a","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.8.tgz","integrity":"sha512-qv6z5ORuv5TZOBwv9U5IugKTB2xHhvquYEOsleYMyS1/1AJw7kf4+tDSHez+4CRRWxhykgcT7LzNcayhyL7KDg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDHcHdKHwlzwgjpvxWoURk/souySJpInBexNKcWMU2xjQIhAI2abpFOYbN/Q++aJ6hkt80FhhIr9S+2B7yIeI2M8Wpc"}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.9":{"name":"txn","version":"0.2.9","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn.git"},"engines":["node"],"dependencies":{"defaultable":"~0.7.2","request":"~2.2.5","log4js":"~0.4.0","obj_diff":"~0.2.0"},"main":"api.js","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"_id":"txn@0.2.9","devDependencies":{},"_engineSupported":true,"_npmVersion":"1.1.0-beta-4","_nodeVersion":"v0.6.6","_defaultsLoaded":true,"dist":{"shasum":"63ef1372b50106c405d906d3cf77a0cd0a9565db","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.9.tgz","integrity":"sha512-k/mFFX5JQq8GGVdXjO/2NLl81ZVzh7CK6itULPZYahuDXeCQdoDlxd5Qm8u3i6BtOzRiXVUA/ysDEtnUEYYkwA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFv2ZNneQiOTjcaiCOyOTVnYz1u1yI1J5IKuIawpayMmAiA/p5VPSt3kuTE2EVmMvwWBN5h2blwXWa6pLrkMDOC4jg=="}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.10":{"name":"txn","version":"0.2.10","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn"},"engines":["node"],"dependencies":{"defaultable":"~0.7.2","request":"~2.2.5","log4js":"~0.5.4","obj_diff":"~0.2.0"},"main":"api.js","_id":"txn@0.2.10","dist":{"shasum":"61eab4633fd50ba20815256e2a64b912b7e15de9","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.10.tgz","integrity":"sha512-oNdeIa1ZmOngB0SnwVYxj/OD4f9JoyywmDFR8aif5telv61hztRQ5WsGz2Y6RZJvOXcHfftfgDMu6uiiWOUJTA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEOL+PKH0MxVyxO995fVxUZby/xA8x7wlpE+VFOxLYKoAiAdijT1rU7MYc/JE8dYbxc4LX2fHhL4I0ev9u4b3sqQ6Q=="}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.11":{"name":"txn","version":"0.2.11","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn"},"engines":["node"],"dependencies":{"defaultable":"~0.7.2","request":"~2.16.6","log4js":"~0.5.4","obj_diff":"~0.2.0"},"main":"api.js","_id":"txn@0.2.11","dist":{"shasum":"f9eacbff2816c7a82d5c7a1c5e8eccfeb48adbe4","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.11.tgz","integrity":"sha512-4LzVNH51MT2FbZnMx8Yhk+W6RZDvCV0Bti2bC6mP3lhoTC3xE0fqpNyjmLrluII9aHKoMaedHQryTipjDxT1vQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCrt3+/xQaJXsNQBQyxoOMCH4fENS11JrhmoBCzrqhpkQIgMypNbbDzfyNXqFTcRhPHyXymeOygxpP2xAKzI2u0J+U="}]},"_from":".","_npmVersion":"1.2.14","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.12":{"name":"txn","version":"0.2.12","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn"},"engines":["node"],"dependencies":{"defaultable":"~0.7.2","request":"~2.16.6","log4js":"~0.5.4","obj_diff":"~0.2.0"},"main":"api.js","_id":"txn@0.2.12","dist":{"shasum":"4428063d633c796feb179ccaacbedb5cccb7b951","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.12.tgz","integrity":"sha512-GR7kxQHjPzMglb/0TPl+7NurzenEK6NyJxTElfLf+abo9MtbvX6v0TLzROA9N1DIrnHXFcs0HHSmfBIWsWIFCA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCqdhY/RbBUpO0k3xRsSCN9Egzltyh99zFM60g27zq+RAIgfl1yYL+bfgSQd6f3nwbPrQMHklPnNlgjoawlm5oRHRU="}]},"_from":".","_npmVersion":"1.2.14","_npmUser":{"name":"jhs","email":"jhs@iriscouch.com"},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"}]},"0.2.14":{"name":"txn","version":"0.2.14","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn"},"engines":["node"],"dependencies":{"defaultable":"~0.7.2","request":"~2.39.0","browser-request":"~0.2.1","log4js":"~0.5.4","obj_diff":"~0.2.0"},"browser":{"request":"browser-request"},"main":"api.js","gitHead":"f0ab157b7e03900b661245f8c5e2d4c0da1620bf","bugs":{"url":"https://github.com/iriscouch/txn/issues"},"_id":"txn@0.2.14","scripts":{},"_shasum":"b961b021b47757ba8d19c5dd8901813a51e9c259","_from":".","_npmVersion":"1.4.21","_npmUser":{"name":"jcrugzz","email":"jcrugzz@gmail.com"},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"},{"name":"jcrugzz","email":"jcrugzz@gmail.com"}],"dist":{"shasum":"b961b021b47757ba8d19c5dd8901813a51e9c259","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.14.tgz","integrity":"sha512-+PBIg/qrUSVyfcVTJxFTE0ekIBd3THJ5+emKLncN7/sKOnwx5vPTCmmxYPTIXBEHGMFzUJ159gn5HZRwonzLGQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBFam0O67RJwcOEP0a+WM6HwuH8POYLYi1I8pe+QvhQdAiBEC8qcfjRhF9AY9o/1Gt4wF9cyHpHXYKbhSdiOOeAmwg=="}]}},"0.2.15":{"name":"txn","version":"0.2.15","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/iriscouch/txn","repository":{"type":"git","url":"git://github.com/iriscouch/txn"},"engines":["node"],"scripts":{"test":"node test/run.js"},"dependencies":{"defaultable":"~0.7.2","request":"^2.48.0","browser-request":"~0.2.1","debug":"~0.7.2","obj_diff":"~0.2.0"},"devDependencies":{"log4js":"~0.5.4"},"browser":{"request":"browser-request"},"main":"api.js","gitHead":"c019fb938a25cd1328f9b1dd1525fb057d25d87d","bugs":{"url":"https://github.com/iriscouch/txn/issues"},"_id":"txn@0.2.15","_shasum":"654eb58d59b0d6d599316361496f3bd325acc46f","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"jcrugzz","email":"jcrugzz@gmail.com"},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"},{"name":"jcrugzz","email":"jcrugzz@gmail.com"}],"dist":{"shasum":"654eb58d59b0d6d599316361496f3bd325acc46f","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.15.tgz","integrity":"sha512-rJ1Pyopt1vmIHu5YEy+R0i3IaTR60q2wK2bodq0/92QlhDHzhi5/4ZV4ib6I7uTvXQV48s1/ZXIEALl3SSnD9Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDPQkLlA0fRMlSx31fkLmF5yBErgyYdcKkB/BR5fUA2fgIhAOprZwxmW1uDLAkkn0rvY9UP56w484KhfcjL7yxs1n7X"}]}},"0.2.16":{"name":"txn","version":"0.2.16","author":{"name":"Jason Smith","email":"jhs@iriscouch.com","url":"http://www.iriscouch.com/"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/nodejitsu/txn","repository":{"type":"git","url":"git://github.com/nodejitsu/txn"},"engines":["node"],"scripts":{"test":"node test/run.js"},"dependencies":{"defaultable":"~0.7.2","request":"^2.48.0","browser-request":"~0.2.1","debug":"^2.1.0","obj_diff":"~0.2.0"},"devDependencies":{"log4js":"~0.6.4"},"browser":{"request":"browser-request"},"main":"api.js","license":"Apache 2.0","gitHead":"3ffcbdbc8e7ca880443486313a516822dccbe471","bugs":{"url":"https://github.com/nodejitsu/txn/issues"},"_id":"txn@0.2.16","_shasum":"5bd94bde3366a3ae6c354ea069791ef8c905e39a","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"jcrugzz","email":"jcrugzz@gmail.com"},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"},{"name":"jcrugzz","email":"jcrugzz@gmail.com"}],"dist":{"shasum":"5bd94bde3366a3ae6c354ea069791ef8c905e39a","tarball":"https://registry.npmjs.org/txn/-/txn-0.2.16.tgz","integrity":"sha512-8ujOhbKvRZPCssYuU64Ng16zPff/uM/AGOVfeijpwFsby5akdtmZDXzgpXQ6cmtTmOMMYcU0DrAwRZIyg6DqkA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCB1VNYcAvrxgAekrgT1RCPMYLZJLfzKmkBUyA+JsmspQIhAPzHKAKRP7xk9VqKdCiGKdmTwRlnBa4Z/PmFZ6T/FXpv"}]}},"1.0.0":{"name":"txn","version":"1.0.0","author":{"name":"Jason Smith","email":"jason.h.smith@gmail.com"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/jhs/txn","repository":{"type":"git","url":"git://github.com/jhs/txn.git"},"engines":["node"],"scripts":{"test":"tap test/pouchdb.js","test-pouchdb":"env couchdb= tap test/pouchdb.js","test-couchdb":"env couchdb=${couchdb:-http://127.0.0.1:5984} node test/pouchdb.js"},"dependencies":{"browser-request":"~0.2.1","debug":"^2.1.0","defaultable":"~0.7.2","obj_diff":"~0.2.0","request":"^2.57.0"},"devDependencies":{"memdown":"^1.0.0","pouchdb":"^3.6.0","tap":"^1.2.0"},"browser":{"request":"browser-request"},"main":"api.js","license":"Apache 2.0","gitHead":"2766f20055835c13fa8c1c4a625464e0b1142465","bugs":{"url":"https://github.com/jhs/txn/issues"},"_id":"txn@1.0.0","_shasum":"a295c677c271e15a77387646d02db62dabcf78dc","_from":".","_npmVersion":"2.11.0","_nodeVersion":"2.2.1","_npmUser":{"name":"jhs","email":"jason.h.smith@gmail.com"},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"},{"name":"jcrugzz","email":"jcrugzz@gmail.com"}],"dist":{"shasum":"a295c677c271e15a77387646d02db62dabcf78dc","tarball":"https://registry.npmjs.org/txn/-/txn-1.0.0.tgz","integrity":"sha512-o+rpmnyF+YWr84hamxt/3JPPuqWZaEmYpFvyjRwHDR/lOTK2SuXM53O4Yz51hOiSKEY387pq3uKLzK278Wc7XQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDs5aY3+ALHioa96rHmsZvHLlFoiNUoWieTJzKHiMNcHAiBJ3is8j+rqZXKVh6r6r3ajzGPkKxJe++540Uwn9KGBDA=="}]}},"1.0.1":{"name":"txn","version":"1.0.1","author":{"name":"Jason Smith","email":"jason.h.smith@gmail.com"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/jhs/txn","repository":{"type":"git","url":"git://github.com/jhs/txn.git"},"engines":["node"],"scripts":{"test":"tap test/txn.js","test-pouchdb":"env couchdb= tap test/txn.js","test-couchdb":"env couchdb=${couchdb:-http://127.0.0.1:5984} node test/txn.js"},"dependencies":{"browser-request":"~0.2.1","debug":"^2.1.0","defaultable":"~0.7.2","obj_diff":"~0.2.0","request":"^2.57.0"},"devDependencies":{"memdown":"^1.0.0","pouchdb":"^3.6.0","tap":"^1.2.0"},"browser":{"request":"browser-request"},"main":"api.js","license":"Apache 2.0","gitHead":"5255cfbc08de809a4a7af74e44335a28c93a3a5e","bugs":{"url":"https://github.com/jhs/txn/issues"},"_id":"txn@1.0.1","_shasum":"162414a65b62689d1c26791382a653402fb0e8f0","_from":".","_npmVersion":"2.11.0","_nodeVersion":"2.2.1","_npmUser":{"name":"jhs","email":"jason.h.smith@gmail.com"},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"},{"name":"jcrugzz","email":"jcrugzz@gmail.com"}],"dist":{"shasum":"162414a65b62689d1c26791382a653402fb0e8f0","tarball":"https://registry.npmjs.org/txn/-/txn-1.0.1.tgz","integrity":"sha512-9NupkkIGvW8GpDmdLVdFyhpJlF/QGTuwR1EKS5+gWl+2YHvj4FyQV7aAUOSZhgVaFT7WeW+CRjS7nARnN9eCiA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBd+SHBWmS/6VfTm35/cMPTRMsqu8YLtbDFZ9uMLeFAWAiBTOstCdXaY13kuA9Gldq40SyPpnn8OzNGHnITWTI2keA=="}]}},"1.1.0":{"name":"txn","version":"1.1.0","author":{"name":"Jason Smith","email":"jason.h.smith@gmail.com"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/jhs/txn","repository":{"type":"git","url":"git://github.com/jhs/txn.git"},"engines":["node"],"scripts":{"test":"tap test/txn.js","test-pouchdb":"env couchdb= tap test/txn.js","test-couchdb":"env couchdb=${couchdb:-http://127.0.0.1:5984} node test/txn.js"},"dependencies":{"browser-request":"~0.2.1","debug":"^2.1.0","defaultable":"~0.7.2","obj_diff":"~0.2.0","request":"^2.57.0"},"devDependencies":{"memdown":"^1.0.0","pouchdb":"^3.6.0","tap":"^1.2.0"},"browser":{"request":"browser-request"},"main":"api.js","license":"Apache 2.0","gitHead":"7eefa25cf7967195f43df86917b63d2ab16ec65d","bugs":{"url":"https://github.com/jhs/txn/issues"},"_id":"txn@1.1.0","_shasum":"4dc3942cc327de548b93102a42f8bc115adf1fd5","_from":".","_npmVersion":"2.11.0","_nodeVersion":"2.2.1","_npmUser":{"name":"jhs","email":"jason.h.smith@gmail.com"},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"},{"name":"jcrugzz","email":"jcrugzz@gmail.com"}],"dist":{"shasum":"4dc3942cc327de548b93102a42f8bc115adf1fd5","tarball":"https://registry.npmjs.org/txn/-/txn-1.1.0.tgz","integrity":"sha512-N4Ifl4/aR1ZtA14j27Cw9brQZsJ3ycRabtuGpkH8UKoPP3+LnSIuRMjosN+UNdhFx4xSgmNvmfRoU4Yy/KGNOQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCMpk3QNq/jcNQ7NRIVELSd+roKe+qeXTGxMesKisYy3wIhAJ5ivnmMLdlRinMFWdY4Dc8UExfV2zaZ9pKEc6s6/zxQ"}]}},"1.1.1":{"name":"txn","version":"1.1.1","author":{"name":"Jason Smith","email":"jason.h.smith@gmail.com"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/jhs/txn","repository":{"type":"git","url":"git://github.com/jhs/txn.git"},"engines":["node"],"scripts":{"test":"tap test/txn.js","test-pouchdb":"env couchdb= tap test/txn.js","test-couchdb":"env couchdb=${couchdb:-http://127.0.0.1:5984} node test/txn.js"},"dependencies":{"browser-request":"~0.2.1","debug":"^2.1.0","defaultable":"~0.7.2","obj_diff":"~0.2.0","request":"^2.57.0"},"devDependencies":{"memdown":"^1.0.0","pouchdb":"^3.6.0","tap":"^1.2.0"},"browser":{"request":"browser-request"},"main":"api.js","license":"Apache 2.0","gitHead":"828ee4c7584a6dd6e49b91a09c6270f3b399a5c4","bugs":{"url":"https://github.com/jhs/txn/issues"},"_id":"txn@1.1.1","_shasum":"66bd1d00506a3ce8279db49e5cc168723d878f3d","_from":".","_npmVersion":"2.11.0","_nodeVersion":"2.2.1","_npmUser":{"name":"jhs","email":"jason.h.smith@gmail.com"},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"},{"name":"jcrugzz","email":"jcrugzz@gmail.com"}],"dist":{"shasum":"66bd1d00506a3ce8279db49e5cc168723d878f3d","tarball":"https://registry.npmjs.org/txn/-/txn-1.1.1.tgz","integrity":"sha512-WwD1f+C499cLE98Y3BKwWwOQ9hC7dHd8liZiNC4Fvzaa988XJBgY7ZjAp/c2oJITOlch7uqK7NUkeSbtptyjcw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHtI11gjfhuhNmd1257XDJXG/vpjyv8+ReCeksoOcQIAAiBkdQf9VkFMi+vkSNxbp59uvmvGL6uGaEhk+y890kY7rQ=="}]}},"1.1.2":{"name":"txn","version":"1.1.2","author":{"name":"Jason Smith","email":"jason.h.smith@gmail.com"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/jhs/txn","repository":{"type":"git","url":"git://github.com/jhs/txn.git"},"engines":["node"],"scripts":{"test":"tap test/txn.js","test-pouchdb":"env couchdb= tap test/txn.js","test-couchdb":"env couchdb=${couchdb:-http://127.0.0.1:5984} node test/txn.js"},"dependencies":{"browser-request":"~0.2.1","debug":"^2.1.0","defaultable":"~0.7.2","obj_diff":"~0.2.0","pouchdb":"^5.3.0","request":"^2.57.0"},"devDependencies":{"memdown":"^1.0.0","pouchdb":"^3.6.0","tap":"^1.2.0"},"browser":{"request":"browser-request"},"main":"api.js","license":"Apache 2.0","gitHead":"0a6876d2c3fd05a16d1a8fe86661f1acfb175bab","bugs":{"url":"https://github.com/jhs/txn/issues"},"_id":"txn@1.1.2","_shasum":"8c4eb6e648b312010a585033725e692b7d37f237","_from":".","_npmVersion":"3.3.12","_nodeVersion":"5.5.0","_npmUser":{"name":"jhs","email":"jason.h.smith@gmail.com"},"dist":{"shasum":"8c4eb6e648b312010a585033725e692b7d37f237","tarball":"https://registry.npmjs.org/txn/-/txn-1.1.2.tgz","integrity":"sha512-ZZsM/TmfsU7JO6JUhQTimgmJveEPH3/iiiniA/ByGot9Se+/zcqePQ1zx321YL5sH/fpy4jiEC9Vmyt05s0rWg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCkVt8ssw9MQQ9A0IyIpNvdnmNjpPdSN/XtOf7MtSkLvwIhAJEFsedNG0Bcneefmzq7d8OM7cIVl/0vppzMvNPyAgkc"}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"},{"name":"jcrugzz","email":"jcrugzz@gmail.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/txn-1.1.2.tgz_1457193323733_0.43898564181290567"}},"1.2.0":{"name":"txn","version":"1.2.0","author":{"name":"Jason Smith","email":"jason.h.smith@gmail.com"},"description":"Process and update CouchDB data in atomic, all-or-nothing transactions","tags":["couchdb","transaction","transactions"],"homepage":"http://github.com/jhs/txn","repository":{"type":"git","url":"git://github.com/jhs/txn.git"},"engines":["node"],"scripts":{"test":"tap test/txn.js","test-pouchdb":"env couchdb= tap test/txn.js","test-couchdb":"env couchdb=${couchdb:-http://127.0.0.1:5984} node test/txn.js"},"dependencies":{"async":"^2.0.0-rc.6","browser-request":"~0.2.1","debug":"^2.1.0","defaultable":"~0.7.2","obj_diff":"^0.3.0","pouchdb":"^5.3.0","request":"^2.57.0"},"devDependencies":{"memdown":"^1.0.0","pouchdb":"^3.6.0","tap":"^1.2.0"},"browser":{"request":"browser-request"},"main":"api.js","license":"Apache-2.0","gitHead":"398cf5ccae734006e708252990020b58750dbd35","bugs":{"url":"https://github.com/jhs/txn/issues"},"_id":"txn@1.2.0","_shasum":"7fe038e8c625b7da4bb90024316c8fa632a0b2f1","_from":".","_npmVersion":"3.8.9","_nodeVersion":"6.2.0","_npmUser":{"name":"jhs","email":"jason.h.smith@gmail.com"},"dist":{"shasum":"7fe038e8c625b7da4bb90024316c8fa632a0b2f1","tarball":"https://registry.npmjs.org/txn/-/txn-1.2.0.tgz","integrity":"sha512-bcUUprYgUx+lrrheu6Tvs3bYp9f4CTI2JjM9Z2XbXIkyas8n5Z7dInmzngVdH5WuMEjyLpHVgajj3R4XG9A3Ig==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDjnCA0AbgaIhAxPA8L9a1XbOQz0LWBmyPeb1wMEwXLjQIgAL8RwO57RD+lWgfMi7jlCX5UZSSR6efSOTbBfxFW29I="}]},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"},{"name":"jcrugzz","email":"jcrugzz@gmail.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/txn-1.2.0.tgz_1465564523836_0.4200557030271739"}}},"maintainers":[{"name":"jhs","email":"jhs@iriscouch.com"},{"name":"jcrugzz","email":"jcrugzz@gmail.com"}],"time":{"modified":"2022-06-28T00:34:25.204Z","created":"2011-10-03T21:00:04.964Z","0.1.0":"2011-10-03T21:00:05.489Z","0.2.0":"2011-10-04T14:22:22.918Z","0.2.1":"2011-10-13T18:10:54.559Z","0.2.2":"2011-11-22T02:44:29.780Z","0.2.3":"2011-11-22T03:20:41.014Z","0.2.4":"2011-11-28T10:54:50.994Z","0.2.5":"2011-12-12T10:43:55.314Z","0.2.6":"2011-12-26T02:12:04.775Z","0.2.7":"2012-03-26T03:21:40.701Z","0.2.8":"2012-03-26T05:06:16.240Z","0.2.9":"2012-04-07T09:34:28.234Z","0.2.10":"2012-11-05T07:32:12.882Z","0.2.11":"2013-03-21T08:42:09.274Z","0.2.12":"2013-04-04T12:22:19.479Z","0.2.14":"2014-07-28T17:44:40.210Z","0.2.15":"2014-12-05T16:05:27.961Z","0.2.16":"2014-12-07T21:01:11.523Z","1.0.0":"2015-06-08T16:13:41.073Z","1.0.1":"2015-06-08T17:01:30.907Z","1.1.0":"2015-06-09T04:24:32.164Z","1.1.1":"2015-06-12T14:23:51.501Z","1.1.2":"2016-03-05T15:55:25.078Z","1.2.0":"2016-06-10T13:15:24.390Z"},"author":{"name":"Jason Smith","email":"jason.h.smith@gmail.com"},"repository":{"type":"git","url":"git://github.com/jhs/txn.git"},"homepage":"http://github.com/jhs/txn","readme":"# Transaction: JavaScript ACID objects\n\n[![build\nstatus](https://secure.travis-ci.org/nodejitsu/txn.png)](http://travis-ci.org/nodejitsu/txn)\n\nTransaction (or *Txn*) is a library to load, modify, and commit JavaScript objects in atomic, all-or-nothing operations. It comes from internal Iris Couch tooling, inspired by Google [App Engine transactions][app_engine_txn].\n\nTransaction is great for making discrete changes to CouchDB, Cloudant, and PouchDB documents.\n\n## Objective\n\nTxn **guarantees** that data modifications either *commit* completely, or *roll back* completely ([MVCC][mvcc]). Txn automatically and transparently retries the operation a few times until it commits. I like me some transaction and you should too:\n\n1. Write a simple, clear *operation* function to process a chunk of data (JavaScript object)\n1. Other parts of the program trigger the operation for various objects with various IDs.\n1. Operations might accidently run *multiple times*, even *concurrently*, perhaps behaving *unpredictably*, probably *timing out* when web sites go down. In other words, it is working within the real world.\n1. No matter. Transaction ensures that, for a given object ID, changes are atomic, consistent, isolated, and durable (ACID guarantees).\n\n## Easy transactions\n\nInstall Transaction with NPM\n\n    $ npm install txn\n\nUsage:\n\n```javascript\nvar txn = require(\"txn\");\nvar request = require('request');\n\nvar url = \"https://example.cloudant.com/my_db/my_doc\";\n\ntxn({uri:url}, change_the_doc, change_done);\n\nfunction change_the_doc(doc, to_txn) {\n  // I run on the doc that is fetched. Usually, I run once. But, if Txn detects\n  // a document conflict, I may run multiple times as Txn retries.\n  doc.awesome = (doc.type == \"teacher\") ? true : 'maybe';\n  request(\"http://twitter.com/\" + doc.twitter, function(er, resp, body) {\n    if(er)\n      return to_txn(er);\n    doc.twitter_feed = body;\n    return to_txn();\n  })\n}\n\nfunction change_done(error, newDoc) {\n  // I run once, after the transaction is complete.\n  if(error)\n    return console.log(\"Sorry, the change didn't stick: \" + error);\n  else\n    console.log(\"Yay! The new doc is: \" + JSON.stringify(newDoc));\n})\n```\n\n<a name=\"pouchdb\"></a>\n## PouchDB\n\nTxn supports PouchDB. The npm package provides a PouchDB plugin.\n\n```javascript\nvar PouchDB = require('PouchDB');\nvar Txn = require('txn');\n\n// Load Txn support into PouchDB.\nPouchDB.plugin(Txn.PouchDB);\n\n// Now your PouchDB database has transaction support!\nvar db = new PouchDB('example');\n\n// This operation adds 5 to a \"count\" field.\nfunction add_five(doc, to_txn) {\n  if (!doc.count) {\n    doc.count = 0;\n  }\n\n  doc.count = doc.count + 5;\n  return to_txn();\n}\n\ndb.txn({id:'my_doc', create:true, timestamps:true}, add_five, function(er, doc) {\n  if (er)\n    console.log('Problem creating my_doc: ' + er);\n  else\n    console.log('Document created ' + doc.created_at + ' count = ' + doc.count);\n})\n```\n\n<a name=\"serial\"></a>\n## Serial Transactions\n\nTxn eliminates a classic mistake when using an MVCC database: lost concurrent updates. Txn is here to simplify and clarify concurrent updates.\n\n```javascript\nvar PouchDB = require('PouchDB');\nvar Txn = require('txn');\nPouchDB.plugin(Txn.PouchDB);\n\nvar db = new PouchDB('example');\n\n// Add five points. What could be simpler?\nfunction add_five(doc, to_txn) {\n  doc.points = (doc.points || 0) + 5;\n  return to_txn();\n}\n\n// Run add_five three times, at the same time! The result will always be 15.\ndb.txn({id:'points', create:true}, add_five, add_done);\ndb.txn({id:'points', create:true}, add_five, add_done);\ndb.txn({id:'points', create:true}, add_five, add_done);\n\nfunction add_done(er, doc, txr) {\n  if (er) {\n    console.log('PouchDB error while tabulating points: ' + er);\n  } else {\n    // txr is the \"transaction result\" which you can usually ignore.\n    console.log('It took '+txr.tries+' tries to give you '+doc.points+' points');\n  }\n}\n```\n\nExample output:\n\n```\nIt took 1 tries to give you 5 points\nIt took 2 tries to give you 10 points\nIt took 3 tries to give you 15 points\n```\n\nWhat that means:\n\n1. One Txn call stored `{\"points\":5}` on the first try. The others both failed with a conflict. So they each retried.\n2. A second Txn call then succeeded, storing `{\"points\":10}` on its second try. But the third failed yet again.\n3. The third Txn call finally succeeded, storing `{\"points\":10}` on its third try.\n\nIf this example is confusing or uninteresting to you, not to worry! In any case, Txn is usually simpler than writing your own fetching and storing code for your database. Just provide a document ID, and a function to change the document.\n\n<a name=\"api\"></a>\n## API\n\n### Setting default options\n\nTransaction uses [Defaultable][def]. You can set defaults which will always apply. You can also set defaults based on previous defaults.\n\n```javascript\n// Global defaults for everything.\nvar txn = require('txn').defaults({\"timestamps\":false, \"couch\":\"http://localhost:5984\"});\n\n// Specific defaults for different databases. (timestamps and couch from above still apply.)\nvar user_txn = txn.defaults({\"db\":\"users\", \"delay\":1000, \"timeout\":45000});\nvar jobs_txn = txn.defaults({\"db\":\"jobs\" , \"delay\":100 , \"create\": true});\n\n// Now things look much better.\nuser_txn({id:\"bob\"}, do_user, on_user_txn);\njobs_txn({id:\"cleanup\"}, do_job, on_job_txn);\n```\n\n### Basic idea\n\nTransaction helps you *fetch, modify, then store* some JSON. It has a simple call signature, and you can set temporary or permanent defaults (see below).\n\ntxn(**request_obj**, **operation_func**, **txn_callback_func**)\n\n### request_obj\n\nThe **request_obj** is for the [request][req] module. (Txn uses *request* internally.) Txn supports some additional optional fields in this object.\n\n* Mandatory: Some location of the data. Everything else is optional.\n  * For **CouchDB**, including **Cloudant**:\n    * *either* **uri** | Location to GET the data and PUT it back. Example: `\"https://me:secret@example.iriscouch.com/my_db/my_doc\"`\n    * *or* broken into parts:\n       * **couch** | URI of the CouchDB server. Example: `\"https://me:secret@example.iriscouch.com\"`\n       * **db** | Name of the Couch database. Example: `\"my_db\"`\n       * **id** | ID of the Couch document. Example: `\"my_doc\"`\n  * For **PouchDB**, only the **id** field is needed.\n* **create** | If `true`, missing documents are considered empty objects, `{}`, passed to the operation. If `false`, missing documents are considered errors, passed to the callback. Newly-created objects will not have a `_rev` field.\n* **doc** | Skip the first fetch, assume *doc* is initial data value. Notes:\n  * This is useful with `_changes?include_docs=true`\n  * The `._id` can substitute for *id* above. Thus, given a `_changes` event, just use `txn({doc:change.doc}, ...)`\n  * If there is a conflict, Txn will re-fetch the document as usual! To avoid this, set `max_tries=1`.\n  * Not supported by `.defaults()`\n* **timestamps** | Automatically add an `updated_at` field when updating and `created_at` when creating. Default: `false`\n* **max_tries** | How many times to run the fetch/operation/store cycle before giving up. An MVCC conflict triggers a retry. Default: `5`\n* **after** | Milliseconds to postpone the *first* operation. (A random value is a good way to load-balance job consumers). Default: `null` i.e. run immediately\n* **delay** | Milliseconds to wait before *retrying* after a conflict. Each retry doubles the wait time. Default: `100`\n* **timeout** | Milliseconds to wait for the **operation** to finish. Default: `15000` (15 seconds)\n* **log** | Logger object to use. Default is a debug function in the namespace \"txn\"\n\nFor example:\n\n```javascript\n{ uri       : \"https://me:secret@example.iriscouch.com/_users/org.couchdb.user:bob\"\n, create    : true          // Use missing doc IDs to create new docs\n, timestamps: true          // Automatic created_at and updated_at fields\n, timeout   : 5 * 60 * 1000 // Five minutes before assuming the operation failed.\n}\n```\n\n### operation_func\n\nThis is your primary *worker function* to receive, react-to, and modify the data object. **Txn will wrap this function in fetch/store requests.** If there is an MVCC conflict, **Txn will fetch again, re-run this function, and store again**. If you give this function a name, it will be reflected in Txn's logs. So make it count!\n\nThe function receives two parameters.\n\n1. The fetched JSON object, often called **doc**\n2. A callback to return processing to Txn, often called **to_txn**. The callback takes two parameters:\n  1. An error object\n  2. An optional *replacement object*. If provided, modifications to **doc** are ignored and this object is used instead.\n\n```javascript\nfunction make_a_contestant(user, to_txn) {\n  if(! user._rev) {\n    // Creating a user.\n    user.type = \"user\";\n    user.name = \"bob\";\n    user.roles = [];\n  }\n\n  // Demonstrate sending an Error to the transaction callback function.\n  if(require(\"os\").hostname() == \"staging\")\n    return to_txn(new Error(\"Making contestants may not run on the staging server\"));\n\n  // People named Joe may not play. Demonstrates sending a replacement object.\n  if(user.name == \"joe\")\n    return to_txn(null, {\"_deleted\": true});\n\n  user.roles.push(\"contestant\");\n  if(Math.random() < 0.5)\n    user.roles.push(\"red_team\");\n  else\n    user.roles.push(\"blue_team\");\n\n  return to_txn();\n}\n```\n\nNote, Txn automatically sets the `_id` and `_rev` fields. The operation function needn't bother.\n\n### txn_callback_func\n\nWhen Txn is all done, it will run your final callback function with the results.\n\nThe callback function receives three parameters:\n\n1. An error object, either from Txn (e.g. too many conflicts, operation timeout, HTTP error) or the one sent by *operation_func*. Txn will set various fields depending on the type of error.\n  * `timeout` if the operation function timed out.\n  * `conflict` and `tries` if there was an MVCC conflict and the number of retries was exhausted\n2. The final committed object.\n3. A transaction result object with information about the process. Useful fields:\n  * `tries`: The number of tries the entire run took (`1` means the operation worked on the first try)\n  * `name`: The name of this transaction (your operation function name)\n\n```javascript\nfunction after_txn(error, doc, txr) {\n  if(error) {\n    console.error(\"Failed to run transaction after \" + txr.tries + \" attempts\");\n    throw error;\n  }\n\n  console.log(\"Transaction success: \" + doc._id);\n\n  // Application code continues.\n}\n```\n\n### Transaction Result: txr\n\nYour callback receives a third argument, `txr`, the transaction result. Usually, you simply check the error argument to see if the transaction succeeded or failed. But the `txr` object contains the details about the execution. Properties:\n\n* **tries**: Integer, the number of times the full transaction cycle ran (fetch, modify, store)\n* **fetches**: Integer, the number of times Txn fetched the document from the database; usually the same as *tries* unless you provide a `doc` parameter, telling Txn to skip the first fetch\n* **stores**: Integer, the number of times Txn attempted to store the document in the database; usually the same as *tries* unless Txn encountered an error\n* **is_create**: Boolean, `true` if the document was created for the first time; `false` if the document was updated from a prior revision\n\nFor example, if you already know of a document in the database and you try to update it\n\n``` javascript\n// My application already knows this, perhaps from a _changes feed.\nvar doc = {_id:\"my_doc\", _rev:\"3-0f3e848a3249737d5814bdd60228ae77\", count:3};\n\ntxn({doc:doc}, increment, on_done);\n\nfunction increment(doc, to_txn) {\n  doc.count = doc.count + 1;\n  return to_txn();\n}\n\nfunction on_done(er, doc, txr) {\n  console.log('Tries:' + txr.tries + ' Fetches:' + txr.fetches);\n}\n```\n\nThe above example tells Txn to be optimistic, and to assume that we already know the document \"my_doc\". If the update runs with no conflicts, the output will be:\n\n    Fetches:0 Tries:1\n\nAnd thus we saved a full GET round-trip! However, if the document was out of date, *the code still works as-is*:\n\n    Fetches:1 Tries:2\n\nTxn tried the update, encountered a conflict, then fetched the latest document revision to process.\n\n## Example: account signup\n\nConsider account signup as a stateful workflow:\n\n* **requested** (performed by user): User submits their username and email address\n* **emailed** (performed by server): Approved the request and emailed the user\n* **confirmed**: (performed by user): User clicked the email link and confirmed signup\n* **done**: (performed by server): Initial account is set up and ready to use.\n\nThe code:\n\n```javascript\n// Usage: signup.js <username>\nvar txn = require(\"txn\");\nvar username = process.env.username;\nvar user_uri = \"http://example.iriscouch.com/users/\" + username;\n\n// Execute the signup processor and react to what happens.\ntxn({\"uri\":user_uri}, process_signup, function(error, newData) {\n  if(!error)\n    return console.log(\"Processed \" + username + \" to state: \" + newData.state);\n\n  // These errors can be sent by Txn.\n  if(error.timeout)\n    return console.log(\"Gave up after \" + error.tries + \" conflicts\");\n  if(error.conflict)\n    return console.log(\"process_signup never completed. Troubleshoot and try again\");\n\n  // App-specific errors, made by process_signup below.\n  if(error.email)\n    return console.log('Failed to email: ' + username);\n  if(error.account)\n    return console.log('Failed to create account: ' + username);\n\n  throw error; // Unknown error\n})\n\nfunction process_signup(doc, to_txn) {\n  if(doc.state == 'requested') {\n    if(! valid_request(doc))\n      return to_txn(null, {\"_deleted\":true}); // Return a whole new doc.\n\n    doc.emailed_by = require('os').hostname();\n    doc.signup_key = Math.random();\n    send_email(doc.email, doc.signup_key, function(error) {\n      if(error) {\n        error.email = true;\n        return to_txn(error); // Roll back\n      }\n      doc.state = 'emailed';\n      return to_txn();\n    })\n  }\n\n  // If the data is unchanged, Txn will not write to the back-end. This operation is thus read-only.\n  else if(doc.state == 'emailed') {\n    console.log('Still waiting on user to click email link.');\n    return to_txn();\n  }\n\n  else if(doc.state == 'confirmed') {\n    doc.confirmed_at = new Date;\n    create_account(doc.username, function(error) {\n      if(error) {\n        error.account = true;\n        return to_txn(error);\n      }\n      doc.confirmed_by = require('os').hostname();\n      doc.state = 'done';\n      return to_txn();\n    })\n  }\n}\n```\n\n## Considerations\n\nTransaction is great for job processing, from a CouchDB `_changes` feed for example. Unfortunately, jobs are for *doing stuf* (create an account, save a file, send a tweet) and the useful \"stuff\" are all side-effects. But Txn only provides atomic *data*. It cannot roll-back side-effects your own code made.\n\nThus the best Txn functions are [reentrant][reent]: At any time, for any reason, a txn function might begin executing anew, concurrent to the original execution, perhaps with the same input parameters or perhaps with different ones. Either execution path could finish first. (The race loser will be rolled back and re-executed, this time against the winner's updated data.)\n\n[app_engine_txn]: http://code.google.com/appengine/docs/python/datastore/transactions.html\n[mvcc]: http://en.wikipedia.org/wiki/Multiversion_concurrency_control\n[reent]: http://en.wikipedia.org/wiki/Reentrancy_(computing)\n[follow]: https://github.com/iriscouch/follow\n[req]: https://github.com/mikeal/request\n[def]: https://github.com/iriscouch/defaultable\n","readmeFilename":"README.md","bugs":{"url":"https://github.com/jhs/txn/issues"},"license":"Apache-2.0"}