{"_id":"invisible","_rev":"40-6b245b9109ca60f0f3e783031ad8ef82","name":"invisible","description":"DRY models for client and server","dist-tags":{"latest":"0.4.1"},"versions":{"0.0.0":{"name":"invisible","version":"0.0.0","description":"DRY models for client and server","main":"index.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"_id":"invisible@0.0.0","dist":{"shasum":"68cf07b5cda3c1abca4b5acc3e70ef3513215229","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.0.0.tgz","integrity":"sha512-JwmOpK2TZ/dU8TQKoWzyxBeqkwwe0HKYeLkUKdu/KB1C3p5W+to+MnRbvjMUxQUY6cYtpNMe9ipzRXaDRJKXzA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEkhi4b5POdZZyPfycjmPckwzP60z4xQ1cmCi6RO9UFRAiBmSHeu9/xpxefltfyMYc/GB6Y7Kn79hFBSeQVLbXzefA=="}]},"_from":".","_npmVersion":"1.2.32","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"}]},"0.1.0":{"name":"invisible","version":"0.1.0","description":"DRY models for client and server","main":"index.js","scripts":{"test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3"},"_id":"invisible@0.1.0","dist":{"shasum":"1f308970cda40b0fb7586082a8a27ae0924c1559","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.1.0.tgz","integrity":"sha512-Fwd9W6kMcz3HReYHEO2Y3jQIDM1hwgGlmKcQgiTINlbixtm8tZgFFPwXXBuELjwdBmNi5gdfVXAgCudQ4Vp9WQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID6+QYXz9wo8AqNqw8QcJ4Hb2kWvXyiimjuDa7dBVlnlAiEAyRO8zVeAHluJWlndx/vnwykw3azWnEjsdnoVJXG/o6c="}]},"_from":".","_npmVersion":"1.3.8","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"}]},"0.1.1":{"name":"invisible","version":"0.1.1","description":"DRY models for client and server","main":"index.js","prepublish":"grunt coffee","scripts":{"test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3"},"_id":"invisible@0.1.1","dist":{"shasum":"3bd46c3b33886ea61976f90bac8dc5c786f64272","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.1.1.tgz","integrity":"sha512-qmjyU9NIdhFI3HjNIavd62BiesXYo3Cp07x6TNgfAFERxVT5LOur3abSyqGDpp21RhLlZvVTd1NUs9uXlIUG0g==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG9KmdgqVhNP7Kaxqbl9SHbksMJzyf7M/wCgJ5S9B61cAiAyzr3yMHIuJpjXnG6d23S1zaqeMiqsnY6J3N1xYPjmjA=="}]},"_from":".","_npmVersion":"1.3.8","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"}]},"0.1.2":{"name":"invisible","version":"0.1.2","description":"DRY models for client and server","main":"index.js","prepublish":"grunt coffee","scripts":{"test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3"},"_id":"invisible@0.1.2","dist":{"shasum":"069782bfcfaa1405da7a0948fd4aced31226e7e0","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.1.2.tgz","integrity":"sha512-otHSOaapOqENNZMYTsKDPtyCy3Tyvs2t4I3cOnTGkT3SPuHS8rD3YObfGmkR3FLEjpGS7MGTm5x6jafQegMS1A==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH4eoK+JmYNB0M03yuqAC4QaKtrgeZeNvHBihw5MXG9PAiAHWs0BvMdmECZJUncZMekkdhAdt9a7IhRj0MzFZm1a1A=="}]},"_from":".","_npmVersion":"1.3.8","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"}]},"0.1.3":{"name":"invisible","version":"0.1.3","description":"DRY models for client and server","main":"index.js","scripts":{"prepublish":"grunt coffee","test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3"},"_id":"invisible@0.1.3","dist":{"shasum":"da825b828aa73d67193e84d702303d8fceaf21a0","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.1.3.tgz","integrity":"sha512-b29ortcAbyneJvquZOV/0YeXtlDSCxgxMlXdv1BP5bV4sPL+gX+/q2RtxfRAoygQ5yon2VZhSUiA4FyfFS26rQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGsHbXHmTljvgWVTpzva79ThRX8sbXov5rCfofzd6hmzAiBWJjc6frdF5366LgXeAykBsqZuTC4U5rLxkAzz6QfYmQ=="}]},"_from":".","_npmVersion":"1.3.8","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"}]},"0.1.4":{"name":"invisible","version":"0.1.4","description":"DRY models for client and server","main":"index.js","scripts":{"prepublish":"grunt coffee","test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3","nock":"git://github.com/facundoolano/nock","supertest":"~0.7.1","express":"~3.4.0"},"_id":"invisible@0.1.4","dist":{"shasum":"4fe85e82c1949ceddbe5028cdb0b63f340968f92","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.1.4.tgz","integrity":"sha512-CnWhN2dk/zWC6TFdCzx9m8LDJl3VVxeeX/75I8nOiKMdWeniatEIlBF0o1kLo4AOpW+U13Us8CLVUjMBh0SBxA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD7e0bUNgewGGkYlp0z9i68NCis+EGKGnbUlj9+2VOLyQIgbwJo7dBVrZ/YzvKfztfKi3fhO00HRym3TJoeN4VSZL4="}]},"_from":".","_npmVersion":"1.3.2","_npmUser":{"name":"facundoolano","email":"facundo.olano@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}]},"0.1.5":{"name":"invisible","version":"0.1.5","description":"DRY models for client and server","main":"index.js","scripts":{"prepublish":"grunt coffee","test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17","revalidator":"~0.1.5"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3","nock":"git://github.com/facundoolano/nock","supertest":"~0.7.1","express":"~3.4.0"},"_id":"invisible@0.1.5","dist":{"shasum":"31b1147816d2bc118289b61c6c636c646a9e0970","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.1.5.tgz","integrity":"sha512-Mz1G09/2IdTm4hgXjRpmc8WOaVfj9B+LVrwd16tKJ3wS+IoO2/WNjQ/6ieE9pgREUL7vsU4PCV1utah+ILeQdA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICVUe8SIjC7U8BFeTy+yVXFgc2qe76klhf9fng/gGV7uAiEA/IYDnTPud4iFgmCbnZiDOPk3iv+B/S/IDGsx9Bs4JEg="}]},"_from":".","_npmVersion":"1.3.2","_npmUser":{"name":"facundoolano","email":"facundo.olano@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}]},"0.1.6":{"name":"invisible","version":"0.1.6","description":"DRY models for client and server","main":"index.js","scripts":{"prepublish":"grunt coffee","test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17","revalidator":"git://github.com/facundoolano/revalidator"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3","nock":"git://github.com/facundoolano/nock","supertest":"~0.7.1","express":"~3.4.0"},"_id":"invisible@0.1.6","dist":{"shasum":"55bb198cd4e13571e433448db6e375361b51c5ab","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.1.6.tgz","integrity":"sha512-2qtvAOAq/sJ+IQyQxr0vOzD4sIWrO3d7a/NAbWX9xbJgtDogBrMQQVIes1yfKvziL3PXVjAEdtTTwScUkG6EnQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDZH6cQq3Qs+CWaPxJHj3dKE7XRyK4F3uDq31fJ1PE9WwIgQHNVnzDMuFw4dyDG0WwDbCasHV6aqon3ELlKLR/MS9c="}]},"_from":".","_npmVersion":"1.3.2","_npmUser":{"name":"facundoolano","email":"facundo.olano@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}]},"0.1.7":{"name":"invisible","version":"0.1.7","description":"DRY models for client and server","main":"index.js","scripts":{"prepublish":"grunt coffee","test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17","socket.io":"~0.9.16","revalidator":"git://github.com/facundoolano/revalidator"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3","nock":"git://github.com/facundoolano/nock","supertest":"~0.7.1","express":"~3.4.0","socket.io-client":"~0.9.16"},"_id":"invisible@0.1.7","dist":{"shasum":"c18f068af4f53f8569f322953d1b0213d9103a75","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.1.7.tgz","integrity":"sha512-XJuLdHeO/F83lISbmieOiGgwYBp4NRlUfQwqICAfSDrXMcr9k9avZgmD5WAq8AO2b65rkr9YUGASd78b4jJcjw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGgF91pAZegjg60wvv3vBArHWBMHylfDZPEcHwmy59t7AiBRExzzJR8mYF6RaK9+R1Kj0oV0vM+hLAgOgaTaeCAfMA=="}]},"_from":".","_npmVersion":"1.3.2","_npmUser":{"name":"facundoolano","email":"facundo.olano@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}]},"0.2.0":{"name":"invisible","version":"0.2.0","description":"DRY models for client and server","main":"index.js","scripts":{"prepublish":"grunt coffee","test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17","socket.io":"~0.9.16","revalidator":"git://github.com/facundoolano/revalidator"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3","nock":"git://github.com/facundoolano/nock","supertest":"~0.7.1","express":"~3.4.0","socket.io-client":"~0.9.16"},"_id":"invisible@0.2.0","dist":{"shasum":"7d165110787b784405875979c67760e523ae8812","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.2.0.tgz","integrity":"sha512-gR5nUqKWIuAyEwOwciZ4UV+ozceRgW/metpgmpOxkqvYidO8OYGBAhf1FEjpFTdNFrnVqnjGNbI7+guyLgaW9w==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGOb1fSytAwtGd+iPB/b0QYgDPsJO2uo4VP/Dh1WJzKEAiAnuVVm3/KqdSwIG6pc6osRMO9X2NCWf5WB+qBVzIX43g=="}]},"_from":".","_npmVersion":"1.3.11","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}]},"0.2.1":{"name":"invisible","version":"0.2.1","description":"DRY models for client and server","main":"index.js","scripts":{"prepublish":"grunt coffee","test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17","socket.io":"~0.9.16","revalidator":"git://github.com/facundoolano/revalidator"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3","nock":"git://github.com/facundoolano/nock","supertest":"~0.7.1","express":"~3.4.0","socket.io-client":"~0.9.16"},"_id":"invisible@0.2.1","dist":{"shasum":"fb5d2a54675c799fee22ea3716be8d513123f071","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.2.1.tgz","integrity":"sha512-YfoBmt5Vo0rPFx3Oecct4YTrsZdkA+BWabv+ORz1IopfBvJCB7yk1A8+zRQ2PONlNnL7O6FEd+p7LeUtKjfP6g==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDZBcAToKMPah68Qfp5pjSYrvFi9kurUlOQSOEq1XrPBAIgc5UkXcwhrZC6YyWjGT+IKvf8Nrn0oA9BU2w6PYFpcdc="}]},"_from":".","_npmVersion":"1.3.11","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}]},"0.2.2":{"name":"invisible","version":"0.2.2","description":"DRY models for client and server","main":"index.js","scripts":{"prepublish":"grunt coffee","test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17","socket.io":"~0.9.16","revalidator":"git://github.com/facundoolano/revalidator"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3","nock":"git://github.com/facundoolano/nock","supertest":"~0.7.1","express":"~3.4.0","socket.io-client":"~0.9.16"},"_id":"invisible@0.2.2","dist":{"shasum":"482b258ccb621a5a728fee83bcf36a9ebfe5a117","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.2.2.tgz","integrity":"sha512-WbTP+n5SXRRKhngAkk1i0h1K0Y2Ocw571y/04DXATeowG9YOWmb2uhBmDpb+d3MqXAGQ8vi/CrQRreR1eHw14A==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCRGkUmCq8vcufPSTC57MBf8btMTuPbfMUkaahg5ZRRkAIhAOPUzG5jhHT0kO2D6dJ0cipPD+P9+XcLmjv9wl8/ruvz"}]},"_from":".","_npmVersion":"1.3.11","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}]},"0.2.3":{"name":"invisible","version":"0.2.3","description":"DRY models for client and server","main":"index.js","scripts":{"prepublish":"grunt coffee","test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17","socket.io":"~0.9.16","revalidator":"git://github.com/facundoolano/revalidator"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3","nock":"git://github.com/facundoolano/nock","supertest":"~0.7.1","express":"~3.4.0","socket.io-client":"~0.9.16"},"_id":"invisible@0.2.3","dist":{"shasum":"525dc4e345f49c63a64f7f99b66bf90761a4acc4","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.2.3.tgz","integrity":"sha512-ZspZ3yigspxgUtC3yESCT/o6YZTBugI0dE3WF5TVNzTVTe/68V96lBjJbUjjxaDsX3tRv1F2ON4bcgZ92hXsRw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCFbPCYe/4aYZ1MfzxDn7ARwGep0O/wk7wvFuERK4O9IAIhAKXBsyE4ja50xW7Fi6as5dvpPNVcN9c0R09e0EfaCvGf"}]},"_from":".","_npmVersion":"1.3.11","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}]},"0.2.4":{"name":"invisible","version":"0.2.4","description":"DRY models for client and server","main":"index.js","scripts":{"prepublish":"grunt coffee","test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17","socket.io":"~0.9.16","revalidator":"git://github.com/facundoolano/revalidator"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3","nock":"git://github.com/facundoolano/nock","supertest":"~0.7.1","express":"~3.4.0","socket.io-client":"~0.9.16"},"_id":"invisible@0.2.4","dist":{"shasum":"22b9a2e7ce13015f3597d2d5342be284ffab65f1","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.2.4.tgz","integrity":"sha512-F6ITupaAGg6FMUoCpEzEX29IysWijrbTCKKMFd95zKaPDLnlLcDlLlrojcOGATG0DDn5mLuOb4Vyy4HmqIM7iw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCrMnK9nNr9ptTEIOlayzGxpvjQK+yYaYtvfG37yPkTRgIhALoweEGt6Y+KZ3he8jK3mvieqsDAp4KzJJamfERozqho"}]},"_from":".","_npmVersion":"1.3.11","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}]},"0.2.6":{"name":"invisible","version":"0.2.6","description":"DRY models for client and server","main":"index.js","scripts":{"prepublish":"grunt coffee","test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17","socket.io":"~0.9.16","revalidator":"git://github.com/facundoolano/revalidator"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3","nock":"git://github.com/facundoolano/nock","supertest":"~0.7.1","express":"~3.4.0","socket.io-client":"~0.9.16"},"homepage":"https://github.com/sammla/invisible","_id":"invisible@0.2.6","dist":{"shasum":"5b31e13ad45eb5dcdc59c0fedf6e8e0b2b198c66","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.2.6.tgz","integrity":"sha512-vPYxvvn6/d0NbLShsX2fhyEFYXAltxZCTUsBlHsHlTIgdlDzG1syLE6CqR4QKSAbUWdzcxON2EVIKLz63vdxag==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDjgv4qRITfGXw4Vsf4DY88L9gGosRNaBp6y5m0E2MrsgIgMcBk1XZhq4LWCIJGmJlHzDjVyfx8Ah1Cs2zcXqite04="}]},"_from":".","_npmVersion":"1.3.14","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}]},"0.2.7":{"name":"invisible","version":"0.2.7","description":"DRY models for client and server","main":"index.js","scripts":{"prepublish":"grunt coffee","test":"grunt test"},"repository":{"type":"git","url":"git://github.com/sammla/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/sammla/invisible/issues"},"dependencies":{"browserify":"~2.25.1","path":"~0.4.9","coffeeify":"~0.5.1","underscore":"~1.5.1","mongodb":"~1.3.17","socket.io":"~0.9.16","socket.io-client":"~0.9.16","revalidator":"git://github.com/facundoolano/revalidator"},"devDependencies":{"matchdep":"~0.1.2","grunt-contrib-coffee":"~0.7.0","grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-cli":"~0.1.9","grunt-mocha-test":"~0.6.3","nock":"git://github.com/facundoolano/nock","supertest":"~0.7.1","express":"~3.4.0"},"homepage":"https://github.com/sammla/invisible","_id":"invisible@0.2.7","dist":{"shasum":"e2ed2363cbc37d14ecbaaafc72a84fbbfcc91cdf","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.2.7.tgz","integrity":"sha512-Y9B+CBIUGWf/fLzIl5NOdNQnKMcIu74TumkhY18BN0TFAbSIm4yFY7FQmWpFS2vHIbXNt2vhIYqUzbPTUtmjyQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDkc+t24eo/RxazG+3s9sG+5MPIBdL75hE0RzBc07+C4AiBpolzQAO/TxrSsG6wdg6jn2vdAIcogyVfel0ZMi+01ag=="}]},"_from":".","_npmVersion":"1.3.14","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}]},"0.3.0":{"name":"invisible","version":"0.3.0","description":"DRY models for client and server","main":"index.js","scripts":{"test":"grunt test"},"repository":{"type":"git","url":"git://github.com/invisiblejs/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/invisiblejs/invisible/issues"},"dependencies":{"body-parser":"^1.2.0","browserify":"^6.0.3","express":"^4.3.1","grunt":"^0.4.5","mongodb":"^1.4.18","path":"~0.4.9","revalidator":"^0.2.0","socket.io":"^1.1.0","socket.io-client":"^1.1.0","underscore":"^1.7.0"},"devDependencies":{"grunt":"~0.4.1","grunt-contrib-watch":"~0.5.2","grunt-mocha-test":"~0.6.3","matchdep":"~0.1.2","nock":"^0.32.1","supertest":"~0.7.1"},"gitHead":"3b72cae2cc86f169b0cf315c1cd4fec26d94ca19","homepage":"https://github.com/invisiblejs/invisible","_id":"invisible@0.3.0","_shasum":"14734585a1ac69a7de2654d100459abd138c79f3","_from":".","_npmVersion":"2.1.3","_nodeVersion":"0.10.32","_npmUser":{"name":"sammla","email":"martin.c.paulucci@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}],"dist":{"shasum":"14734585a1ac69a7de2654d100459abd138c79f3","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.3.0.tgz","integrity":"sha512-giy0ziJBZdVZ9SgSfuWX7QCnBWRxhO5V6HorUws4LAujq2YqAT4PVCOCASnDxzg9QXiFpKs6YA3ndnn2adeLUA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH8krr8G1w3+0/KOZFT2tNe8vjwqG93TuUewjYqYSsPRAiBFxJFnkMc+CFNymFa2TXlq97JpaDvMWY1c6xUfoNa8IQ=="}]}},"0.4.0":{"name":"invisible","version":"0.4.0","description":"DRY models for client and server","main":"index.js","scripts":{"jscs":"jscs test/ lib/ examples/","jshint":"jshint lib/ test/ examples/","lint":"npm run jshint && npm run jscs","pretest":"npm run lint","test":"mocha test/server/ test/client/"},"repository":{"type":"git","url":"git://github.com/invisiblejs/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/invisiblejs/invisible/issues"},"dependencies":{"body-parser":"^1.2.0","browserify":"9.x","coffee-script":"^1.9.2","coffeeify":"^1.1.0","express":"^4.12.3","mongodb":"^2.0.28","revalidator":"^0.3.0","socket.io":"^1.1.0","socket.io-client":"^1.1.0","socketio-auth":"0.0.1","underscore":"^1.7.0","winston":"^1.0.0"},"devDependencies":{"jscs":"~1.8.0","jshint":"~2.5.10","matchdep":"~0.1.2","mocha":"~1.21.4","nock":"^0.32.1","proxyquire":"^1.0.1","sinon":"^1.10.3","supertest":"~0.7.1"},"gitHead":"5f63dfbe7ee46de0b265c55d3dc5d65db6dd39cb","homepage":"https://github.com/invisiblejs/invisible","_id":"invisible@0.4.0","_shasum":"f5fff3acbdaa85d7920b025abec5e71e9f527fea","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"facundoolano","email":"facundo.olano@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}],"dist":{"shasum":"f5fff3acbdaa85d7920b025abec5e71e9f527fea","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.4.0.tgz","integrity":"sha512-gxCol7jVF/LPgDC6LQShNnoCTxKRM2T2glDAA7nOCgixHyE0OzYCB0MHL5DQH0KNMFr8fOshOsfS+FiYtFTg9Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICC0nJlz8jmx09C8QtJHfRcJnaxIqECsy5RkzHdaYkRnAiEAwoVisTw1wWZBQFxJzZuV/e6H5M60jajbG6JThWtyJZ4="}]}},"0.4.1":{"name":"invisible","version":"0.4.1","description":"DRY models for client and server","main":"index.js","scripts":{"jscs":"jscs test/ lib/ examples/","jshint":"jshint lib/ test/ examples/","lint":"npm run jshint && npm run jscs","pretest":"npm run lint","test":"mocha test/server/ test/client/"},"repository":{"type":"git","url":"git://github.com/invisiblejs/invisible.git"},"author":{"name":"Facundo Olano and Martin Paulucci"},"license":"BSD","bugs":{"url":"https://github.com/invisiblejs/invisible/issues"},"dependencies":{"body-parser":"^1.2.0","browserify":"10.x","coffee-script":"^1.9.2","coffeeify":"^1.1.0","express":"^4.12.3","mongodb":"^2.0.28","revalidator":"^0.3.0","socket.io":"^1.1.0","socket.io-client":"^1.1.0","socketio-auth":"0.0.1","underscore":"^1.7.0","winston":"^1.0.0"},"devDependencies":{"jscs":"~1.8.0","jshint":"~2.5.10","matchdep":"~0.1.2","mocha":"~1.21.4","nock":"^0.32.1","proxyquire":"^1.0.1","sinon":"^1.10.3","supertest":"~0.7.1"},"gitHead":"dac7504e7cdd1ea2e2e1781763bbb1a9d973f6ca","homepage":"https://github.com/invisiblejs/invisible","_id":"invisible@0.4.1","_shasum":"64767c442e33026b89b25f243f6d41fd41225e9c","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"facundoolano","email":"facundo.olano@gmail.com"},"maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}],"dist":{"shasum":"64767c442e33026b89b25f243f6d41fd41225e9c","tarball":"https://registry.npmjs.org/invisible/-/invisible-0.4.1.tgz","integrity":"sha512-JG9QH4uSBmpE3Q50BAGWlDUrm+G5LxmNJIT2wB9iTVTr/Ng/FRTO2ysga/GvVErF3Yam7UlnGyRolHWxWrAeGA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCO4J/hLV/AJ7BAZ7yrVm/93ctFmCSHwzlFZHWCJX8aqgIgHnoKBlhFI775xGtKtdJ8h0vV5xB1y3Q7bJqYMH9yInE="}]}}},"readme":"# [Invisible.js](http://invisiblejs.github.io) [![Build Status](https://secure.travis-ci.org/invisiblejs/invisible.png)](http://travis-ci.org/invisiblejs/invisible) [![Dependencies](https://david-dm.org/invisiblejs/invisible.png)](https://david-dm.org/invisiblejs/invisible) [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/invisiblejs/invisible?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n\nInvisible is a JavaScript library that leverages\n[browserify](https://github.com/substack/node-browserify) to achieve the Holy Grail of web programming:\nmodel reuse in the client and the server.\n\n## Installation and setup\n\nInstall with npm:\n```\nnpm install invisible\n```\n\nWire up Invisible into your [express](http://expressjs.com/) (Works only with Express 4.x) app:\n```javascript\nvar express = require(\"express\");\nvar path = require(\"path\");\nvar invisible = require(\"invisible\");\n\nvar app = express();\n\napp.use(invisible.router({\n  rootFolder: path.join(__dirname, 'models')\n}));\n\napp.listen(3000);\n```\n\n## Extending models\n\nTo make your models available everywhere, define them and call `Invisible.createModel`.\n\n```javascript\n// models/person.js\nvar Invisible = require(\"invisible\");\nvar crypto = require(\"crypto\");\nvar _s = require(\"underscore.string\");\n\nfunction Person(firstName, lastName, email){\n    this.firstName = firstName;\n    this.lastName = lastName;\n    this.email = email;\n}\n\nPerson.prototype.fullName = function(){\n    return this.firstName + ' ' + this.lastName;\n}\n\nPerson.prototype.getAvatarUrl = function(){\n    cleanMail = _s.trim(this.email).toLowerCase();\n    hash = crypto.createHash(\"md5\").update(cleanMail).digest(\"hex\");\n    return \"http://www.gravatar.com/avatar/\" + hash;\n}\n\nmodule.exports = Invisible.createModel(\"Person\", Person);\n```\n\nNow your models will be available under the Invisible namespace. Require as usual in the server:\n\n```javascript\nvar Invisible = require(\"invisible\")\nvar john = new Invisible.models.Person(\"John\", \"Doe\", \"john.doe@mail.com\");\njohn.fullName(); //John Doe\n```\n\nIn the client, just add the invisible script:\n\n```html\n<script src=\"invisible.js\"></script>\n<script>\n    var jane = new Invisible.models.Person(\"Jane\", \"Doe\", \"jane.doe@mail.com\");\n    alert(jane.fullName()); //Jane Doe\n</script>\n```\n\nInvisible.js uses [browserify](https://github.com/substack/node-browserify) to expose you server defined\nmodels in the browser, so you can use any broserify-able library to implement them. Note that this\nintegration is seamless, no need to build a bundle, Invisible.js does that for you on the fly.\n\n## REST and MongoDB integration\n\nIn addition to making your models available everywhere, Invisible extends them with methods to handle\npersistence. In the server this means interacting with MongoDB and in the client making requests to an\nauto-generated REST API, that subsequently performs the same DB action.\n\n### Save\n```javascript\njane.save(function(err, result){\n    if (err){\n        console.log(\"something went wrong\");\n    } else {\n        console.log(\"Jane's id is \" + jane._id);\n        console.log(\"which equals \" + result._id);\n    }\n})\n```\nThe first time the save method is called, it creates the model in the database and sets its `_id` attribute.\nSubsequent calls update the model. Validations are called upon saving, see the validations section for details.\n\nNote that a full Invisible model instance is passed to the callback, and the calling instance is also updated\nwhen the process is done.\n\n### Delete\n```javascript\njane.delete(function(err, result){\n    if (err){\n        console.log(\"something went wrong\");\n    } else {\n        console.log(\"Jane is no more.\");\n    }\n})\n```\n### Query\n\n```javascript\nInvisible.Person.query(function(err, results){\n    if (err){\n        console.log(\"something went wrong\");\n    } else {\n        console.log(\"Saved persons are:\");\n        for (var i = 0; i < results.length; i++){\n            console.log(results[i].fullName());\n        }\n    }\n});\n\nInvisible.Person.query({firstName: \"Jane\"}, function(err, results){\n    if (err){\n        console.log(\"something went wrong\");\n    } else {\n        console.log(\"Persons named Jane are:\");\n        for (var i = 0; i < results.length; i++){\n            console.log(results[i].fullName());\n        }\n    }\n});\n\nInvisible.Person.query({}, {sort: \"lastName\", limit: 10}, function(err, results){\n    if (err){\n        console.log(\"something went wrong\");\n    } else {\n        console.log(\"First 10 persons are:\");\n        for (var i = 0; i < results.length; i++){\n            console.log(results[i].fullName());\n        }\n    }\n});\n```\n\nQueries the database for existent models. The first two optional arguments correspond to the\n[Query object](http://mongodb.github.io/node-mongodb-native/markdown-docs/queries.html#query-object)\nand [Query options](http://mongodb.github.io/node-mongodb-native/markdown-docs/queries.html#query-options)\nin the MongoDB Node.JS driver. The one difference is that when using ids you can pass strings,\nthat will be converted to ObjectID when necessary.\n\n### Find by id\n```javascript\nInvisible.Person.findById(jane._id, function(err, model){\n    if (err){\n        console.log(\"something went wrong\");\n    } else {\n        console.log(\"Jane's name is \" + model.firstName);\n        console.log(\"But we knew that!\");\n    }\n})\n```\n\nLooks into the database for a model with the specified `_id` value. As in the query method, you can pass\na string id instead of an ObjectID instance.\n\n## Validations\n\nInvisible.js integrates with [revalidator](https://github.com/flatiron/revalidator) to handle model validations.\nA `validate` method is added to each model which looks for a defined validation schema, and is executed each time\na model is saved, both in the client and the server. For example:\n\n```javascript\nfunction Person(email){\n    this.email = email;\n}\n\nPerson.prototype.validations = {\n    properties: {\n        email: {\n            format: 'email',\n            required: true\n        }\n    }\n}\n\nvar john = new Person(\"john.doe@none.com\");\njohn.save(function(err, result){\n    console.log(\"All OK here.\");\n});\n\njohn.email = \"invalid\";\njohn.save(function(err, result){\n    console.log(err);\n    /* Prints: {valid: false, errors: [{attribute: 'format',\n        property: 'email', message: 'is not a valid email'}]} */\n})\n```\n\nInvisible.js also introduces \"method\" validations, which allow you to specify a method which should be called\nin the validation process. This way asynchronic validations, such as querying the database, can be performed:\n\n```javascript\nPerson.prototype.validations = {\n    methods: ['checkUnique']\n}\n\nPerson.prototype.checkUnique = function(cb) {\n    Invisible.Person.query({email: this.email}, function(err, res){\n        if (res.length > 0){\n            cb({valid: false, errors: [\"email already registered\"]});\n        } else {\n            cb({valid: true, errors: []});\n        }\n    });\n}\n```\n\nThe custom validation method takes a callback and should call it with the return format of revalidator: an object\nwith a \"valid\" boolean field and an \"errors\" list. Note that the method validations are only called if the\nproperties validations succeed, and stop the validation process upon the first failure.\n\n## Real time events\n\nInvisible.js uses [socket.io](http://socket.io/) to emmit an event whenever something changes for a model, and lets you add listener\nfunctions to react to those changes in realtime.\n\nTo add realtime features:\n```javascript\nvar server = app.listen(3000);\ninvisible.addRealtime(server);\n```\n\nAnd then in your code:\n```javascript\nInvisible.Person.on('new', function(model){\n    console.log(model.fullName() + \" has been created\");\n});\n\nInvisible.Person.on('update', function(model){\n    console.log(model.fullName() + \" has been updated\");\n});\n\nInvisible.Person.on('delete', function(model){\n    console.log(model.fullName() + \" has been deleted\");\n});\n```\n\n## Authentication\n\nInvisible.js provides a default method to authenticate the requests to the REST API, based on OAuth2's [Resource\nOwner Password flow](http://techblog.hybris.com/2012/06/11/oauth2-resource-owner-password-flow/). This means than when activating authentication, a route is exposed that exchanges user\ncredentials for a request token used to sign the rest of the API calls. Unsigned calls will get a 401 response.\n\nTo use authentication, you must first define a user model in whatever way you like; the only constraint is that\nyou must be able to identify a user with a pair of credentials such as username/password. By default the `User`\nname is assumed for the model, but this can be overriden via the `userModel` configuration.\n\n```javascript\n//models/user.js\nfunction User(email){\n    this.email = email;\n}\n\nUser.prototype.setPassword = function(rawPassword){\n    this.hashedPassword = someHashFunction(rawPassword);\n}\n\nUser.prototype.isPassword = function(rawPassword){\n    return this.hashedPassword == someHashFunction(rawPassword);\n}\n\nmodule.exports = Invisible.createModel(\"User\", User);\n```\n\nOnce the User model is defined, authentication is activated by defining an `authenticate` function in the\nconfiguration, that takes the credentials and returns the authenticated user:\n\n```javascript\n//auth.js\nmodule.exports = function authenticateUser(email, password, done){\n\n    Invisible.User.query({email: email}, function(err, users){\n        if (err) {\n            return done(err);\n        }\n        if (users.length < 1){\n            return done(null, false);\n        }\n        var user = users[0];\n        if (!user.isPassword(password)) {\n            return done(null, false);\n        }\n        return done(null, user);\n    });\n}\n\n//app.js\n//...express and invisible configurations...\nauth = require(\"./auth\");\napp.use(invisible.router({\n  rootFolder: path.join(__dirname, 'models'),\n  authenticate: auth\n}));\n```\n\nOptionally, an `authExpiration` configuration can be included to specify the amount of seconds the acess token\ncan be used before requiring a refresh. The token refresh is managed seamlessly by the client models.\n\nIn order for the client model to get an access token to sign its requests, a `login` function must be called when\nthe user enters his credentials; note that these are used for the exchange and not stored for further use:\n\n```javascript\n//...get credentials from login form...\nInvisible.login(email, password, function(err){\n   if(err){\n    console.log(\"Invalid credentials!\");\n   } else {\n    console.log(\"User logged, requests signed\");\n   }\n});\n```\n\nOnce login is successful, the calls to the REST API will be allowed to the client models. A `logout` method is also\nprovided to drop the tokens from being used in further model requests.\n\nThe only endpoint which does not require a signed request is the POST to the user model, to allow user registration.\n\n## Authorization\nOnce you can identify the user making requests, you'll usually want to establish what he can and can't do with the data.\nThe models provide hooks to authorize a user to call its methods: `allowCreate`, `allowUpdate`, `allowFind` and `allowDelete`. All of them take the user instance and should callback telling if the method is allowed to that user:\n\n```javascript\nfunction Message(from_id, to_id, text){\n    this.from_id = from_id;\n    this.to_id = to_id;\n    this.text = text;\n}\n\nMessage.prototype.allowCreate = function(user, cb) {\n    //a user can only create messages sent by him\n    return cb(null, this.from_id === user._id);\n}\n\nMessage.prototype.allowUpdate = function(user, cb) {\n    //a user can only update messages sent by him\n    return cb(null, this.from_id === user._id;\n}\n\nMessage.prototype.allowFind = function(user, cb) {\n    //a user can only get messages sent by him or to him\n    return cb(null, this.from_id === user._id || this.to_id === user._id;\n}\n\nMessage.prototype.allowDelete = function(user, cb) {\n    //a user cannot delete messages\n    return cb(null, false);\n}\n\nmodule.exports = Invisible.createModel(\"Message\", Message);\n```\nSimilarly, `allowEvents` can be used to decide if a user is authorized to receive a real time update on a model:\n```javascript\nMessage.prototype.allowEvents = function(user, cb) {\n    //only sent events when a message is sent to the user\n    return cb(null, this.to_id === user._id;\n}\n```\n\nAnother hook, `baseQuery`, is available to restrict what segment of the database the user should have access to.\nIt also takes the user, and callbacks with a criteria object like the one for the [query method](/#query). This base criteria,\nis and-ed with the criteria used in `query` to filter out unauthorized data. Following the previous example:\n\n```javascript\nMessage.baseQuery = function(user, cb){\n    //only expose message sent to or by the user\n    return cb(null, {$or: [{from: user._id}, {to: user._id}]})\n}\n```\nNow when calling `Invisible.Message.query` in the client, only messages sent by and to the logged user will be\nreceived.\n\n\n","maintainers":[{"name":"sammla","email":"martin.c.paulucci@gmail.com"},{"name":"facundoolano","email":"facundo.olano@gmail.com"}],"time":{"modified":"2022-06-19T01:55:34.787Z","created":"2013-06-23T20:59:14.537Z","0.0.0":"2013-06-23T20:59:19.235Z","0.1.0":"2013-09-05T17:39:52.770Z","0.1.1":"2013-09-05T21:41:44.790Z","0.1.2":"2013-09-05T21:52:15.778Z","0.1.3":"2013-09-05T21:54:37.556Z","0.1.4":"2013-09-10T23:46:02.758Z","0.1.5":"2013-09-24T21:14:07.168Z","0.1.6":"2013-09-25T13:34:42.704Z","0.1.7":"2013-09-30T20:19:37.317Z","0.2.0":"2013-10-15T20:30:45.234Z","0.2.1":"2013-10-17T17:50:57.699Z","0.2.2":"2013-10-17T18:03:36.755Z","0.2.3":"2013-10-30T13:36:14.047Z","0.2.4":"2013-10-30T17:43:56.498Z","0.2.6":"2013-11-25T18:50:04.517Z","0.2.7":"2013-11-25T18:54:29.669Z","0.3.0":"2014-10-13T10:03:26.962Z","0.4.0":"2015-04-30T02:54:45.940Z","0.4.1":"2015-05-01T16:54:32.067Z"},"author":{"name":"Facundo Olano and Martin Paulucci"},"repository":{"type":"git","url":"git://github.com/invisiblejs/invisible.git"},"homepage":"https://github.com/invisiblejs/invisible","bugs":{"url":"https://github.com/invisiblejs/invisible/issues"},"license":"BSD","readmeFilename":"README.md"}