Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
# Changelog
All notable changes to this project will be documented in this file.

## 0.5.0
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

- Add `trackByTrackingNumber(trackRequest, options)` — calls the FedEx Track API (`POST /track/v1/trackingnumbers`). Same passthrough pattern as the other methods: caller supplies the full request body, the package forwards it verbatim. Supports `options.customer_transaction_id` and `options.timeout`. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.
## [0.5.1] - 2026-05-26
### Fixed
- A 200 response carrying an `errors[]` envelope now rejects with an `HttpError` that includes the error detail. The already-read body is passed to `HttpError.from(response, json)`, since the response stream is consumed by `response.json()` and can't be re-read. Requires `@stores.com/http-error` `~1.2.0`.

## 0.4.0
## [0.5.0] - 2026-05-21
### Added
- `trackByTrackingNumber(trackRequest, options)` — calls the FedEx Track API (`POST /track/v1/trackingnumbers`). Same passthrough pattern as the other methods: caller supplies the full request body, the package forwards it verbatim. Supports `options.customer_transaction_id` and `options.timeout`. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.

- Add `groundEndOfDayClose(closeRequest, options)` — calls the FedEx Ground End of Day Close API (`PUT /ship/v1/endofday/`). Same passthrough pattern as the other methods: caller supplies the full request body, the package forwards it verbatim. Supports `options.customer_transaction_id` and `options.timeout`. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.
## [0.4.0] - 2026-05-14
### Added
- `groundEndOfDayClose(closeRequest, options)` — calls the FedEx Ground End of Day Close API (`PUT /ship/v1/endofday/`). Same passthrough pattern as the other methods: caller supplies the full request body, the package forwards it verbatim. Supports `options.customer_transaction_id` and `options.timeout`. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.

## 0.3.0
## [0.3.0] - 2026-05-13
### Added
- `createShipment(shipRequest, options)` — calls the FedEx Ship API to create a shipment (`POST /ship/v1/shipments`). Same passthrough pattern as the other methods: caller supplies the full request body, the package forwards it verbatim. Supports `options.customer_transaction_id` and `options.timeout`. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.
- `cancelShipment(cancelRequest, options)` — calls the FedEx Ship API to cancel a shipment (`PUT /ship/v1/shipments/cancel`). Same passthrough pattern. Supports `options.customer_transaction_id` and `options.timeout`. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.

- Add `createShipment(shipRequest, options)` — calls the FedEx Ship API to create a shipment (`POST /ship/v1/shipments`). Same passthrough pattern as the other methods: caller supplies the full request body, the package forwards it verbatim. Supports `options.customer_transaction_id` and `options.timeout`. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.
- Add `cancelShipment(cancelRequest, options)` — calls the FedEx Ship API to cancel a shipment (`PUT /ship/v1/shipments/cancel`). Same passthrough pattern. Supports `options.customer_transaction_id` and `options.timeout`. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.

## 0.2.0

- Add `validateAddress(addressValidationRequest, options)` — calls the FedEx Address Validation API (`POST /address/v1/addresses/resolve`). Same passthrough pattern as `rateAndTransitTimes`: caller supplies the full request body, the package forwards it verbatim. Supports `options.customer_transaction_id` and `options.timeout` like the other methods. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.

## 0.1.0
## [0.2.0] - 2026-05-12
### Added
- `validateAddress(addressValidationRequest, options)` — calls the FedEx Address Validation API (`POST /address/v1/addresses/resolve`). Same passthrough pattern as `rateAndTransitTimes`: caller supplies the full request body, the package forwards it verbatim. Supports `options.customer_transaction_id` and `options.timeout` like the other methods. Non-2xx responses and 200-with-`errors[]` envelopes both reject with `HttpError`.

## [0.1.0] - 2026-05-08
### Added
- Initial release.
- `new FedEx({ api_key, secret_key, url })` — client constructor.
- `getAccessToken(options)` — OAuth `client_credentials` token, cached in memory per `api_key` for half the token lifetime.
Expand Down
12 changes: 6 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function FedEx(args) {
const json = await response.json();

if (json.errors?.length) {
throw await HttpError.from(response);
throw await HttpError.from(response, json);
}

return json;
Expand Down Expand Up @@ -91,7 +91,7 @@ function FedEx(args) {
const json = await response.json();

if (json.errors?.length) {
throw await HttpError.from(response);
throw await HttpError.from(response, json);
}

return json;
Expand Down Expand Up @@ -179,7 +179,7 @@ function FedEx(args) {
const json = await response.json();

if (json.errors?.length) {
throw await HttpError.from(response);
throw await HttpError.from(response, json);
}

return json;
Expand Down Expand Up @@ -224,7 +224,7 @@ function FedEx(args) {
const json = await response.json();

if (json.errors?.length) {
throw await HttpError.from(response);
throw await HttpError.from(response, json);
}

return json;
Expand Down Expand Up @@ -269,7 +269,7 @@ function FedEx(args) {
const json = await response.json();

if (json.errors?.length) {
throw await HttpError.from(response);
throw await HttpError.from(response, json);
}

return json;
Expand Down Expand Up @@ -314,7 +314,7 @@ function FedEx(args) {
const json = await response.json();

if (json.errors?.length) {
throw await HttpError.from(response);
throw await HttpError.from(response, json);
}

return json;
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"dependencies": {
"@stores.com/http-error": "~1.1.0",
"@stores.com/http-error": "~1.2.0",
"memory-cache": "~0.2.0"
},
"description": "FedEx REST API client for address validation, ground end of day close, OAuth tokens, rate quotes, shipment cancellation, shipment creation, and tracking.",
Expand Down Expand Up @@ -36,5 +36,5 @@
"test": "node --test --test-force-exit --test-reporter=spec",
"test:only": "node --test --test-force-exit --test-only --test-reporter=spec"
},
"version": "0.5.0"
"version": "0.5.1"
}
12 changes: 12 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ test('cancelShipment (mocked)', async (t) => {
trackingNumber: '794644790138'
}), (err) => {
assert.strictEqual(err.name, 'HttpError');
assert.ok(err.json?.errors?.length, 'errors[] envelope should be captured');
assert.notStrictEqual(err.message, '200 ', 'message should reflect the errors, not the bare status');
return true;
});
});
Expand Down Expand Up @@ -320,6 +322,8 @@ test('createShipment (mocked)', async (t) => {
requestedShipment: {}
}), (err) => {
assert.strictEqual(err.name, 'HttpError');
assert.ok(err.json?.errors?.length, 'errors[] envelope should be captured');
assert.notStrictEqual(err.message, '200 ', 'message should reflect the errors, not the bare status');
return true;
});
});
Expand Down Expand Up @@ -534,6 +538,8 @@ test('groundEndOfDayClose (mocked)', async (t) => {
groundServiceCategory: 'GROUND'
}), (err) => {
assert.strictEqual(err.name, 'HttpError');
assert.ok(err.json?.errors?.length, 'errors[] envelope should be captured');
assert.notStrictEqual(err.message, '200 ', 'message should reflect the errors, not the bare status');
return true;
});
});
Expand Down Expand Up @@ -833,6 +839,8 @@ test('rateAndTransitTimes (mocked)', async (t) => {
}
}), (err) => {
assert.strictEqual(err.name, 'HttpError');
assert.ok(err.json?.errors?.length, 'errors[] envelope should be captured');
assert.notStrictEqual(err.message, '200 ', 'message should reflect the errors, not the bare status');
return true;
});
});
Expand Down Expand Up @@ -1350,6 +1358,8 @@ test('trackByTrackingNumber (mocked)', async (t) => {
}]
}), (err) => {
assert.strictEqual(err.name, 'HttpError');
assert.ok(err.json?.errors?.length, 'errors[] envelope should be captured');
assert.notStrictEqual(err.message, '200 ', 'message should reflect the errors, not the bare status');
return true;
});
});
Expand Down Expand Up @@ -1949,6 +1959,8 @@ test('validateAddress (mocked)', async (t) => {
}]
}), (err) => {
assert.strictEqual(err.name, 'HttpError');
assert.ok(err.json?.errors?.length, 'errors[] envelope should be captured');
assert.notStrictEqual(err.message, '200 ', 'message should reflect the errors, not the bare status');
return true;
});
});
Expand Down