Comparing version 1.2.0 to 2.10.2
const VERSION = require('../package.json').version | ||
const { REJOINER_API_KEY, REJOINER_API_SECRET, REJOINER_SITE_ID } = process.env | ||
const { REJOINER_API_KEY, REJOINER_SITE_ID, REJOINER_WEBHOOK_SECRET } = process.env | ||
const DEFAULT_BASE_URL = 'https://rj2.rejoiner.com/api/v1' | ||
const REJOINER_BASE_URL = process.env.REJOINER_BASE_URL || DEFAULT_BASE_URL | ||
module.exports = { | ||
VERSION, | ||
REJOINER_API_KEY, | ||
REJOINER_API_SECRET, | ||
REJOINER_SITE_ID, | ||
REJOINER_WEBHOOK_SECRET, | ||
REJOINER_BASE_URL, | ||
} |
@@ -0,8 +1,26 @@ | ||
const { withClient } = require('../helpers') | ||
const listsEndpoint = (client) => { | ||
const endpoint = 'lists' | ||
const { dispatchReturnData, postEmail } = withClient(client) | ||
return { | ||
name: endpoint, | ||
get: () => client.dispatch.get(endpoint) | ||
.then(res => res.data), | ||
path: endpoint, | ||
get: () => dispatchReturnData('get')(`${endpoint}/`), | ||
add: (name) => { | ||
if (typeof name === 'string') { | ||
return dispatchReturnData('post')(`${endpoint}/`, { name }) | ||
} | ||
return dispatchReturnData('post')(`${endpoint}/`, name) | ||
}, | ||
contacts: listId => ({ | ||
get: (page) => { | ||
const pagination = page ? `?page=${page}` : '' | ||
return dispatchReturnData('get')(`${endpoint}/${listId}/contacts/${pagination}`) | ||
}, | ||
add: email => postEmail(`${endpoint}/${listId}/contacts/`, email), | ||
remove: email => postEmail(`${endpoint}/${listId}/contacts/remove/`, email), | ||
}), | ||
} | ||
@@ -9,0 +27,0 @@ } |
@@ -5,3 +5,3 @@ const axios = require('axios') | ||
const path = require('path') | ||
const { merge } = require('lodash') | ||
const merge = require('lodash.merge') | ||
@@ -11,7 +11,8 @@ const { | ||
REJOINER_API_KEY, | ||
REJOINER_API_SECRET, | ||
REJOINER_SITE_ID, | ||
REJOINER_WEBHOOK_SECRET, | ||
REJOINER_BASE_URL, | ||
} = require('./config') | ||
function Rejoiner(options) { | ||
function Rejoiner2(options) { | ||
const opts = merge({}, options) | ||
@@ -21,32 +22,16 @@ | ||
this.apiKey = opts.apiKey || REJOINER_API_KEY | ||
this.apiSecret = opts.apiSecret || REJOINER_API_SECRET | ||
this.webhookSecret = opts.webhookSecret || REJOINER_WEBHOOK_SECRET | ||
this.baseURL = opts.baseURL || REJOINER_BASE_URL | ||
this.sign = ({ httpVerb, requestPath, requestBody }) => { | ||
const req = [httpVerb, requestPath, requestBody].join('\n') | ||
return crypto.createHmac('sha1', this.apiSecret).update(req).digest('base64') | ||
} | ||
if (!this.siteId) throw new Error('Site ID must be configured') | ||
if (!this.apiKey) throw new Error('API Key must be configured') | ||
this.dispatch = axios.create({ | ||
baseURL: `https://app.rejoiner.com/api/1.0/site/${this.siteId}`, | ||
baseURL: `${this.baseURL}/${this.siteId}`, | ||
headers: { | ||
'User-Agent': `rejoiner-node/v${VERSION}`, | ||
Authorization: `Rejoiner ${this.apiKey}`, | ||
'User-Agent': `rejoiner2-node/v${VERSION}`, | ||
}, | ||
}) | ||
this.dispatch.interceptors.request.use((conf) => { | ||
const signedReq = this.sign({ | ||
httpVerb: conf.method.toUpperCase(), | ||
requestPath: conf.url.replace('https://app.rejoiner.com', ''), | ||
requestBody: JSON.stringify(conf.data), | ||
}) | ||
const withSignedReqHeader = merge({}, conf, { | ||
headers: { | ||
Authorization: `Rejoiner ${this.apiKey}:${signedReq}`, | ||
}, | ||
}) | ||
return withSignedReqHeader | ||
}) | ||
fs.readdirSync(path.join(__dirname, 'endpoints')) | ||
@@ -57,6 +42,31 @@ .filter(file => file.indexOf('.') !== 0) | ||
const endpoint = require(path.join(__dirname, 'endpoints', file))(this) | ||
this[endpoint.name] = endpoint | ||
this[endpoint.path] = endpoint | ||
}) | ||
this.verifyWebhook = (signatureHeader, payload) => { | ||
if (!this.webhookSecret) throw new Error('No webhook secret configured') | ||
const { timestamp, hmac } = signatureHeader.split(',') | ||
.reduce((signature, element) => { | ||
const [key, value] = element.trim().split('=') | ||
switch (key) { | ||
case 't': | ||
return { ...signature, timestamp: value } | ||
case 'sha1': | ||
return { ...signature, hmac: value } | ||
default: | ||
return signature | ||
} | ||
}, {}) | ||
const signedPayload = `${timestamp}.${payload}` | ||
const digest = crypto.createHmac('sha1', this.webhookSecret) | ||
.update(signedPayload) | ||
.digest('hex') | ||
return digest === hmac | ||
} | ||
} | ||
module.exports = Rejoiner | ||
module.exports = Rejoiner2 |
{ | ||
"name": "rejoiner", | ||
"description": "Rejoiner REST API client wrapper for Node.js", | ||
"version": "1.2.0", | ||
"version": "2.10.2", | ||
"main": "lib/rejoiner.js", | ||
@@ -29,3 +29,3 @@ "author": "Sascha Bratton <sascha@brattonbratton.com>", | ||
"graceful-fs": "^4.1.11", | ||
"lodash": "^4.17.13" | ||
"lodash.merge": "^4.6.2" | ||
}, | ||
@@ -37,3 +37,6 @@ "devDependencies": { | ||
"husky": "^0.14.3" | ||
}, | ||
"engines": { | ||
"node": ">=8.3.0" | ||
} | ||
} |
135
README.md
@@ -20,40 +20,67 @@ # Rejoiner Node.js client wrapper | ||
var apiClient = new Rejoiner({ | ||
siteId: '527bcca942bd247ca1816847', | ||
domain: '173.203.96.102', | ||
apiKey: '63cab4a5e1c44fcbbe260daa3f0bc55d', | ||
apiSecret: 'cb015c09a3b54688a247470b462082b3', | ||
var client = new Rejoiner({ | ||
// Your Site ID | ||
siteId: 'eXaMpLe', | ||
// Your API key | ||
apiKey: 'tHiSaPiKeYiSjUsTaNeXaMpLeAnDyOuCaNtUsEiT', | ||
}) | ||
```` | ||
## Endpoints | ||
## Ping | ||
### Convert Lead | ||
The `ping` endpoint can be used to verify your credentials are working. | ||
````js | ||
apiClient.lead.convert({ | ||
email: 'foo2@bar.com', | ||
client.verify.ping() | ||
.then(...) | ||
.catch(...) | ||
```` | ||
## Customer Endpoints | ||
### Convert Customer | ||
````js | ||
client.customer.convert({ | ||
email: 'test@example.com', | ||
cart_data: { | ||
cart_value: 79996, | ||
cart_value: 20000, | ||
cart_item_count: 2, | ||
promo: 'COUPON_CODE', | ||
return_url: 'https://www.example.com/return_url', | ||
... | ||
}, | ||
cart_items: [{ | ||
'name': 'Item Name', | ||
'product_id': 'ITM1', | ||
'price': 19999, | ||
'product_url': 'http://yoursite.com/productpage', | ||
'category': ['televisions', 'smart_tv'], | ||
'item_qty': 2, | ||
'qty_price': 39998, | ||
'image_url': 'http://yoursite.com/path/to/image.jpg' | ||
}, { | ||
'name': 'Item Name2', | ||
'product_id': 'ITM2', | ||
'price': 19999, | ||
'product_url': 'http://yoursite.com/productpage2', | ||
'category': ['televisions'], | ||
'item_qty': 2, | ||
'qty_price': 39998, | ||
'image_url': 'http://yoursite.com/path/to/image2.jpg' | ||
}], | ||
cart_items: [ | ||
{ | ||
product_id: 'example', | ||
name: 'Example Product', | ||
price: 10000, | ||
description: 'Information about Example Product.', | ||
category: [ | ||
'Example Category 1', | ||
'Example Category 2', | ||
], | ||
item_qty: 1, | ||
qty_price: 10000, | ||
product_url: 'https://www.example.com/products/example', | ||
image_url: 'https://www.example.com/products/example/images/example.jpg', | ||
... | ||
}, | ||
{ | ||
product_id: 'example2', | ||
name: 'Example Product 2', | ||
price: 10000, | ||
description: 'Information about Example Product 2.', | ||
category: [ | ||
'Example Category 2', | ||
'Example Category 3', | ||
], | ||
item_qty: 1, | ||
qty_price: 10000, | ||
product_url: 'https://www.example.com/products/example2', | ||
image_url: 'https://www.example.com/products/example2/images/example.jpg', | ||
... | ||
}, | ||
... | ||
], | ||
}) | ||
@@ -64,6 +91,6 @@ .then(...) | ||
### Cancellation | ||
### Journey Cancellation | ||
````js | ||
apiClient.lead.cancel('foo@bar.com') | ||
client.customer.cancel('test@example.com') | ||
.then(...) | ||
@@ -73,10 +100,6 @@ .catch(...) | ||
### Adding Contact to List | ||
### Customer Unsubscribe | ||
````js | ||
apiClient.contact.add({ | ||
email: 'foo@bar.com', | ||
list_id: '5706374ae6ec520d3370e368', | ||
first_name: 'Tom', | ||
}) | ||
client.customer.unsubscribe('test@example.com') | ||
.then(...) | ||
@@ -86,6 +109,6 @@ .catch(...) | ||
### Unsubscribe Contact | ||
### Record Explicit Customer Consent | ||
````js | ||
apiClient.lead.unsubscribe('foo@bar.com') | ||
client.customer.optIn('test@example.com') | ||
.then(...) | ||
@@ -95,6 +118,8 @@ .catch(...) | ||
### Retrieve Lists | ||
## Email List Endpoints | ||
### Email Lists | ||
````js | ||
apiClient.lists.get() | ||
client.lists.get() | ||
.then(...) | ||
@@ -104,8 +129,32 @@ .catch(...) | ||
### Record Contact Opt In | ||
### Retrieving Listing of Contacts | ||
````js | ||
apiClient.lead.optIn('foo@bar.com') | ||
client.lists.contacts('eXaMpLeLiStId').get() | ||
.then(...) | ||
.catch(...) | ||
```` | ||
#### With optional page number for pagination | ||
````js | ||
client.lists.contacts('eXaMpLeLiStId').get(2) | ||
.then(...) | ||
.catch(...) | ||
```` | ||
### Add Customer to List | ||
````js | ||
client.lists.contacts('eXaMpLeLiStId').add('test@example.com') | ||
.then(...) | ||
.catch(...) | ||
```` | ||
### Remove Customer From List | ||
````js | ||
client.lists.contacts('eXaMpLeLiStId').remove('test@example.com') | ||
.then(...) | ||
.catch(...) | ||
```` |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
11215
12
185
0
155
3
1
+ Addedlodash.merge@^4.6.2
+ Addedlodash.merge@4.6.2(transitive)
- Removedlodash@^4.17.13
- Removedlodash@4.17.21(transitive)