Comparing version 3.0.1 to 4.0.0
116
lib/apns.js
const _ = require('lodash') | ||
const apnsErrors = require('./errors') | ||
const EventEmitter = require('events').EventEmitter | ||
const Promise = require('bluebird') | ||
const { EventEmitter } = require('events') | ||
const { Pool } = require('tarn') | ||
const jwt = require('jsonwebtoken') | ||
const Promise = require('bluebird') | ||
// Notifications | ||
const Http2Client = require('./http2-client') | ||
const Errors = require('./errors') | ||
const Notification = require('./notifications/notification') | ||
@@ -12,13 +12,2 @@ const BasicNotification = require('./notifications/basic-notification') | ||
// HTTP/2 Client | ||
const HTTP2Client = (() => { | ||
try { | ||
// try native module | ||
return require('./http2-client') | ||
} catch(err) { | ||
// else fallback to spdy | ||
return require('./spdy-client') | ||
} | ||
})() | ||
/** | ||
@@ -34,3 +23,3 @@ * @const | ||
*/ | ||
const MAX_CONNECTIONS = 8 | ||
const MAX_CONNECTIONS = 10 | ||
@@ -41,3 +30,3 @@ /** | ||
*/ | ||
const CONCURRENCY = 32 | ||
const CONCURRENCY = 64 | ||
@@ -74,34 +63,2 @@ /** | ||
/** | ||
* @static | ||
* @prop {Class} Notification | ||
*/ | ||
static get Notification() { | ||
return Notification | ||
} | ||
/** | ||
* @static | ||
* @prop {Class} BasicNotification | ||
*/ | ||
static get BasicNotification() { | ||
return BasicNotification | ||
} | ||
/** | ||
* @static | ||
* @prop {Class} SilentNotification | ||
*/ | ||
static get SilentNotification() { | ||
return SilentNotification | ||
} | ||
/** | ||
* @static | ||
* @prop {Object} errors | ||
*/ | ||
static get errors() { | ||
return apnsErrors | ||
} | ||
/** | ||
* @constructor | ||
@@ -126,9 +83,34 @@ * @param {Object} options | ||
this._concurrency = concurrency | ||
this._clients = _.times(connections, () => new HTTP2Client(host, port)) | ||
this._clientIndex = 0 | ||
this._clients = this._createClientPool({ host, port, connections }) | ||
this._interval = setInterval(() => this._resetSigningToken(), RESET_TOKEN_INTERVAL).unref() | ||
this.on(apnsErrors.expiredProviderToken, () => this._resetSigningToken()) | ||
this.on(Errors.expiredProviderToken, () => this._resetSigningToken()) | ||
} | ||
/** | ||
* @private | ||
* @method _createClientPool | ||
* @param {String} host | ||
* @param {Number} port | ||
* @return {Pool} | ||
*/ | ||
_createClientPool({ host, port, connections }) { | ||
return new Pool({ | ||
create: cb => new Http2Client(host, port).connect().asCallback(cb), | ||
validate: client => client.ready, | ||
destroy: client => client.destroy(), | ||
min: 0, | ||
max: connections | ||
}) | ||
} | ||
/** | ||
* @private | ||
* @method _acquireClient | ||
* @return {Promise} | ||
*/ | ||
_acquireClient() { | ||
return Promise.resolve(this._clients.acquire().promise) | ||
} | ||
/** | ||
* @method send | ||
@@ -152,13 +134,2 @@ * @param {Array<Notification>|Notification} notifications | ||
* @private | ||
* @param {HTTP2Client} _nextClient | ||
*/ | ||
get _nextClient() { | ||
let client = this._clients[this._clientIndex] | ||
let nextIndex = this._clientIndex + 1 | ||
this._clientIndex = nextIndex < this._clients.length ? nextIndex : 0 | ||
return client | ||
} | ||
/** | ||
* @private | ||
* @method _send | ||
@@ -188,3 +159,4 @@ * @param {Notification} notification | ||
return this._nextClient.post(options, body) | ||
return this._acquireClient() | ||
.then(client => client.post(options, body)) | ||
.then(res => this._handleServerResponse(res, notification)) | ||
@@ -209,3 +181,3 @@ } | ||
} catch(err) { | ||
json = { reason: apnsErrors.unknownError } | ||
json = { reason: Errors.unknownError } | ||
} | ||
@@ -217,3 +189,3 @@ | ||
this.emit(json.reason, json) | ||
this.emit(apnsErrors.error, json) | ||
this.emit(Errors.error, json) | ||
@@ -254,3 +226,3 @@ return Promise.reject(json) | ||
token = this._token = null | ||
this.emit(apnsErrors.invalidSigningKey) | ||
this.emit(Errors.invalidSigningKey) | ||
} | ||
@@ -271,2 +243,8 @@ | ||
module.exports = APNS | ||
module.exports = { | ||
APNS, | ||
Errors, | ||
Notification, | ||
BasicNotification, | ||
SilentNotification | ||
} |
@@ -6,3 +6,5 @@ const { URL } = require('url') | ||
// Check to make sure this is the native http2 | ||
if (!http2.constants || !http2.constants.NGHTTP2_SESSION_CLIENT) throw new Error('Invalid http2 library') | ||
if (!http2.constants || !http2.constants.NGHTTP2_SESSION_CLIENT) { | ||
throw new Error('Invalid http2 library, must be running Node v8.10 or later') | ||
} | ||
@@ -27,6 +29,47 @@ const { | ||
this._timeout = timeout | ||
this.client() | ||
this._ready = false | ||
this._session = null | ||
} | ||
/** | ||
* @param {Boolean} ready | ||
*/ | ||
get ready() { | ||
return this._ready && this._session && !this._session.destroyed | ||
} | ||
/** | ||
* @param {Http2Session} | ||
*/ | ||
get session() { | ||
return this._session | ||
} | ||
/** | ||
* @method connect | ||
* @return {Promise} | ||
*/ | ||
connect() { | ||
return new Promise((resolve, reject) => { | ||
let session = http2.connect(this._url) | ||
session.once('socketError', reject) | ||
session.once('connect', () => { | ||
this._connected(session) | ||
resolve(this) | ||
}) | ||
}) | ||
} | ||
/** | ||
* @method destroy | ||
*/ | ||
destroy() { | ||
if (this._session && !this._session.destroyed) { | ||
this._session.destroy() | ||
} | ||
this._ready = false | ||
this._session = null | ||
} | ||
/** | ||
* @method get | ||
@@ -72,4 +115,5 @@ */ | ||
request({ method, path, headers={} }, body=null) { | ||
if (!method) return Promise.reject(`method is required`) | ||
if (!path) return Promise.reject(`path is required`) | ||
if (!method) throw new Error('method is required') | ||
if (!path) throw new Error('path is required') | ||
if (!this._session) throw new Error('Must call connect() before making a request') | ||
@@ -79,5 +123,5 @@ return new Promise((resolve, reject) => { | ||
headers[HTTP2_HEADER_PATH] = path | ||
let req = this.client().request(headers) | ||
let req = this._session.request(headers) | ||
// Cancel request after timeout | ||
@@ -89,5 +133,5 @@ req.setTimeout(this._timeout, () => req.rstWithCancel()) | ||
let body = '' | ||
req.on('data', chunk => body += chunk) | ||
req.on('end', () => { | ||
@@ -117,16 +161,13 @@ resolve({ | ||
* @private | ||
* @return {Http2Session} | ||
* @method _connected | ||
* @param {Http2Session} session | ||
*/ | ||
client() { | ||
if (this._client && this._client.destroyed === false) { | ||
return this._client | ||
} | ||
// Create client | ||
let client = this._client = http2.connect(this._url) | ||
// Events | ||
client.on('goaway', () => client.destroy()) | ||
return client | ||
_connected(session) { | ||
session.on('close', () => this.destroy()) | ||
session.on('frameError', () => this.destroy()) | ||
session.on('goaway', () => this.destroy()) | ||
session.on('socketError', () => this.destroy()) | ||
session.on('timeout', () => this.destroy()) | ||
this._session = session | ||
this._ready = true | ||
} | ||
@@ -133,0 +174,0 @@ } |
{ | ||
"name": "apns2", | ||
"version": "3.0.1", | ||
"version": "4.0.0", | ||
"description": "Node client for connecting to Apple's Push Notification Service using the new HTTP/2 protocol with JSON web tokens.", | ||
@@ -10,3 +10,3 @@ "author": "Andrew Barba <abarba.77@gmail.com>", | ||
"engines": { | ||
"node": ">=6.0.0" | ||
"node": ">=8.10.0" | ||
}, | ||
@@ -17,16 +17,16 @@ "repository": { | ||
"dependencies": { | ||
"bluebird": "^3.4.1", | ||
"jsonwebtoken": "^7.0.1", | ||
"lodash": "^4.13.1", | ||
"spdy": "^3.4.7" | ||
"bluebird": "3.5.1", | ||
"jsonwebtoken": "8.2.1", | ||
"lodash": "4.17.10", | ||
"tarn": "1.1.4" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^4.5.0", | ||
"mocha": "^3.3.0", | ||
"should": "^12.0.0" | ||
"eslint": "4.19.1", | ||
"mocha": "5.1.1", | ||
"should": "13.2.1" | ||
}, | ||
"scripts": { | ||
"lint": "make lint", | ||
"test": "make test-all" | ||
"lint": "npx eslint ./", | ||
"test": "npx mocha --exit --bail --slow 1000 --timeout 5000 ./test/test.js" | ||
} | ||
} |
@@ -9,6 +9,4 @@ APNS2 | ||
> Now uses the native `http2` module in Node.js v8.4.0 when exposed with `--expose-http2` | ||
> Now uses the native `http2` module in Node.js v8.10 or later | ||
> On earlier versions of Node.js we fallback to the `node-spdy` module | ||
--- | ||
@@ -21,3 +19,3 @@ | ||
```javascript | ||
const APNS = require('apns2'); | ||
const { APNS } = require('apns2') | ||
@@ -29,3 +27,3 @@ let client = new APNS({ | ||
defaultTopic: `com.tablelist.Tablelist` | ||
}); | ||
}) | ||
``` | ||
@@ -40,5 +38,5 @@ | ||
```javascript | ||
const { BasicNotification } = APNS; | ||
const { BasicNotification } = require('apns2') | ||
let bn = new BasicNotification(deviceToken, 'Hello, World'); | ||
let bn = new BasicNotification(deviceToken, 'Hello, World') | ||
@@ -48,4 +46,4 @@ client.send(bn).then(() => { | ||
}).catch(err => { | ||
console.error(err.reason); | ||
}); | ||
console.error(err.reason) | ||
}) | ||
``` | ||
@@ -56,3 +54,3 @@ | ||
```javascript | ||
const { BasicNotification } = APNS; | ||
const { BasicNotification } = require('apns2') | ||
@@ -64,3 +62,3 @@ let bn = new BasicNotification(deviceToken, 'Hello, World', { | ||
} | ||
}); | ||
}) | ||
@@ -70,4 +68,4 @@ client.send(bn).then(() => { | ||
}).catch(err => { | ||
console.error(err.reason); | ||
}); | ||
console.error(err.reason) | ||
}) | ||
``` | ||
@@ -80,5 +78,5 @@ | ||
```javascript | ||
const { SilentNotification } = APNS; | ||
const { SilentNotification } = require('apns2') | ||
let sn = new SilentNotification(deviceToken); | ||
let sn = new SilentNotification(deviceToken) | ||
@@ -88,7 +86,7 @@ client.send(sn).then(() => { | ||
}).catch(err => { | ||
console.error(err.reason); | ||
}); | ||
console.error(err.reason) | ||
}) | ||
``` | ||
Note: [Apple recommends](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH107-SW1) that no options other than the `content-available` flag be sent in order for a notification to truly be silent and wake up your app in the background. Therefore this class does not accept any additional options in the constructor. | ||
Note: [Apple recommends](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW8) that no options other than the `content-available` flag be sent in order for a notification to truly be silent and wake up your app in the background. Therefore this class does not accept any additional options in the constructor. | ||
@@ -100,7 +98,7 @@ #### Advanced | ||
```javascript | ||
const { Notification } = APNS; | ||
const { Notification } = require('apns2') | ||
let notification = new Notification(deviceToken, { | ||
aps: { ... } | ||
}); | ||
}) | ||
@@ -110,4 +108,4 @@ client.send(notification).then(() => { | ||
}).catch(err => { | ||
console.error(err.reason); | ||
}); | ||
console.error(err.reason) | ||
}) | ||
``` | ||
@@ -124,15 +122,15 @@ | ||
```javascript | ||
const errors = APNS.errors; | ||
const { Errors } = require('apns2') | ||
// Listen for a specific error | ||
client.on(errors.badDeviceToken, err => { | ||
client.on(Errors.badDeviceToken, err => { | ||
// Handle accordingly... | ||
// Perhaps delete token from your database | ||
console.error(err.reason, err.statusCode, err.notification.deviceToken); | ||
}); | ||
console.error(err.reason, err.statusCode, err.notification.deviceToken) | ||
}) | ||
// Listen for any error | ||
client.on(errors.error, err => { | ||
console.error(err.reason, err.statusCode, err.notification.deviceToken); | ||
}); | ||
client.on(Errors.error, err => { | ||
console.error(err.reason, err.statusCode, err.notification.deviceToken) | ||
}) | ||
``` | ||
@@ -149,3 +147,3 @@ | ||
... | ||
}); | ||
}) | ||
``` | ||
@@ -159,3 +157,3 @@ | ||
... | ||
}); | ||
}) | ||
``` | ||
@@ -165,6 +163,2 @@ | ||
`apns2` requires Node.js v6 | ||
#### Native http2 | ||
To use the new built in `http2` library in Node.js v8.4.0 you must start your node process with `node --expose-http2`. apns2 will automatically pick up the native module and use it instead of `node-spdy`. | ||
`apns2` requires Node.js v8.10 or later |
@@ -5,11 +5,10 @@ const fs = require('fs') | ||
// Package | ||
const APNS = require('../') | ||
const errors = APNS.errors | ||
const HTTP2Client = (() => { | ||
try { | ||
return require('../lib/http2-client') | ||
} catch(err) { | ||
return require('../lib/spdy-client') | ||
} | ||
})() | ||
const HTTP2Client = require('../lib/http2-client') | ||
const { | ||
APNS, | ||
Notification, | ||
BasicNotification, | ||
SilentNotification, | ||
Errors | ||
} = require('../') | ||
@@ -23,2 +22,3 @@ describe('http2', () => { | ||
client = new HTTP2Client('www.google.com', 443) | ||
return client.connect() | ||
}) | ||
@@ -50,10 +50,8 @@ | ||
it('should not make a get request', () => { | ||
return client.get({ | ||
path: '/' | ||
}).then(() => { | ||
throw new Error('Failed') | ||
}).catch(() => { | ||
// good | ||
}) | ||
it('should not connect', () => { | ||
return client.connect() | ||
.then(() => { | ||
throw new Error('Failed') | ||
}) | ||
.catch(() => {}) | ||
}) | ||
@@ -81,3 +79,3 @@ }) | ||
it('should send a basic notification', () => { | ||
let basicNotification = new APNS.BasicNotification(deviceToken, `Hello, Basic`) | ||
let basicNotification = new BasicNotification(deviceToken, `Hello, Basic`) | ||
return apns.send(basicNotification) | ||
@@ -87,3 +85,3 @@ }) | ||
it('should send a basic notification with options', () => { | ||
let basicNotification = new APNS.BasicNotification(deviceToken, `Hello, 1`, { | ||
let basicNotification = new BasicNotification(deviceToken, `Hello, 1`, { | ||
badge: 1 | ||
@@ -95,3 +93,3 @@ }) | ||
it('should send a basic notification with additional data', () => { | ||
let basicNotification = new APNS.BasicNotification(deviceToken, `Hello, ICON`, { | ||
let basicNotification = new BasicNotification(deviceToken, `Hello, ICON`, { | ||
badge: 0, | ||
@@ -106,3 +104,3 @@ data: { | ||
it('should send a silent notification', () => { | ||
let silentNotification = new APNS.SilentNotification(deviceToken) | ||
let silentNotification = new SilentNotification(deviceToken) | ||
return apns.send(silentNotification) | ||
@@ -112,3 +110,3 @@ }) | ||
it('should send a notification', () => { | ||
let notification = new APNS.Notification(deviceToken, { | ||
let notification = new Notification(deviceToken, { | ||
aps: { | ||
@@ -124,4 +122,4 @@ alert: { | ||
it('should send both notifications', () => { | ||
let basicNotification = new APNS.BasicNotification(deviceToken, `Hello, Multiple`) | ||
let silentNotification = new APNS.SilentNotification(deviceToken) | ||
let basicNotification = new BasicNotification(deviceToken, `Hello, Multiple`) | ||
let silentNotification = new SilentNotification(deviceToken) | ||
return apns.send([basicNotification, silentNotification]).then(result => { | ||
@@ -134,6 +132,6 @@ should.exist(result) | ||
it('should fail to send a notification', () => { | ||
let noti = new APNS.BasicNotification(`fakedevicetoken`, `Hello, bad token`) | ||
let noti = new BasicNotification(`fakedevicetoken`, `Hello, bad token`) | ||
return apns.send(noti).catch(err => { | ||
should.exist(err) | ||
err.reason.should.equal(errors.badDeviceToken) | ||
err.reason.should.equal(Errors.badDeviceToken) | ||
}) | ||
@@ -144,9 +142,9 @@ }) | ||
apns.once(errors.error, err => { | ||
apns.once(Errors.error, err => { | ||
should.exist(err) | ||
err.reason.should.equal(errors.badDeviceToken) | ||
err.reason.should.equal(Errors.badDeviceToken) | ||
done() | ||
}) | ||
let noti = new APNS.BasicNotification(`fakedevicetoken`, `Hello, bad token`) | ||
let noti = new BasicNotification(`fakedevicetoken`, `Hello, bad token`) | ||
apns.send(noti).catch(err => { | ||
@@ -159,9 +157,9 @@ should.exist(err) | ||
apns.once(errors.badDeviceToken, err => { | ||
apns.once(Errors.badDeviceToken, err => { | ||
should.exist(err) | ||
err.reason.should.equal(errors.badDeviceToken) | ||
err.reason.should.equal(Errors.badDeviceToken) | ||
done() | ||
}) | ||
let noti = new APNS.BasicNotification(`fakedevicetoken`, `Hello, bad token`) | ||
let noti = new BasicNotification(`fakedevicetoken`, `Hello, bad token`) | ||
apns.send(noti).catch(err => { | ||
@@ -168,0 +166,0 @@ should.exist(err) |
Sorry, the diff of this file is not supported yet
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
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
1
60052
15
770
149
+ Addedtarn@1.1.4
+ Addedbluebird@3.5.1(transitive)
+ Addedjsonwebtoken@8.2.1(transitive)
+ Addedlodash@4.17.10(transitive)
+ Addedlodash.includes@4.3.0(transitive)
+ Addedlodash.isboolean@3.0.3(transitive)
+ Addedlodash.isinteger@4.0.4(transitive)
+ Addedlodash.isnumber@3.0.3(transitive)
+ Addedlodash.isplainobject@4.0.6(transitive)
+ Addedlodash.isstring@4.0.1(transitive)
+ Addedtarn@1.1.4(transitive)
- Removedspdy@^3.4.7
- Removedbluebird@3.7.2(transitive)
- Removedcore-util-is@1.0.3(transitive)
- Removeddebug@2.6.9(transitive)
- Removeddetect-node@2.1.0(transitive)
- Removedhandle-thing@1.2.5(transitive)
- Removedhoek@2.16.3(transitive)
- Removedhpack.js@2.1.6(transitive)
- Removedhttp-deceiver@1.2.7(transitive)
- Removedinherits@2.0.4(transitive)
- Removedisarray@1.0.0(transitive)
- Removedisemail@1.2.0(transitive)
- Removedjoi@6.10.1(transitive)
- Removedjsonwebtoken@7.4.3(transitive)
- Removedlodash@4.17.21(transitive)
- Removedminimalistic-assert@1.0.1(transitive)
- Removedmoment@2.30.1(transitive)
- Removedms@2.0.0(transitive)
- Removedobuf@1.1.2(transitive)
- Removedprocess-nextick-args@2.0.1(transitive)
- Removedreadable-stream@2.3.8(transitive)
- Removedsafe-buffer@5.1.2(transitive)
- Removedselect-hose@2.0.0(transitive)
- Removedspdy@3.4.7(transitive)
- Removedspdy-transport@2.1.1(transitive)
- Removedstring_decoder@1.1.1(transitive)
- Removedtopo@1.1.0(transitive)
- Removedutil-deprecate@1.0.2(transitive)
- Removedwbuf@1.7.3(transitive)
Updatedbluebird@3.5.1
Updatedjsonwebtoken@8.2.1
Updatedlodash@4.17.10