New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

zotero

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

zotero - npm Package Compare versions

Comparing version 0.0.6 to 0.1.0

lib/stream.js

98

lib/client.js

@@ -0,1 +1,3 @@

'use strict';
// --- Dependencies ---

@@ -27,3 +29,3 @@

* @constructor
* @extends events.EventEmitter
* @extends EventEmitter
*

@@ -35,5 +37,7 @@ * @param {Object} options - override the default configuration.

this.options = extend({}, Client.defaults, options);
var defaults = this.constructor.defaults;
this.options = extend({}, defaults, options);
this.options.headers =
extend({}, Client.defaults.headers, options && options.headers);
extend({}, defaults.headers, options && options.headers);

@@ -55,3 +59,3 @@ this.state = new ClientState(this);

host: 'api.zotero.org',
port: 443,
protocol: 'https',

@@ -127,2 +131,3 @@ headers: {

* Alternatively, the message object to send.
* @param {Object|String} [body] Message body.
* @param {Function} callback

@@ -132,3 +137,3 @@ *

*/
Client.prototype.request = function (options, callback) {
Client.prototype.request = function (options, body, callback) {
debug('#request %j', options);

@@ -143,3 +148,3 @@

var self = this;
var message = new Message(options);
var message = new Message(options, body);

@@ -221,3 +226,3 @@ message.once('received', function () {

Client.prototype.get = function (path, options, headers, callback) {
return this.http('GET', path, options, headers, callback);
return this.http('GET', path, options, null, headers, callback);
};

@@ -237,2 +242,3 @@

* @param {Object} [options] Request parameters.
* @param {Object|String} [body] Request body.
* @param {Object} [headers] Request headers.

@@ -243,7 +249,73 @@ * @param {Function} [callback]

*/
Client.prototype.delete = function (path, options, headers, callback) {
return this.http('DELETE', path, options, headers, callback);
Client.prototype.delete = function (path, options, body, headers, callback) {
return this.http('DELETE', path, options, body, headers, callback);
};
/**
* Issues a POST request to the Zotero API. See the `#request`
* method for further details.
*
* @method post
*
* @example
* client.post('/users/42/items', { key: 'abc123' }, { title: ... });
* //-> posts item to /users/42/items?key=abc123
*
* @param {String} path The API destination path.
* @param {Object} [options] Request parameters.
* @param {Object|String} [body] Request body.
* @param {Object} [headers] Request headers.
* @param {Function} [callback]
*
* @return {Message} The Zotero API message object.
*/
Client.prototype.post = function (path, options, body, headers, callback) {
return this.http('POST', path, options, body, headers, callback);
};
/**
* Issues a PUT request to the Zotero API. See the `#request`
* method for further details.
*
* @method put
*
* @example
* client.put('/users/42/items', { key: 'abc123' }, { title: ... });
* //-> posts item to /users/42/items?key=abc123
*
* @param {String} path The API destination path.
* @param {Object} [options] Request parameters.
* @param {Object|String} [body] Request body.
* @param {Object} [headers] Request headers.
* @param {Function} [callback]
*
* @return {Message} The Zotero API message object.
*/
Client.prototype.put = function (path, options, body, headers, callback) {
return this.http('PUT', path, options, body, headers, callback);
};
/**
* Issues a PATCH request to the Zotero API. See the `#request`
* method for further details.
*
* @method patch
*
* @example
* client.put('/users/42/items', { key: 'abc123' }, { title: ... });
* //-> posts item to /users/42/items?key=abc123
*
* @param {String} path The API destination path.
* @param {Object} [options] Request parameters.
* @param {Object|String} [body] Request body.
* @param {Object} [headers] Request headers.
* @param {Function} [callback]
*
* @return {Message} The Zotero API message object.
*/
Client.prototype.patch = function (path, options, body, headers, callback) {
return this.http('PATCH', path, options, body, headers, callback);
};
/**
* Issues a HTTP request to the Zotero API. See the `#request`

@@ -258,2 +330,3 @@ * method for further details; also see `#get`, `#delete` and

* @param {Object} [options] Request parameters.
* @param {Object|String} [body] Request body.
* @param {Object} [headers] Request headers.

@@ -264,3 +337,3 @@ * @param {Function} [callback]

*/
Client.prototype.http = function (method, path, options, headers, callback) {
Client.prototype.http = function (method, path, options, body, headers, callback) {

@@ -273,2 +346,5 @@ // Handle cases where not all arguments are specified. This is not

} else if (typeof body === 'function') {
callback = body; body = null;
} else if (typeof options === 'function') {

@@ -286,3 +362,3 @@ callback = options; options = null;

}, callback);
}, body, callback);
};

@@ -289,0 +365,0 @@

@@ -0,1 +1,3 @@

'use strict';
var proxy = require('./proxy');

@@ -2,0 +4,0 @@

@@ -0,1 +1,3 @@

'use strict';
var proxy = require('./proxy');

@@ -2,0 +4,0 @@

@@ -0,3 +1,6 @@

'use strict';
// --- Dependencies ---
var assert = require('assert');
var join = require('path').join;

@@ -8,2 +11,4 @@

var Client = require('./client');
var Stream = require('./stream');
var proxy = require('./proxy');

@@ -13,5 +18,7 @@ var items = require('./items');

var utils = require('./utils');
var utils = require('./utils');
var extend = utils.extend;
var omit = utils.omit;
var omit = utils.omit;
var once = utils.once;
var noop = utils.noop;

@@ -233,3 +240,61 @@ /** @module zotero */

/**
* Connects to the Zotero Stream API and listens for
* Events for this library.
*
* @method stream
*
* @param {Function} [callback] Called with the Stream
* instance once the stream has been established.
*
* @return {Stream} A Stream instance for this library.
*/
Library.prototype.stream = function (callback) {
assert(this.id);
callback = once(callback || noop);
var stream = new Stream();
debug('connection to library stream %s...', this.prefix);
function failed(reason) {
debug('failed to connect to library stream: %j', reason);
callback(new Error('failed to connect to library stream'), stream);
}
return stream
.once('connected', function () {
try {
stream.removeListener('error', failed);
var subscription = {
topics: ['/' + this.prefix]
};
if (this.key)
subscription.apiKey = this.key;
stream.subscribe(subscription, function (error, message) {
if (error) return failed(error);
if (message.code !== 201) {
debug('status code 201 expected but was %s', message.code);
return failed('failed to subscribe to library');
}
debug('successfully connected to library stream');
callback(null, stream);
});
} catch (reason) {
failed(reason);
}
}.bind(this))
.on('error', failed);
};
// --- Exports ---
exports = module.exports = Library;

@@ -0,1 +1,3 @@

'use strict';
// --- Dependencies ---

@@ -28,6 +30,12 @@

* @extends Stream
*
* @params {Object} [options] For `https.request`.
* @params {Object} [body] Optional request body.
*/
function Message(options) {
function Message(options, body) {
Stream.call(this);
if (options) this.bind(options);
if (options || body)
this.bind(options, body);
}

@@ -247,2 +255,5 @@

*
* If given, the body will be included
* as a JSON string.
*
* @method bind

@@ -252,4 +263,5 @@ * @chainable

* @params {Object} options For `https.request`.
* @params {Object|String} [body] Optional request body.
*/
Message.prototype.bind = function (options) {
Message.prototype.bind = function (options, body) {
debug('binding new http request...');

@@ -279,2 +291,12 @@

if (body) {
if (typeof body === 'string') {
req.write(body);
} else {
req.write(JSON.stringify(body));
req.setHeader('Content-Type', 'application/json');
}
}
this.emit('request', req);

@@ -281,0 +303,0 @@

@@ -0,1 +1,3 @@

'use strict';
var debug = require('debug')('zotero:proxy'),

@@ -2,0 +4,0 @@ escape = require('querystring').escape,

11

lib/utils.js

@@ -0,1 +1,3 @@

'use strict';
var slice = Array.prototype.slice,

@@ -100,3 +102,3 @@ concat = Array.prototype.concat;

return exports.pick(obj, Object.keys(obj).filter(function (key) {
return exclude.indexOf(key) < 0
return exclude.indexOf(key) < 0;
}));

@@ -126,7 +128,8 @@ };

f.called = true;
return (f.value = fn.apply(this, arguments));
}
f.value = fn.apply(this, arguments);
return f.value;
};
};
exports.noop = function noop() {};

@@ -0,7 +1,8 @@

'use strict';
// --- Dependencies ---
var debug = require('debug');
debug.enable('zotero:node');
var print = debug('zotero:node');
var prints = debug('zotero:node');

@@ -11,2 +12,3 @@ var Client = require('./client');

var Message = require('./message');
var Stream = require('./stream');

@@ -64,11 +66,11 @@

if (error) {
print('API call failed: (%s) %s', error.code || 'no code', error.message);
prints('API call failed: (%s) %s', error.code || 'no code', error.message);
}
if (message) {
print('Path:\t%s', message.path);
print('Status:\t%d', message.code);
print('Type:\t%s', message.type);
print('Headers:\t%j', message.headers);
print('Content:\t\%j', message.data);
prints('Path:\t%s', message.path);
prints('Status:\t%d', message.code);
prints('Type:\t%s', message.type);
prints('Headers:\t%j', message.headers);
prints('Content:\t\%j', message.data);
}

@@ -118,6 +120,7 @@ };

zotero.Client = Client;
zotero.Client = Client;
zotero.Library = Library;
zotero.Message = Message;
zotero.Stream = Stream;
exports = module.exports = zotero;
{
"name": "zotero",
"version": "0.0.6",
"version": "0.1.0",
"description": "Zotero API client",

@@ -30,3 +30,3 @@ "main": "lib/zotero.js",

"mocha": "1.20.x",
"nock": "~0.34.1",
"nock": "~0.37",
"should": "4.0.x",

@@ -39,4 +39,5 @@ "sinon": "1.10.x",

"debug": "*",
"eventsource": "^0.1.4",
"mime-types": "~1.0.0"
}
}

@@ -41,8 +41,5 @@ Zotero-Node

> // Make the client use version 2 of the Zotero API
> lib.client.version = 2;
> // The default HTTP headers used by the client
> lib.client.options.headers;
{ 'Zotero-API-Version': '2', 'User-Agent': 'zotero-node/0.0.1' }
{ 'Zotero-API-Version': '3', 'User-Agent': 'zotero-node/0.0.1' }

@@ -109,2 +106,43 @@ > // Let's make the client re-use the TCP connection to the server

Stream API
----------
Zotero-Node supports the Zotero Stream API through zotero.Stream. To create
a single key stream, simply pass your Zotero API key to the constructor:
var stream = new zotero.Stream({ key: 'your-zotero-api-key' });
You can then register handlers for all events:
stream.on('topicUpdated', function (evt) {
console.log(evt.data.topic);
console.log(evt.data.version);
});
If you create a stream without a key, it will default to a multi key
stream. Once the stream has been established, you can manage your
subscriptions using the `.subscribe` and `.unsubscribe` methods.
(new zotero.Stream())
.on('connected', function () {
this.subscribe([
{ apiKey: 'abc123' },
{ apiKey: 'efd456', topics: [ '/users/12345' ] }
]);
});
You can also create a multi-key stream for a given Zotero user or group
library, by using the `.stream` method on the library instance. This will
automatically create the stream and subscribe to the current library,
using the library's API key (if present):
zotero({ user: '475425' })
.stream(function (error, stream) {
// This will set up a stream and subscribe to
// the topic '/users/475425'. The callback will
// be called once the subscription has been
// accepted (or if there was an error).
});
Rate-Limiting

@@ -150,3 +188,3 @@ -------------

lib.client.messages[0].req.getHeader('Zotero-API-Version');
// Handle the API response or errors when the promise is

@@ -162,2 +200,10 @@ // resolved or rejected:

Note that the Stream API also uses promieses now:
lib
.stream()
.then(function (stream) {
// ...
});
You can undo the promisification at any time by calling:

@@ -164,0 +210,0 @@

@@ -0,1 +1,3 @@

'use strict';
var Client = require('../lib/client'),

@@ -48,2 +50,3 @@ Message = require('../lib/message'),

});
describe('#get', function () {

@@ -232,2 +235,28 @@

describe('#post', function () {
describe('given a body object', function () {
var path = '/users/475425/items';
beforeEach(function() {
nock('https://api.zotero.org')
.post(path, '{"title":"foo"}')
.reply(200, { success: { 0: 'abc123' }});
});
it('sends a JSON body', function (done) {
client.post(path, null, { title: 'foo' }, function (error, message) {
(!error).should.be.true;
message.code.should.eql(200);
message.data.should.have.property('success');
message.data.success.should.have.property('0', 'abc123');
message.req.getHeader('content-type').should.eql('application/json');
done();
});
});
});
});
describe('#state', function () {

@@ -234,0 +263,0 @@ it('is not limited by default', function () {

@@ -1,5 +0,10 @@

var Library = require('../lib/library'),
Client = require('../lib/client'),
sinon = require('sinon');
'use strict';
var sinon = require('sinon');
var nock = require('nock');
var Library = require('../lib/library');
var Client = require('../lib/client');
var Stream = require('../lib/stream');
describe('Zotero.Library', function () {

@@ -115,7 +120,2 @@ var library;

it('cannot be removed', function () {
library.items = null;
library.items.should.be.a.Function;
});
it('calls #get with items/:id', function () {

@@ -195,7 +195,2 @@ library.items('foo');

it('cannot be re-assigned', function () {
library.collections = null;
library.collections.should.be.a.Function;
});
it('calls #get with collections/:id', function () {

@@ -323,3 +318,103 @@ library.collections();

});
describe('#stream', function () {
describe('when the event stream works', function () {
beforeEach(function () {
library.user = 12345;
nock('https://stream.zotero.org')
.get('/')
.reply(
200,
'event: connected\n' +
'data: {"connectionId":"foobar"}\n\n' +
'event: topicUpdated\n' +
'data: {"topic":"foo","version":23}\n\n',
{
'Content-Type': 'text/event-stream'
}
);
});
it('creates a library stream', function (done) {
nock('https://stream.zotero.org')
.post('/connections/foobar', {
subscriptions: [{
topics: [ '/users/12345' ]
}]
})
.reply(201);
var s = library.stream(function (error, stream) {
(!error).should.be.true;
s.should.be.equal(stream);
done();
});
s.should.be.instanceof(Stream);
});
it('uses the library API key if present', function (done) {
nock('https://stream.zotero.org')
.post('/connections/foobar', {
subscriptions: [{
apiKey: 'qwerty',
topics: [ '/users/12345' ]
}]
})
.reply(201);
library.key = 'qwerty';
library.stream(function (error) {
(!error).should.be.true;
done();
});
});
it('fails if the subscription request fails', function (done) {
nock('https://stream.zotero.org')
.post('/connections/foobar')
.reply(413);
library.stream(function (error) {
(!error).should.be.false;
done();
});
});
});
describe('when the event stream does not work', function () {
beforeEach(function () {
library.user = 12345;
nock('https://stream.zotero.org')
.get('/')
.reply(
200,
'event: connected\n' +
'data: {}\n\n' +
'event: topicUpdated\n' +
'data: {"topic":"foo","version":23}\n\n',
{
'Content-Type': 'text/event-stream'
}
);
});
it('calls back with an error', function (done) {
library.stream(function (error) {
(!error).should.be.false;
done();
});
});
});
});
});

@@ -0,1 +1,3 @@

'use strict';
var sinon = require('sinon');

@@ -16,3 +18,3 @@ var nock = require('nock');

it('is false if there is a next link', function () {
var m = new Message();
m = new Message();

@@ -19,0 +21,0 @@ m.links = {};

@@ -0,8 +1,10 @@

'use strict';
var zotero = require('..'),
nock = require('nock'),
Promise = require('bluebird');
B = require('bluebird');
describe('When using Promises', function () {
before(function () {
zotero.promisify(Promise.promisify.bind(Promise));
zotero.promisify(B.promisify.bind(B));
});

@@ -37,3 +39,3 @@

it('returns the a promise object', function () {
client.get(path).should.be.instanceof(Promise);
client.get(path).should.be.instanceof(B);
});

@@ -69,2 +71,1 @@

});

@@ -0,1 +1,3 @@

'use strict';
var proxy = require('../lib/proxy'),

@@ -73,2 +75,1 @@ sinon = require('sinon');

});

@@ -0,1 +1,3 @@

'use strict';
var utils = require('../lib/utils');

@@ -2,0 +4,0 @@

@@ -0,1 +1,3 @@

'use strict';
var zotero = require('..');

@@ -2,0 +4,0 @@ //var sinon = require('sinon');

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc