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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- Default `User-Agent` retains structured runtime metadata fields (`Nodejs/`, `OS/`, `OSVersion/`, `OSArch/`) via runtime-safe detection
- TypeScript declarations are now generated from source and published from `dist/types`.
- Internal root `types/` declaration sources and demo fixtures were removed from the repository.
- Calling `retrieveStatelessRates` now returns the entire response and not only the `rates` key, allowing errors and other useful information to be exposed. Note that you will now need to reference the `rates` key to get the returned rates

## v8.9.0 (2026-06-25)

Expand Down
16 changes: 12 additions & 4 deletions src/services/beta_rate_service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import baseService from './base_service';
import type EasyPostClient from '../easypost';
import type Rate from '../models/rate';
import baseService from './base_service';

type BetaRateRetrieveResponse = {
rates?: Rate[];
[key: string]: unknown;
};

/**
* @extends baseService
Expand All @@ -9,9 +15,11 @@ export default (easypostClient: EasyPostClient) =>
/**
* Retrieve a list of stateless {@link Rate rates} based on the provided parameters.
* @param {Object} params - Map of parameters for the API call
* @returns {Rate[]} - List of stateless rates
* @returns {Object} - Stateless rates response
*/
static async retrieveStatelessRates(params: Record<string, unknown>) {
static async retrieveStatelessRates(
params: Record<string, unknown>,
): Promise<BetaRateRetrieveResponse> {
const url = 'beta/rates';
const wrappedParams = {
shipment: params,
Expand All @@ -20,7 +28,7 @@ export default (easypostClient: EasyPostClient) =>
try {
const response = await easypostClient._post(url, wrappedParams);

return this._convertToEasyPostObject(response.body.rates, wrappedParams);
return this._convertToEasyPostObject(response.body, wrappedParams);
} catch (e) {
return Promise.reject(e);
}
Expand Down
16 changes: 10 additions & 6 deletions test/services/beta_rate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,34 +26,38 @@ describe('BetaRateService', function () {
});

it('retrieves a list of stateless rates', async function () {
const statelessRates = await client.BetaRate.retrieveStatelessRates(
const statelessRateResponse = await client.BetaRate.retrieveStatelessRates(
Fixture.basicShipment() as BetaRateRetrieveInput,
);

statelessRates.forEach((rate: any) => {
statelessRateResponse.rates.forEach((rate: any) => {
expect(rate).to.be.an.instanceOf(Rate);
expect(rate).to.not.have.property('id');
});
});

it('retrieve the lowest rate', async function () {
const statelessRates = await client.BetaRate.retrieveStatelessRates(
const statelessRateResponse = await client.BetaRate.retrieveStatelessRates(
Fixture.basicShipment() as BetaRateRetrieveInput,
);

const lowestStatelessRate = client.Utils.getLowestRate(statelessRates);
const lowestStatelessRate = client.Utils.getLowestRate(statelessRateResponse.rates);

expect(lowestStatelessRate.service).to.be.equal('GroundAdvantage');
expect(lowestStatelessRate.rate).to.be.equal('6.98');
});

it('retrieve invalid lowest rate', async function () {
const statelessRates = await client.BetaRate.retrieveStatelessRates(
const statelessRateResponse = await client.BetaRate.retrieveStatelessRates(
Fixture.basicShipment() as BetaRateRetrieveInput,
);

expect(() => {
client.Utils.getLowestRate(statelessRates, ['invalid_carrier'], ['invalid_service']);
client.Utils.getLowestRate(
statelessRateResponse.rates,
['invalid_carrier'],
['invalid_service'],
);
}).to.throw(FilteringError, 'No rates found.');
});
});