Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

customerio-node

Package Overview
Dependencies
Maintainers
4
Versions
44
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

customerio-node - npm Package Compare versions

Comparing version 2.1.1 to 3.0.0-beta.1

8

CHANGELOG.md

@@ -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 @@

10

dist/api.d.ts

@@ -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';

27

dist/request.d.ts

@@ -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

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