customerio-node
Advanced tools
Comparing version 2.1.1 to 3.0.0-beta.1
@@ -6,2 +6,10 @@ # Changelog | ||
- (**BREAKING**) Remove the dependency on `request` ([#62](https://github.com/customerio/customerio-node/pull/62)) | ||
- We don't expect this to break many consumers of `customerio-node`. Unless you were using [`request`](https://github.com/request/request#requestoptions-callback) specific options, you don't need to make any changes. | ||
- (**BREAKING**) Return an `Error` instance for non-`2XX` status codes ([#62](https://github.com/customerio/customerio-node/pull/62)) | ||
- We don't expect this to break many consumers of `customerio-node`. Unless you were using `instanceof` to check the type of error returned from track or api methods, you don't need to make any changed. `message`, `statusCode`, `response`, and `body` are still accessible as properties on the error. | ||
- Return a readable message when the server returns an array of errors instead of `Unknown error` ([#62](https://github.com/customerio/customerio-node/pull/62)) | ||
## [2.1.1] | ||
@@ -8,0 +16,0 @@ |
@@ -1,5 +0,7 @@ | ||
import Request, { BearerAuth, RequestData, RequestDefaults } from './request'; | ||
/// <reference types="node" /> | ||
import type { RequestOptions } from 'https'; | ||
import Request, { BearerAuth, RequestData } from './request'; | ||
import { Region } from './regions'; | ||
import { SendEmailRequest } from './api/requests'; | ||
declare type APIDefaults = RequestDefaults & { | ||
declare type APIDefaults = RequestOptions & { | ||
region: Region; | ||
@@ -15,5 +17,5 @@ url?: string; | ||
constructor(appKey: BearerAuth, defaults?: Partial<APIDefaults>); | ||
sendEmail(req: SendEmailRequest): Promise<unknown>; | ||
triggerBroadcast(id: string | number, data: RequestData, recipients: Recipients): Promise<unknown>; | ||
sendEmail(req: SendEmailRequest): Promise<Record<string, any>>; | ||
triggerBroadcast(id: string | number, data: RequestData, recipients: Recipients): Promise<Record<string, any>>; | ||
} | ||
export { SendEmailRequest } from './api/requests'; |
@@ -1,3 +0,3 @@ | ||
import request from 'request'; | ||
import type { RequiredUriUrl, CoreOptions } from 'request'; | ||
/// <reference types="node" /> | ||
import type { RequestOptions } from 'https'; | ||
export declare type BasicAuth = { | ||
@@ -9,5 +9,9 @@ apikey: string; | ||
export declare type RequestAuth = BasicAuth | BearerAuth; | ||
export declare type RequestDefaults = CoreOptions; | ||
export declare type RequestOptions = CoreOptions & RequiredUriUrl; | ||
export declare type RequestData = Record<string, any> | undefined; | ||
export declare type RequestHandlerOptions = { | ||
method: RequestOptions['method']; | ||
uri: string; | ||
headers: RequestOptions['headers']; | ||
body?: string | null; | ||
}; | ||
export default class CIORequest { | ||
@@ -18,10 +22,9 @@ apikey?: BasicAuth['apikey']; | ||
auth: string; | ||
defaults: RequestDefaults; | ||
private request; | ||
constructor(auth: RequestAuth, defaults?: RequestDefaults); | ||
options(uri: string, method: CoreOptions['method'], data?: RequestData): request.CoreOptions & request.UriOptions; | ||
handler(options: RequestOptions): Promise<unknown>; | ||
put(uri: string, data?: RequestData): Promise<unknown>; | ||
destroy(uri: string): Promise<unknown>; | ||
post(uri: string, data?: RequestData): Promise<unknown>; | ||
defaults: RequestOptions; | ||
constructor(auth: RequestAuth, defaults?: RequestOptions); | ||
options(uri: string, method: RequestOptions['method'], data?: RequestData): RequestHandlerOptions; | ||
handler({ uri, body, method, headers }: RequestHandlerOptions): Promise<Record<string, any>>; | ||
put(uri: string, data?: RequestData): Promise<Record<string, any>>; | ||
destroy(uri: string): Promise<Record<string, any>>; | ||
post(uri: string, data?: RequestData): Promise<Record<string, any>>; | ||
} |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const request_1 = __importDefault(require("request")); | ||
const https_1 = require("https"); | ||
const utils_1 = require("./utils"); | ||
const TIMEOUT = 10000; | ||
@@ -22,41 +20,47 @@ class CIORequest { | ||
}, defaults); | ||
this.request = request_1.default.defaults(this.defaults); | ||
} | ||
options(uri, method, data) { | ||
const body = data ? JSON.stringify(data) : null; | ||
const headers = { | ||
Authorization: this.auth, | ||
'Content-Type': 'application/json', | ||
'Content-Length': body ? body.length : 0, | ||
}; | ||
const body = data ? JSON.stringify(data) : null; | ||
const options = { method, uri, headers, body }; | ||
if (!body) | ||
delete options.body; | ||
return options; | ||
return { method, uri, headers, body }; | ||
} | ||
handler(options) { | ||
handler({ uri, body, method, headers }) { | ||
return new Promise((resolve, reject) => { | ||
this.request(options, (error, response, body) => { | ||
if (error) | ||
return reject(error); | ||
let json = null; | ||
try { | ||
if (body) | ||
json = JSON.parse(body); | ||
} | ||
catch (e) { | ||
const message = `Unable to parse JSON. Error: ${e} \nBody:\n ${body}`; | ||
return reject(new Error(message)); | ||
} | ||
if (response.statusCode == 200 || response.statusCode == 201) { | ||
resolve(json); | ||
} | ||
else { | ||
reject({ | ||
message: (json && json.meta && json.meta.error) || 'Unknown error', | ||
statusCode: response.statusCode, | ||
response: response, | ||
body: body, | ||
}); | ||
} | ||
let options = Object.assign({}, this.defaults, { method, headers }); | ||
let req = https_1.request(uri, options, (res) => { | ||
let chunks = []; | ||
res.on('data', (data) => { | ||
chunks.push(data); | ||
}); | ||
res.on('end', () => { | ||
let body = Buffer.concat(chunks).toString('utf-8'); | ||
let json = null; | ||
try { | ||
if (body && body.length) { | ||
json = JSON.parse(body); | ||
} | ||
} | ||
catch (error) { | ||
const message = `Unable to parse JSON. Error: ${error} \nBody:\n ${body}`; | ||
return reject(new Error(message)); | ||
} | ||
if (res.statusCode == 200 || res.statusCode == 201) { | ||
resolve(json); | ||
} | ||
else { | ||
reject(new utils_1.CustomerIORequestError(json, res.statusCode || 0, res, body)); | ||
} | ||
}); | ||
}); | ||
req.on('error', (error) => { | ||
reject(error); | ||
}); | ||
if (body) { | ||
req.write(body); | ||
} | ||
req.end(); | ||
}); | ||
@@ -63,0 +67,0 @@ } |
@@ -1,4 +0,6 @@ | ||
import Request, { BasicAuth, RequestData, RequestDefaults } from './request'; | ||
/// <reference types="node" /> | ||
import type { RequestOptions } from 'https'; | ||
import Request, { BasicAuth, RequestData } from './request'; | ||
import { Region } from './regions'; | ||
declare type TrackDefaults = RequestDefaults & { | ||
declare type TrackDefaults = RequestOptions & { | ||
region: Region; | ||
@@ -16,11 +18,11 @@ url?: string; | ||
constructor(siteid: BasicAuth['siteid'], apikey: BasicAuth['apikey'], defaults?: Partial<TrackDefaults>); | ||
identify(customerId: string | number, data?: RequestData): Promise<unknown>; | ||
destroy(customerId: string | number): Promise<unknown>; | ||
suppress(customerId: string | number): Promise<unknown>; | ||
track(customerId: string | number, data?: RequestData): Promise<unknown>; | ||
trackAnonymous(data?: RequestData): Promise<unknown>; | ||
trackPageView(customerId: string | number, path: string): Promise<unknown>; | ||
addDevice(customerId: string | number, device_id: string, platform: string, data?: {}): Promise<unknown>; | ||
deleteDevice(customerId: string | number, deviceToken: string | number): Promise<unknown>; | ||
identify(customerId: string | number, data?: RequestData): Promise<Record<string, any>>; | ||
destroy(customerId: string | number): Promise<Record<string, any>>; | ||
suppress(customerId: string | number): Promise<Record<string, any>>; | ||
track(customerId: string | number, data?: RequestData): Promise<Record<string, any>>; | ||
trackAnonymous(data?: RequestData): Promise<Record<string, any>>; | ||
trackPageView(customerId: string | number, path: string): Promise<Record<string, any>>; | ||
addDevice(customerId: string | number, device_id: string, platform: string, data?: {}): Promise<Record<string, any>>; | ||
deleteDevice(customerId: string | number, deviceToken: string | number): Promise<Record<string, any>>; | ||
} | ||
export {}; |
@@ -0,1 +1,10 @@ | ||
/// <reference types="node" /> | ||
import { IncomingMessage } from 'http'; | ||
export declare const isEmpty: (value: unknown) => boolean; | ||
export declare class CustomerIORequestError extends Error { | ||
statusCode: number; | ||
response: IncomingMessage; | ||
body: string; | ||
static composeMessage(json: Record<string, any> | null): string; | ||
constructor(json: Record<string, any> | null, statusCode: number, response: IncomingMessage, body: string); | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isEmpty = void 0; | ||
exports.CustomerIORequestError = exports.isEmpty = void 0; | ||
const isEmpty = (value) => { | ||
@@ -8,1 +8,25 @@ return value === null || value === undefined || (typeof value === 'string' && value.trim() === ''); | ||
exports.isEmpty = isEmpty; | ||
class CustomerIORequestError extends Error { | ||
constructor(json, statusCode, response, body) { | ||
super(CustomerIORequestError.composeMessage(json)); | ||
this.name = 'CustomerIORequestError'; | ||
this.statusCode = statusCode; | ||
this.response = response; | ||
this.body = body; | ||
} | ||
static composeMessage(json) { | ||
if (!json) { | ||
return 'Unknown error'; | ||
} | ||
if (json.meta && json.meta.error) { | ||
return json.meta.error; | ||
} | ||
else if (json.meta && json.meta.errors) { | ||
const count = json.meta.errors.length; | ||
return `${count} ${count === 1 ? 'error' : 'errors'}: | ||
${json.meta.errors.map((error) => ` - ${error}`).join('\n')}`; | ||
} | ||
return 'Unknown error'; | ||
} | ||
} | ||
exports.CustomerIORequestError = CustomerIORequestError; |
@@ -1,6 +0,7 @@ | ||
import Request, { BearerAuth, RequestData, RequestDefaults } from './request'; | ||
import type { RequestOptions } from 'https'; | ||
import Request, { BearerAuth, RequestData } from './request'; | ||
import { Region, RegionUS } from './regions'; | ||
import { SendEmailRequest } from './api/requests'; | ||
type APIDefaults = RequestDefaults & { region: Region; url?: string }; | ||
type APIDefaults = RequestOptions & { region: Region; url?: string }; | ||
@@ -7,0 +8,0 @@ type Recipients = Record<string, unknown>; |
@@ -1,3 +0,4 @@ | ||
import request from 'request'; | ||
import type { Request, RequiredUriUrl, RequestAPI, CoreOptions } from 'request'; | ||
import { request } from 'https'; | ||
import type { RequestOptions } from 'https'; | ||
import { CustomerIORequestError } from './utils'; | ||
@@ -12,5 +13,9 @@ export type BasicAuth = { | ||
export type RequestAuth = BasicAuth | BearerAuth; | ||
export type RequestDefaults = CoreOptions; | ||
export type RequestOptions = CoreOptions & RequiredUriUrl; | ||
export type RequestData = Record<string, any> | undefined; | ||
export type RequestHandlerOptions = { | ||
method: RequestOptions['method']; | ||
uri: string; | ||
headers: RequestOptions['headers']; | ||
body?: string | null; | ||
}; | ||
@@ -24,7 +29,5 @@ const TIMEOUT = 10_000; | ||
auth: string; | ||
defaults: RequestDefaults; | ||
defaults: RequestOptions; | ||
private request: RequestAPI<Request, CoreOptions, RequiredUriUrl>; | ||
constructor(auth: RequestAuth, defaults?: RequestDefaults) { | ||
constructor(auth: RequestAuth, defaults?: RequestOptions) { | ||
if (typeof auth === 'object') { | ||
@@ -46,43 +49,56 @@ this.apikey = auth.apikey; | ||
); | ||
this.request = request.defaults(this.defaults); | ||
} | ||
options(uri: string, method: CoreOptions['method'], data?: RequestData) { | ||
options(uri: string, method: RequestOptions['method'], data?: RequestData): RequestHandlerOptions { | ||
const body = data ? JSON.stringify(data) : null; | ||
const headers = { | ||
Authorization: this.auth, | ||
'Content-Type': 'application/json', | ||
'Content-Length': body ? body.length : 0, | ||
}; | ||
const body = data ? JSON.stringify(data) : null; | ||
const options: RequestOptions = { method, uri, headers, body }; | ||
if (!body) delete options.body; | ||
return options; | ||
return { method, uri, headers, body }; | ||
} | ||
handler(options: RequestOptions) { | ||
handler({ uri, body, method, headers }: RequestHandlerOptions): Promise<Record<string, any>> { | ||
return new Promise((resolve, reject) => { | ||
this.request(options, (error, response, body) => { | ||
if (error) return reject(error); | ||
let options = Object.assign({}, this.defaults, { method, headers }); | ||
let req = request(uri, options, (res) => { | ||
let chunks: Buffer[] = []; | ||
let json = null; | ||
try { | ||
if (body) json = JSON.parse(body); | ||
} catch (e) { | ||
const message = `Unable to parse JSON. Error: ${e} \nBody:\n ${body}`; | ||
return reject(new Error(message)); | ||
} | ||
res.on('data', (data: Buffer) => { | ||
chunks.push(data); | ||
}); | ||
if (response.statusCode == 200 || response.statusCode == 201) { | ||
resolve(json); | ||
} else { | ||
reject({ | ||
message: (json && json.meta && json.meta.error) || 'Unknown error', | ||
statusCode: response.statusCode, | ||
response: response, | ||
body: body, | ||
}); | ||
} | ||
res.on('end', () => { | ||
let body = Buffer.concat(chunks).toString('utf-8'); | ||
let json = null; | ||
try { | ||
if (body && body.length) { | ||
json = JSON.parse(body); | ||
} | ||
} catch (error) { | ||
const message = `Unable to parse JSON. Error: ${error} \nBody:\n ${body}`; | ||
return reject(new Error(message)); | ||
} | ||
if (res.statusCode == 200 || res.statusCode == 201) { | ||
resolve(json); | ||
} else { | ||
reject(new CustomerIORequestError(json, res.statusCode || 0, res, body)); | ||
} | ||
}); | ||
}); | ||
req.on('error', (error: any) => { | ||
reject(error); | ||
}); | ||
if (body) { | ||
req.write(body); | ||
} | ||
req.end(); | ||
}); | ||
@@ -89,0 +105,0 @@ } |
@@ -1,6 +0,7 @@ | ||
import Request, { BasicAuth, RequestData, RequestDefaults } from './request'; | ||
import type { RequestOptions } from 'https'; | ||
import Request, { BasicAuth, RequestData } from './request'; | ||
import { Region, RegionUS } from './regions'; | ||
import { isEmpty } from './utils'; | ||
type TrackDefaults = RequestDefaults & { region: Region; url?: string; apiUrl?: string }; | ||
type TrackDefaults = RequestOptions & { region: Region; url?: string; apiUrl?: string }; | ||
@@ -7,0 +8,0 @@ class MissingParamError extends Error { |
@@ -0,3 +1,37 @@ | ||
import { IncomingMessage } from 'http'; | ||
export const isEmpty = (value: unknown) => { | ||
return value === null || value === undefined || (typeof value === 'string' && value.trim() === ''); | ||
}; | ||
export class CustomerIORequestError extends Error { | ||
statusCode: number; | ||
response: IncomingMessage; | ||
body: string; | ||
static composeMessage(json: Record<string, any> | null): string { | ||
if (!json) { | ||
return 'Unknown error'; | ||
} | ||
if (json.meta && json.meta.error) { | ||
return json.meta.error; | ||
} else if (json.meta && json.meta.errors) { | ||
const count = json.meta.errors.length; | ||
return `${count} ${count === 1 ? 'error' : 'errors'}: | ||
${json.meta.errors.map((error: string) => ` - ${error}`).join('\n')}`; | ||
} | ||
return 'Unknown error'; | ||
} | ||
constructor(json: Record<string, any> | null, statusCode: number, response: IncomingMessage, body: string) { | ||
super(CustomerIORequestError.composeMessage(json)); | ||
this.name = 'CustomerIORequestError'; | ||
this.statusCode = statusCode; | ||
this.response = response; | ||
this.body = body; | ||
} | ||
} |
{ | ||
"name": "customerio-node", | ||
"description": "A node client for the Customer.io event API. http://customer.io", | ||
"version": "2.1.1", | ||
"version": "3.0.0-beta.1", | ||
"author": "Customer.io (https://customer.io)", | ||
@@ -44,15 +44,12 @@ "contributors": [ | ||
"bugs": "https://github.com/customerio/customerio-node/issues", | ||
"dependencies": { | ||
"@types/request": "^2.48.5", | ||
"request": "^2.58.0" | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"@types/node": "^14.14.41", | ||
"@types/sinon": "^10.0.0", | ||
"@types/node": "^15.12.4", | ||
"@types/sinon": "^10.0.2", | ||
"ava": "^3.15.0", | ||
"nyc": "^15.1.0", | ||
"prettier": "^2.2.1", | ||
"sinon": "^10.0.0", | ||
"ts-node": "^9.1.1", | ||
"typescript": "^4.2.4" | ||
"prettier": "^2.3.1", | ||
"sinon": "^11.1.1", | ||
"ts-node": "^10.0.0", | ||
"typescript": "^4.3.4" | ||
}, | ||
@@ -59,0 +56,0 @@ "homepage": "https://github.com/customerio/customerio-node", |
@@ -27,3 +27,3 @@ # Customerio [![test](https://github.com/customerio/customerio-node/actions/workflows/main.yml/badge.svg)](https://github.com/customerio/customerio-node/actions/workflows/main.yml) | ||
Optionally you can pass `defaults` as an object that will be passed to the underlying request instance. A list of the possible options are listed [here](https://github.com/request/request#requestoptions-callback). | ||
Optionally you can pass `defaults` as an object that will be passed to the underlying request instance. A list of the possible options are listed [here](https://nodejs.org/api/http.html#http_http_request_options_callback). | ||
@@ -100,3 +100,3 @@ This is useful to override the default 10s timeout. Example: | ||
- **id**: String (requiredl) | ||
- **id**: String (required) | ||
- **data**: Object (required) | ||
@@ -103,0 +103,0 @@ - _name_ is a required key on the Object |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
47195
0
861
1
1
- Removed@types/request@^2.48.5
- Removedrequest@^2.58.0
- Removed@types/caseless@0.12.5(transitive)
- Removed@types/node@22.9.0(transitive)
- Removed@types/request@2.48.12(transitive)
- Removed@types/tough-cookie@4.0.5(transitive)
- Removedajv@6.12.6(transitive)
- Removedasn1@0.2.6(transitive)
- Removedassert-plus@1.0.0(transitive)
- Removedasynckit@0.4.0(transitive)
- Removedaws-sign2@0.7.0(transitive)
- Removedaws4@1.13.2(transitive)
- Removedbcrypt-pbkdf@1.0.2(transitive)
- Removedcaseless@0.12.0(transitive)
- Removedcombined-stream@1.0.8(transitive)
- Removedcore-util-is@1.0.2(transitive)
- Removeddashdash@1.14.1(transitive)
- Removeddelayed-stream@1.0.0(transitive)
- Removedecc-jsbn@0.1.2(transitive)
- Removedextend@3.0.2(transitive)
- Removedextsprintf@1.3.0(transitive)
- Removedfast-deep-equal@3.1.3(transitive)
- Removedfast-json-stable-stringify@2.1.0(transitive)
- Removedforever-agent@0.6.1(transitive)
- Removedform-data@2.3.32.5.2(transitive)
- Removedgetpass@0.1.7(transitive)
- Removedhar-schema@2.0.0(transitive)
- Removedhar-validator@5.1.5(transitive)
- Removedhttp-signature@1.2.0(transitive)
- Removedis-typedarray@1.0.0(transitive)
- Removedisstream@0.1.2(transitive)
- Removedjsbn@0.1.1(transitive)
- Removedjson-schema@0.4.0(transitive)
- Removedjson-schema-traverse@0.4.1(transitive)
- Removedjson-stringify-safe@5.0.1(transitive)
- Removedjsprim@1.4.2(transitive)
- Removedmime-db@1.52.0(transitive)
- Removedmime-types@2.1.35(transitive)
- Removedoauth-sign@0.9.0(transitive)
- Removedperformance-now@2.1.0(transitive)
- Removedpsl@1.10.0(transitive)
- Removedpunycode@2.3.1(transitive)
- Removedqs@6.5.3(transitive)
- Removedrequest@2.88.2(transitive)
- Removedsafe-buffer@5.2.1(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsshpk@1.18.0(transitive)
- Removedtough-cookie@2.5.0(transitive)
- Removedtunnel-agent@0.6.0(transitive)
- Removedtweetnacl@0.14.5(transitive)
- Removedundici-types@6.19.8(transitive)
- Removeduri-js@4.4.1(transitive)
- Removeduuid@3.4.0(transitive)
- Removedverror@1.10.0(transitive)