UNPKG

feathers-shippo

Version:

A Feathers JS adapter for the Shippo API

280 lines (279 loc) 10.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ShippoService = exports.shippo = exports.axiosOpts = exports.shippoLimiters = exports.shippoLimiter = exports.calcMinTime = void 0; const errors = __importStar(require("@feathersjs/errors")); const bottleneck_1 = __importDefault(require("bottleneck")); const axios_1 = __importDefault(require("axios")); const SHIPPO_API_URL = 'https://api.goshippo.com'; []; const calcMinTime = (perMinute) => 60000 / perMinute; exports.calcMinTime = calcMinTime; // https://goshippo.com/docs/rate-limits/ const liveMinTimes = { create: (0, exports.calcMinTime)(500), update: (0, exports.calcMinTime)(500), get: (0, exports.calcMinTime)(4000), find: (0, exports.calcMinTime)(50), remove: (0, exports.calcMinTime)(500) // Note most services don't actually have remove }; const testMinTimes = { create: (0, exports.calcMinTime)(50), update: (0, exports.calcMinTime)(50), get: (0, exports.calcMinTime)(400), find: (0, exports.calcMinTime)(5), remove: (0, exports.calcMinTime)(50) // Note most services don't actually have remove }; const shippoLimiter = (method, minTimes) => { const limiter = new bottleneck_1.default({ minTime: minTimes[method] }); // TODO: Inspect the error for a timeoute/expiry to retry after limiter.on('failed', (error, jobInfo) => __awaiter(void 0, void 0, void 0, function* () { if (error.code === 429 && jobInfo.retryCount === 0) { // Retry once after 200ms return 200; } })); return limiter; }; exports.shippoLimiter = shippoLimiter; const shippoLimiters = (token) => { if (!token) { throw new errors.GeneralError('options.token is required a Shippo API Token for new ShippoService()'); } const minTimes = token.startsWith('shippo_live') ? liveMinTimes : testMinTimes; return { create: (0, exports.shippoLimiter)('create', minTimes), update: (0, exports.shippoLimiter)('update', minTimes), get: (0, exports.shippoLimiter)('get', minTimes), find: (0, exports.shippoLimiter)('find', minTimes), remove: (0, exports.shippoLimiter)('remove', minTimes) }; }; exports.shippoLimiters = shippoLimiters; const axiosOpts = (params) => { return { params: params === null || params === void 0 ? void 0 : params.query }; }; exports.axiosOpts = axiosOpts; const shippoResource = (service) => { const { path } = service.options; return { create: (data, params) => { return service.schedule('create', () => __awaiter(void 0, void 0, void 0, function* () { return service.shippo.post(path, data, (0, exports.axiosOpts)(params)); })); }, update: (id, data, params) => { return service.schedule('update', () => { if (!id) { throw new errors.BadRequest('ID is required'); } return service.shippo.put(`${path}/${id}`, data, (0, exports.axiosOpts)(params)); }); }, get: (id, params) => { return service.schedule('get', () => { if (!id) { throw new errors.BadRequest('ID is required'); } return service.shippo.get(`${path}/${id}`, (0, exports.axiosOpts)(params)); }); }, find: (params) => { return service.schedule('find', () => __awaiter(void 0, void 0, void 0, function* () { return service.shippo.get(path, (0, exports.axiosOpts)(params)); })); }, remove: (id, params) => { return service.schedule('remove', () => { return service.shippo.delete(`${path}/${id}`, (0, exports.axiosOpts)(params)); }); } }; }; const shippo = (token) => { return axios_1.default.create({ baseURL: SHIPPO_API_URL, headers: { Authorization: `ShippoToken ${token}`, 'Accept-Encoding': null } }); }; exports.shippo = shippo; class ShippoService { constructor(options, app) { this.options = options; this.app = app; const { token, path } = options; if (!token) { throw new errors.GeneralError('options.token is required a Shippo API Token for new ShippoService()'); } if (!path) { throw new errors.GeneralError(`${path} is invalid options.path for new ShippoService()`); } this.shippo = (0, exports.shippo)(token); this.resource = shippoResource(this); } handleError(error, params) { if (params) { params.shippoError = error; } if (!error.response) { throw error; } const FeathersError = errors[error.response.status]; if (FeathersError) { throw new FeathersError(error.message, error.response.data); } throw new errors.BadRequest(error.message || error, error); } handleMethod(method) { const { methods, path } = this.options; if (!methods.includes(method)) { throw new errors.NotImplemented(`"${method}" not implemented on "${path}" ShippoService`); } } handleResult(result, params) { if (params) { params.shippoResult = result; } if (result.data.results) { result.data.data = result.data.results; delete result.data.results; } if (result.data.count) { result.data.total = result.data.count; delete result.data.count; } return result.data; } schedule(method, fn) { const { limiters } = this.options; if (limiters && limiters[method]) { return limiters[method].schedule(fn); } return fn(); } _create(data, params) { return __awaiter(this, void 0, void 0, function* () { this.handleMethod('create'); return this.resource .create(data, params) .then(this.handleResult) .catch(this.handleError); }); } create(data, params) { return __awaiter(this, void 0, void 0, function* () { return this._create(data, params); }); } _get(id, params) { return __awaiter(this, void 0, void 0, function* () { this.handleMethod('get'); return this.resource .get(id, params) .then(this.handleResult) .catch(this.handleError); }); } get(id, params) { return __awaiter(this, void 0, void 0, function* () { return this._get(id, params); }); } _find(params) { return __awaiter(this, void 0, void 0, function* () { this.handleMethod('find'); return this.resource .find(params) .then(this.handleResult) .catch(this.handleError); }); } find(params) { return __awaiter(this, void 0, void 0, function* () { return this._find(params); }); } _update(id, data, params) { return __awaiter(this, void 0, void 0, function* () { this.handleMethod('update'); return this.resource .update(id, data, params) .then(this.handleResult) .catch(this.handleError); }); } update(id, data, params) { return __awaiter(this, void 0, void 0, function* () { return this._update(id, data, params); }); } _patch(id, data, params) { return __awaiter(this, void 0, void 0, function* () { this.handleMethod('patch'); return this._update(id, data, params) .then(this.handleResult) .catch(this.handleError); }); } patch(id, data, params) { return __awaiter(this, void 0, void 0, function* () { return this._patch(id, data, params); }); } _remove(id, params) { return __awaiter(this, void 0, void 0, function* () { this.handleMethod('remove'); return this.resource .remove(id, params) .then(this.handleResult) .catch(this.handleError); }); } remove(id, params) { return __awaiter(this, void 0, void 0, function* () { return this._remove(id, params); }); } } exports.ShippoService = ShippoService;