Comparing version 1.3.0 to 1.3.1
22
error.js
@@ -0,1 +1,2 @@ | ||
var EventEmitter = require('events').EventEmitter; | ||
var STATUS_CODES = { '100': 'Continue' | ||
@@ -100,4 +101,23 @@ , '101': 'Switching Protocols' | ||
} | ||
function request_err(error, code, request, callback) { | ||
if(typeof request === 'function') { | ||
callback = request; | ||
request = {}; | ||
} | ||
error = gen_err('request', error, code, request); | ||
if(callback) { | ||
callback(error); | ||
return request; | ||
} else { | ||
var em = new EventEmitter(); | ||
process.nextTick(function() { em.emit('error', error); }); | ||
return em; | ||
} | ||
} | ||
exports.uncaught = function (e,c,r,s) { return gen_err('uncaught',e,c,r,s); }; | ||
exports.request = function (e,c,r,s) { return gen_err('request',e,c,r,s); }; | ||
exports.couch = function (e,c,r,s) { return gen_err('couch',e,c,r,s); }; | ||
exports.couch = function (e,c,r,s) { return gen_err('couch',e,c,r,s); }; | ||
exports.init = function (e,c,r,s) { return gen_err('init',e,c,r,s); }; | ||
exports.request_err = request_err; |
// Simple event+strategy-based logging for NanoCouch | ||
// written by: Derek Perez | ||
var verbose = (process.env.NANO_ENV==='testing'); | ||
var _ = require('underscore'); | ||
// snippet by Marak Squires. | ||
// Generates a pesuedo-random identifier for a log event. | ||
function randomString(len, charSet) { | ||
charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | ||
var randomString = ''; | ||
var str = ''; | ||
for (var i = 0; i < len; i++) { | ||
var randomPoz = Math.floor(Math.random() * charSet.length); | ||
randomString += charSet.substring(randomPoz,randomPoz+1); | ||
str += charSet.substring(randomPoz,randomPoz+1); | ||
} | ||
return randomString; | ||
return str; | ||
} | ||
// logging generator, expects a strategy function | ||
// to be provided on require of the module. | ||
// a logging strategy should support two arguments, | ||
// the first an `eventId` used to identify a group of | ||
// log events that would be considered related. the second | ||
// is an array of values that nano may pass to the logStrategy. | ||
module.exports = function(logStrategy) { | ||
module.exports = function logging(cfg) { | ||
var logStrategy = cfg ? cfg.log : undefined; | ||
this.cfg = cfg; | ||
if (typeof logStrategy !== 'function') { | ||
if(verbose) { | ||
logStrategy = function consoleLog(eventId, args) { | ||
console.log(eventId, args); | ||
}; | ||
} | ||
else logStrategy = function noop(){}; | ||
} | ||
// if we've been provided no strategy | ||
// for our logs, and verbose mode is active, | ||
// simply pipe to console.log. | ||
if (!logStrategy && verbose) | ||
logStrategy = function(eventId, args) { console.log(eventId, args) }; | ||
// by default, if we have no logging | ||
// strategy provided, we'll simply return | ||
// an empty function, no output. | ||
else if (!logStrategy) | ||
logStrategy = function(){}; | ||
// the export returns the `logEvent` root function. | ||
// calling this function returns a curried `log` function | ||
// which will allow the user to associate all log hits with | ||
// a unique log eventId. Providing a prefix is optional, simply | ||
// prepends a string to the random string generator, for extra | ||
// debugging goodness. | ||
return function logEvent(prefix) { | ||
var eventId = (prefix ? prefix+'-' : '') + randomString(10); | ||
var eventId = (prefix ? prefix + '-' : '') + randomString(10); | ||
return function log() { | ||
logStrategy.call(this, eventId, _.toArray(arguments)); | ||
} | ||
} | ||
} | ||
logStrategy.call(this, eventId, | ||
[].slice.call(arguments,0)); // convert arguments into array | ||
}; | ||
}; | ||
}; |
315
nano.js
@@ -20,12 +20,16 @@ /* minimal couch in node | ||
, qs = require('querystring') | ||
, _ = require('underscore') | ||
, u = require('url') | ||
, error = require('./error') | ||
, default_url = "http://localhost:5984" | ||
, nano | ||
; | ||
function isEmpty(object) { | ||
for(var property in object) { | ||
if(object.hasOwnProperty(property)) return false; } | ||
return true; | ||
} | ||
/* | ||
* nano is a library that helps you building requests to couchdb | ||
* that is built on top of mikeals/request | ||
* that is built on top of mikeal/request | ||
* | ||
@@ -38,32 +42,11 @@ * no more, no less | ||
module.exports = exports = nano = function database_module(cfg) { | ||
var public_functions = {}, path, db; | ||
if(typeof cfg === "string") { | ||
if(/^https?:/.test(cfg)) { cfg = {url: cfg}; } // url | ||
else { | ||
try { cfg = require(cfg); } // file path | ||
catch(e) { console.error("bad cfg: couldn't load file"); } | ||
} | ||
} | ||
if(!cfg) { | ||
console.error("bad cfg: you passed undefined"); | ||
cfg = {}; | ||
} | ||
if(cfg.proxy || !cfg.jar) { | ||
var opts = {}; | ||
if(cfg.proxy) opts.proxy = cfg.proxy; | ||
if(!cfg.jar) opts.jar = false; | ||
request = require('request').defaults(opts); | ||
} | ||
if(!cfg.url) { | ||
console.error("bad cfg: using default=" + default_url); | ||
cfg = {url: default_url}; // if everything else fails, use default | ||
} | ||
var public_functions = {} | ||
, request_opts = {} | ||
, logging | ||
, path | ||
, path_array | ||
, db | ||
, auth | ||
; | ||
// configure logging strategy for this | ||
// instance of nano | ||
var logging = require('./logging')(cfg.log); | ||
logging("cfg")(cfg); | ||
path = u.parse(cfg.url); | ||
/**************************************************************************** | ||
@@ -102,58 +85,78 @@ * relax * | ||
var log = logging(); | ||
try { | ||
var headers = { "content-type": "application/json" | ||
, "accept": "application/json" | ||
} | ||
, req = { method: (opts.method || "GET"), headers: headers | ||
, uri: cfg.url + "/" + opts.db } | ||
, params = opts.params | ||
, status_code | ||
, parsed | ||
, rh; | ||
var headers = { "content-type": "application/json" | ||
, "accept" : "application/json" | ||
} | ||
, req = { method : (opts.method || "GET") | ||
, headers: headers | ||
, uri : cfg.url + "/" + opts.db } | ||
, params = opts.params | ||
, status_code | ||
, parsed | ||
, rh | ||
; | ||
if (opts.jar) { | ||
req.jar = opts.jar; | ||
} | ||
if (opts.jar) { req.jar = opts.jar; } | ||
if(opts.path) { | ||
req.uri += "/" + opts.path; | ||
if(opts.path) { req.uri += "/" + opts.path; } | ||
else if(opts.doc) { | ||
if(!/^_design/.test(opts.doc)) { | ||
try { req.uri += "/" + encodeURIComponent(opts.doc); } | ||
catch (ex1) { | ||
ex1.message = 'couldnt encode: ' + opts.doc + ' as an uri'; | ||
return error.request_err(ex, 'encodeuri', {}); | ||
} | ||
} | ||
else if(opts.doc) { | ||
if(!/^_design/.test(opts.doc)) { | ||
// add the document to the url | ||
req.uri += "/" + encodeURIComponent(opts.doc); | ||
else { | ||
req.uri += "/" + opts.doc; | ||
} | ||
if(opts.att) { req.uri += "/" + opts.att; } | ||
} | ||
if(opts.encoding && callback) { | ||
req.encoding = opts.encoding; | ||
delete req.headers["content-type"]; | ||
delete req.headers.accept; | ||
} | ||
if(opts.content_type) { | ||
req.headers["content-type"] = opts.content_type; | ||
delete req.headers.accept; // undo headers set | ||
} | ||
if(!isEmpty(params)) { | ||
['startkey', 'endkey', 'key', 'keys'].forEach(function (key) { | ||
if (key in params) { | ||
try { params[key] = JSON.stringify(params[key]); } | ||
catch (ex2) { | ||
ex2.message = 'bad params: ' + key + ' = ' + params[key]; | ||
return error.request_err(ex, 'jsonstringify', {}); | ||
} | ||
} | ||
else { | ||
req.uri += "/" + opts.doc; | ||
} | ||
// add the attachment to the url | ||
if(opts.att) { req.uri += "/" + opts.att; } | ||
}); | ||
try { req.uri += "?" + qs.stringify(params); } | ||
catch (ex3) { | ||
ex3.message = 'invalid params: ' + params.toString(); | ||
return error.request_err(ex3, 'qsstringify', {}); | ||
} | ||
if(opts.encoding && callback) { | ||
req.encoding = opts.encoding; | ||
delete req.headers["content-type"]; | ||
delete req.headers.accept; | ||
} | ||
if(!callback) { // void callback, stream | ||
try { | ||
return request(req); | ||
} catch (ex4) { | ||
return error.request_err(ex4, 'streamthrow', {}); | ||
} | ||
if(opts.content_type) { | ||
req.headers["content-type"] = opts.content_type; | ||
delete req.headers.accept; // undo headers set | ||
} | ||
if(opts.body) { | ||
if (Buffer.isBuffer(opts.body)) { | ||
req.body = opts.body; // raw data | ||
} | ||
//if(cfg.cookie){ | ||
// req.headers.cookie = cfg.cookie; | ||
//} | ||
if(!_.isEmpty(params)) { | ||
['startkey', 'endkey', 'key', 'keys'].forEach(function (key) { | ||
if (key in params) { params[key] = JSON.stringify(params[key]); } | ||
}); | ||
req.uri += "?" + qs.stringify(params); | ||
} | ||
if(!callback) { return request(req); } // void callback, pipe | ||
if(opts.body) { | ||
if (Buffer.isBuffer(opts.body)) { | ||
req.body = opts.body; // raw data | ||
else { | ||
try { | ||
req.body = JSON.stringify(opts.body); | ||
} catch (ex5) { | ||
ex5.message = "couldn't json.stringify the body you provided"; | ||
return error.request_err(ex5, 'jsonstringify', {}, callback); | ||
} | ||
else { req.body = JSON.stringify(opts.body); } // json data | ||
} | ||
log(req); | ||
request(req, function(e,h,b){ | ||
} // json data | ||
} | ||
log(req); | ||
try { | ||
var stream = request(req, function(e,h,b){ | ||
rh = (h && h.headers || {}); | ||
@@ -164,30 +167,24 @@ rh['status-code'] = status_code = (h && h.statusCode || 500); | ||
log({err: 'socket', body: b, headers: rh }); | ||
return callback(error.request(e,"socket",req,status_code),b,rh); | ||
callback(error.request(e,"socket",req,status_code),b,rh); | ||
return stream; | ||
} | ||
// prevent security vunerabilities related to couchdb | ||
delete rh.server; | ||
// prevent problems with trims and stalled responses | ||
delete rh['content-length']; | ||
// did we get json or binary? | ||
try { parsed = JSON.parse(b); } catch (err) { parsed = b; } | ||
if (status_code >= 200 && status_code < 300) { | ||
//if (rh['set-cookie']){ | ||
// cfg.cookie = rh['set-cookie']; //get auth cookie | ||
//} | ||
log({err: null, body: parsed, headers: rh}); | ||
callback(null,parsed,rh); | ||
return stream; | ||
} | ||
else { // proxy the error directly from couchdb | ||
log({err: 'couch', body: parsed, headers: rh}); | ||
if (!parsed) { parsed = {}; } // if HEAD request, body will be undefined | ||
if (!parsed) { parsed = {}; } | ||
callback(error.couch(parsed.reason,parsed.error,req,status_code), | ||
parsed, rh); | ||
return stream; | ||
} | ||
}); | ||
} catch(exc) { | ||
if (callback) { | ||
log({err: 'uncaught', body: exc}); | ||
callback(error.uncaught(exc)); | ||
} | ||
else { console.error({err: 'uncaught', body: exc}); } | ||
return stream; | ||
} catch(ex6) { | ||
return error.request_err(ex6, 'callbackthrow', {}); | ||
} | ||
@@ -327,32 +324,2 @@ } | ||
/**************************************************************************** | ||
* session * | ||
***************************************************************************/ | ||
/* | ||
* creates session | ||
* | ||
* e.g. nano.session.create(user, password) | ||
* | ||
* @param {user:string} user name | ||
* @param {pass:string} password | ||
* | ||
* @see relax | ||
*/ | ||
//function create_session(user, password, callback) { | ||
// var body = new Buffer("name=" + user + "&" + "password=" + password); | ||
// return relax({db: "_session", body:body, method: "POST", content_type: "application/x-www-form-urlencodeddata"}, callback); | ||
//} | ||
/* | ||
* destroy session | ||
* | ||
* e.g. nano.session.destroy() | ||
* | ||
* @see relax | ||
*/ | ||
//function destroy_session(callback) { | ||
// cfg.cookie = null; //make sure cookie gets destroyed also if error | ||
// return relax({db: "_session", method: "DELETE"}, callback); | ||
//} | ||
/**************************************************************************** | ||
* doc * | ||
@@ -437,2 +404,21 @@ ***************************************************************************/ | ||
/* | ||
* bulk fetch functionality | ||
* [1]: http://wiki.apache.org/couchdb/HTTP_Bulk_Document_API | ||
* | ||
* @param {doc_names:object} document keys as per the couchdb api[1] | ||
* @param {params:object} additions to the querystring, note that include_docs is always set to true | ||
* | ||
* @see get_doc | ||
* @see relax | ||
*/ | ||
function fetch_docs(doc_names,params,callback) { | ||
if(typeof params === "function") { | ||
callback = params; | ||
params = {}; | ||
} | ||
params.include_docs = true; | ||
return relax({db: db_name, path: "_all_docs", method: "POST", params: params, body: doc_names},callback); | ||
} | ||
/* | ||
* calls a view | ||
@@ -473,13 +459,17 @@ * | ||
*/ | ||
function update_with_handler_doc(design_name, update_name, doc_name, params, callback) { | ||
function update_with_handler_doc(design_name, update_name, | ||
doc_name, params, callback) { | ||
if(typeof params === "function") { | ||
callback = params; | ||
params = {}; | ||
params = {}; | ||
} | ||
var update_path = '_design/' + design_name + '/_update/' + update_name + '/' + doc_name; | ||
return relax({db: db_name, path: update_path, method: "PUT", params: params}, callback); | ||
var update_path = '_design/' + design_name + '/_update/' + | ||
update_name + '/' + doc_name; | ||
return relax( | ||
{ db: db_name, path: update_path, method: "PUT" | ||
, params: params }, callback); | ||
} | ||
/* | ||
* bulk fetch/update/delete/insert functionality | ||
* bulk update/delete/insert functionality | ||
* [1]: http://wiki.apache.org/couchdb/HTTP_Bulk_Document_API | ||
@@ -498,3 +488,5 @@ * | ||
} | ||
return relax({db: db_name, path: "_bulk_docs", body: docs, method: "POST", params: params}, callback); | ||
return relax( | ||
{ db: db_name, path: "_bulk_docs", body: docs | ||
, method: "POST", params: params}, callback); | ||
} | ||
@@ -532,4 +524,6 @@ | ||
} | ||
return relax({ db: db_name, att: att_name, method: "PUT", content_type: content_type | ||
, doc: doc_name, params: params, body: att},callback); | ||
return relax( | ||
{ db: db_name, att: att_name, method: "PUT" | ||
, content_type: content_type, doc: doc_name, params: params | ||
, body: att}, callback); | ||
} | ||
@@ -577,3 +571,5 @@ | ||
} | ||
, compact: function(cb) { return compact_db(db_name,cb); } | ||
, compact: function(cb) { | ||
return compact_db(db_name,cb); | ||
} | ||
, changes: function(params,cb) { | ||
@@ -587,2 +583,3 @@ return changes_db(db_name,params,cb); | ||
, list: list_docs | ||
, fetch: fetch_docs | ||
, config: {url: cfg.url, db: db_name} | ||
@@ -597,3 +594,3 @@ , attachment: { insert: insert_att | ||
public_functions.view.compact = function(design_name,cb) { | ||
return compact_db(db_name,design_name,cb); | ||
return compact_db(db_name,design_name,cb); | ||
}; | ||
@@ -613,9 +610,5 @@ return public_functions; | ||
} | ||
//, session: { create: create_session | ||
// , destroy: destroy_session | ||
// } | ||
, use: document_module | ||
, scope: document_module // alias | ||
, request: relax | ||
, config: cfg | ||
, relax: relax // alias | ||
@@ -625,6 +618,43 @@ , dinosaur: relax // alias | ||
// does the user want a database, or nano? | ||
if(path.pathname && !_.isEmpty(path.pathname.split('/')[1])) { | ||
var auth = path.auth ? path.auth + '@' : ''; | ||
db = path.pathname.split('/')[1]; | ||
if(typeof cfg === "string") { | ||
if(/^https?:/.test(cfg)) { cfg = {url: cfg}; } // url | ||
else { | ||
try { cfg = require(cfg); } // file path | ||
catch(e) { | ||
e.message = "couldn't read config file " + | ||
(cfg ? cfg.toString() : ''); | ||
throw error.init(e, "badfile"); | ||
} | ||
} | ||
} | ||
if(!(cfg && cfg.url)) | ||
throw error.init("no configuration with a valid url was given", "badurl"); | ||
public_functions.config = cfg; | ||
if(cfg.proxy || cfg.jar) { | ||
if(cfg.proxy) | ||
request_opts.proxy = cfg.proxy; | ||
request_opts.jar = !!cfg.jar; | ||
request = require('request').defaults(request_opts); | ||
} | ||
// assuming a cfg.log inside cfg | ||
logging = require('./logging')(cfg); | ||
try { | ||
path = u.parse(cfg.url); | ||
path_array = path.pathname.split('/').filter(function(e) { return e; }); | ||
} | ||
catch (e2) { | ||
e2.message = "your url is invalid: " + cfg.url; | ||
throw error.init(e2, "invalidurl"); | ||
} | ||
// nano('http://couch.nodejitsu.com/db1') should return a database | ||
// nano('http://couch.nodejitsu.com') should return a nano object | ||
if(path.pathname && path_array.length > 0) { | ||
auth = path.auth ? path.auth + '@' : ''; | ||
db = path_array[0]; | ||
cfg.url = path.protocol + '//' + auth + path.hostname; // reset url | ||
@@ -634,2 +664,3 @@ return document_module(db); | ||
else { return public_functions; } | ||
}; | ||
@@ -636,0 +667,0 @@ |
@@ -5,3 +5,3 @@ { "name" : "nano" | ||
, "repository" : "git://github.com/dscape/nano" | ||
, "version" : "1.3.0" | ||
, "version" : "1.3.1" | ||
, "author" : "Nuno Job <nunojobpinto@gmail.com> (http://nunojob.com)" | ||
@@ -16,2 +16,3 @@ , "contributors" : | ||
, "Dale Harvey <dale@arandomurl.com> (http://arandomurl.com)" | ||
, "Jan Lehnardt <jan@apache.org> (http://jan.prima.de/plok/)" | ||
, "InTheFiveByFive" | ||
@@ -21,3 +22,3 @@ ] | ||
["couchdb", "data", "request", "json", "nosql", "micro", "nano", "database"] | ||
, "dependencies" : {"request": "2.9.3", "underscore": "1.2.3"} | ||
, "dependencies" : {"request": "2.9.x"} | ||
, "devDependencies" : | ||
@@ -27,2 +28,3 @@ { "async": "0.1.15", "ensure": "0.4.6", "nock": "0.5.5" | ||
, "inherits": "1.0.0", "yamlish": "0.0.2", "slide": "1.1.3" | ||
, "underscore": "1.3.1" | ||
} | ||
@@ -29,0 +31,0 @@ , "scripts" : { "test": "./node_modules/ensure/bin/tap.js tests/*/*.js" } |
@@ -47,2 +47,3 @@ var ensure = require('ensure') | ||
tests.att_des = function (callback) { | ||
console.log(require('../../nano')) | ||
nano.db.create(db_name("a"), function () { | ||
@@ -49,0 +50,0 @@ db("a").attachment.insert("new", "att", "Hello World!", "text/plain", |
@@ -72,14 +72,5 @@ var ensure = require('ensure') | ||
tests.bad_file = function (callback) { callback(null,nano('notafile')); }; | ||
tests.bad_file_ok = function (_,e) { this.t.equal(e.config.url,"http://localhost:5984"); }; | ||
tests.obj_cfg = function (callback) { callback(null,nano(cfg)); }; | ||
tests.obj_cfg_ok = function (_,n) { this.t.equal(n.config.url, cfg.url); }; | ||
tests.not_string_or_object = function (callback) { callback(null,nano(false)); }; | ||
tests.not_string_or_object_ok = function (_,e) { this.t.equal(e.config.url,"http://localhost:5984"); }; | ||
tests.nano_undefined = function (callback) { callback(null,nano()); }; | ||
tests.nano_undefined_ok = function (_,e) { this.t.equal(e.config.url,"http://localhost:5984"); }; | ||
ensure(__filename,tests,module,process.argv[2]); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
1
2681
4
118795
10
44
+ Addedrequest@2.9.203(transitive)
- Removedunderscore@1.2.3
- Removedrequest@2.9.3(transitive)
- Removedunderscore@1.2.3(transitive)
Updatedrequest@2.9.x