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

@mediocre/bloodhound

Package Overview
Dependencies
Maintainers
0
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mediocre/bloodhound - npm Package Compare versions

Comparing version 1.14.0 to 2.0.0

247

carriers/fedEx.js
const async = require('async');
const FedExClient = require('shipping-fedex');
const cache = require('memory-cache');
const createError = require('http-errors');
const request = require('request');

@@ -18,5 +20,45 @@ const checkDigit = require('../util/checkDigit');

function FedEx(options) {
const fedExClient = new FedExClient(options);
function FedEx(args) {
const options = Object.assign({
url: 'https://apis.fedex.com'
}, args);
this.getAccessToken = function(callback) {
const key = args.api_key;
const accessToken = cache.get(key);
if (accessToken) {
return callback(null, accessToken);
}
const req = {
form: {
grant_type: 'client_credentials',
client_id: args.api_key,
client_secret: args.secret_key
},
method: 'POST',
url: `${options.url}/oauth/token`
};
request(req, function(err, response, body) {
if (err) {
return callback(err);
}
if (response.statusCode !== 200) {
const err = createError(response.statusCode);
err.response = response;
return callback(err);
}
const accessToken = JSON.parse(body);
cache.put(key, accessToken, (accessToken.expires_in - 100) * 1000);
return callback(null, accessToken);
});
};
this.isTrackingNumberValid = function(trackingNumber) {

@@ -84,16 +126,49 @@ // Remove whitespace

// Create a FedEx track request: https://www.fedex.com/us/developer/webhelp/ws/2018/US/index.htm#t=wsdvg%2FTracking_Shipments.htm%23Tracking_Service_Optionsbc-3&rhtocid=_26_0_2
const trackRequest = {
SelectionDetails: {
PackageIdentifier: {
Type: 'TRACKING_NUMBER_OR_DOORTAG',
Value: trackingNumber
}
},
ProcessingOptions: 'INCLUDE_DETAILED_SCANS'
};
this.getAccessToken(function(err, accessToken) {
if (err) {
return callback(err);
}
// FedEx Web Services requests occasionally fail. Timeout after 5 seconds and retry.
async.retry(function(callback) {
async.timeout(fedExClient.track, 5000)(trackRequest, function(err, trackReply) {
const trackRequestOptions = {
gzip: true,
headers: {
Authorization: `Bearer ${accessToken.access_token}`
},
json: {
includeDetailedScans: true,
trackingInfo: [
{
trackingNumberInfo: {
trackingNumber: trackingNumber
}
}
]
},
method: 'POST',
url: `${options.url}/track/v1/trackingnumbers`
};
async.retry(function(callback) {
request(trackRequestOptions, function(err, response, trackResponse) {
if (err) {
return callback(err);
}
if (trackResponse?.output?.alerts?.length) {
let alerts = trackResponse.output.alerts;
let warnings = alerts.filter(alert => alert.alertType === 'WARNING');
if (warnings.length) {
return callback(new Error(warnings.map(warning => `${warning.code}: ${warning.message}`).join(', ')));
}
}
// Return if only one track detail is returned
if (trackResponse?.output?.completeTrackResults?.trackResults?.scanEvents?.length === 1) {
return callback(null, trackResponse);
}
callback(null, trackResponse);
});
}, function(err, trackReply) {
if (err) {

@@ -103,119 +178,67 @@ return callback(err);

if (trackReply.HighestSeverity === 'ERROR') {
return callback(new Error(trackReply.Notifications[0].Message));
}
const results = {
carrier: 'FedEx',
events: [],
raw: trackReply
};
// Return if only one track detail is returned
if (trackReply?.CompletedTrackDetails?.[0]?.TrackDetails.length === 1) {
return callback(null, trackReply);
// Ensure track reply has events
if (!trackReply?.output?.completeTrackResults?.[0]?.trackResults?.[0]?.scanEvents?.length) {
return callback(null, results);
}
async.mapLimit(trackReply.CompletedTrackDetails[0].TrackDetails, 10, function(trackDetail, callback) {
const trackRequest = {
SelectionDetails: {
PackageIdentifier: {
Type: 'TRACKING_NUMBER_OR_DOORTAG',
Value: trackingNumber
},
TrackingNumberUniqueIdentifier: trackDetail.TrackingNumberUniqueIdentifier
trackReply?.output?.completeTrackResults?.[0]?.trackResults?.[0]?.scanEvents.forEach(e => {
if (TRACKING_STATUS_CODES_BLACKLIST.includes(e.eventType)) {
return;
}
const event = {
address: {
city: e?.scanLocation?.city,
country: e?.scanLocation?.countryCode,
state: e?.scanLocation?.stateOrProvinceCode,
zip: e?.scanLocation?.postalCode
},
ProcessingOptions: 'INCLUDE_DETAILED_SCANS'
date: new Date(e.date),
description: e.eventDescription
};
async.retry(function(callback) {
async.timeout(fedExClient.track, 5000)(trackRequest, function(err, trackReply) {
if (err) {
return callback(err);
}
// Ensure event is after minDate (used to prevent data from reused tracking numbers)
if (event.date < _options.minDate) {
return;
}
if (trackReply.HighestSeverity === 'ERROR') {
return callback(new Error(trackReply.Notifications[0].Message));
}
if (e.exceptionDescription) {
event.details = e.exceptionDescription;
}
callback(null, trackReply);
});
}, callback);
}, function(err, trackReplies) {
if (err) {
return callback(err);
// Remove blacklisted words
if (event.address.city) {
event.address.city = event.address.city.replace(CITY_BLACKLIST, '').trim();
}
// Sort track replies by timestamp
trackReplies.sort((a, b) => b.CompletedTrackDetails[0].TrackDetails[0].StatusDetail.CreationTime - a.CompletedTrackDetails[0].TrackDetails[0].StatusDetail.CreationTime);
if (DELIVERED_TRACKING_STATUS_CODES.includes(e.eventType)) {
results.deliveredAt = new Date(e.date);
}
// Get the most recent track reply
trackReply = trackReplies[0];
if (SHIPPED_TRACKING_STATUS_CODES.includes(e.eventType)) {
results.shippedAt = new Date(e.date);
}
callback(null, trackReply);
results.events.push(event);
});
});
}, function(err, trackReply) {
if (err) {
return callback(err);
}
const results = {
carrier: 'FedEx',
events: [],
raw: trackReply
};
// Add url to carrier tracking page
results.url = `https://www.fedex.com/apps/fedextrack/?tracknumbers=${encodeURIComponent(trackingNumber)}`;
// Ensure track reply has events
if (!trackReply?.CompletedTrackDetails?.[0]?.TrackDetails?.[0]?.Events?.length) {
return callback(null, results);
}
trackReply.CompletedTrackDetails[0].TrackDetails[0].Events.forEach(e => {
if (TRACKING_STATUS_CODES_BLACKLIST.includes(e.EventType)) {
return;
if (!results.shippedAt && results.deliveredAt) {
results.shippedAt = results.deliveredAt;
}
const event = {
address: {
city: e?.Address?.City,
country: e?.Address?.CountryCode,
state: e?.Address?.StateOrProvinceCode,
zip: e?.Address?.PostalCode
},
date: new Date(e.Timestamp),
description: e.EventDescription
};
// Ensure event is after minDate (used to prevent data from reused tracking numbers)
if (event.date < _options.minDate) {
return;
}
if (e.StatusExceptionDescription) {
event.details = e.StatusExceptionDescription;
}
// Remove blacklisted words
if (event.address.city) {
event.address.city = event.address.city.replace(CITY_BLACKLIST, '').trim();
}
if (DELIVERED_TRACKING_STATUS_CODES.includes(e.EventType)) {
results.deliveredAt = new Date(e.Timestamp);
}
if (SHIPPED_TRACKING_STATUS_CODES.includes(e.EventType)) {
results.shippedAt = new Date(e.Timestamp);
}
results.events.push(event);
callback(null, results);
});
// Add url to carrier tracking page
results.url = `https://www.fedex.com/apps/fedextrack/?tracknumbers=${encodeURIComponent(trackingNumber)}`;
if (!results.shippedAt && results.deliveredAt) {
results.shippedAt = results.deliveredAt;
}
callback(null, results);
});
}
};
}
module.exports = FedEx;

@@ -9,2 +9,6 @@ # Changelog

## [2.0.0] - 2024-08-30
### Changed
- Migrated the FedEx carrier integration away from the deprecated WSDL endpoints to the new OAuth/JSON endpoints.
## [1.13.0] - 2024-05-08

@@ -11,0 +15,0 @@ ### Changed

@@ -90,4 +90,4 @@ const NodeGeocoder = require('node-geocoder');

if (typeof options === 'function') {
callback = options;
options = {};
callback = options;
}

@@ -94,0 +94,0 @@

@@ -7,2 +7,4 @@ {

"fast-xml-parser": "~3.21.0",
"http-errors": "~2.0.0",
"memory-cache": "~0.2.0",
"moment-timezone": "~0.5.28",

@@ -12,5 +14,5 @@ "node-geocoder": "~3.28.0",

"pitney-bowes": "~0.3.1",
"shipping-fedex": "0.2.0",
"tz-lookup": "~6.1.25",
"us-states-normalize": "~1.0.0"
"us-states-normalize": "~1.0.0",
"xml2js": "~0.4.23"
},

@@ -45,3 +47,3 @@ "devDependencies": {

},
"version": "1.14.0"
"version": "2.0.0"
}

@@ -61,3 +61,3 @@ # Bloodhound

Creates a new Bloodhound client. Each carrier requires a different combination of credentials (account numbers, meter numbers, passwords, user IDs, etc).
Creates a new Bloodhound client. Each carrier requires a different combination of credentials (API keys, account numbers, passwords, user IDs, etc).

@@ -74,7 +74,4 @@ By default, when Bloodhound encounters a timestamp without a UTC offset it will geocode using OpenStreetMap (which does not require an API key). You can optionally use a different geocoder. You can also optionally cache geocode results in Redis.

fedEx: {
account_number: '123456789',
environment: 'live',
key: 'abcdefghijklmnop',
meter_number: '987654321',
password: 'abcdefghijklmnopqrstuvwxy'
api_key: 'abcdefghijklmnopqrstuvwxyz',
secret_key: 'abcdefghijklmnopqrstuvwxyz'
},

@@ -111,8 +108,4 @@ geocoder: {

**fedEx**
*geocoder**
FedEx options are passed to the [shipping-fedex](https://www.npmjs.com/package/shipping-fedex) module.
**geocoder**
By default Bloodhound uses the OpenStreetMap geocode provider. You can optionally specify geocoder options which are passed to the [node-geocode](https://www.npmjs.com/package/node-geocoder) module.

@@ -119,0 +112,0 @@

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