From acf36a96d6ae88390b2181664cf9df047120c1f9 Mon Sep 17 00:00:00 2001 From: Justintime50 <39606064+Justintime50@users.noreply.github.com> Date: Thu, 6 Aug 2026 15:15:57 -0600 Subject: [PATCH 1/3] step4: convert core entry and shared utils to ts --- src/{constants.js => constants.ts} | 1 + src/{easypost.js => easypost.ts} | 1 + src/utils/{internal_util.js => internal_util.ts} | 1 + src/utils/{util.js => util.ts} | 1 + tsconfig.build.json | 1 + vite.config.js | 4 ++-- 6 files changed, 7 insertions(+), 2 deletions(-) rename src/{constants.js => constants.ts} (99%) rename src/{easypost.js => easypost.ts} (99%) rename src/utils/{internal_util.js => internal_util.ts} (93%) rename src/utils/{util.js => util.ts} (99%) diff --git a/src/constants.js b/src/constants.ts similarity index 99% rename from src/constants.js rename to src/constants.ts index 7a714e907..2a52b4697 100644 --- a/src/constants.js +++ b/src/constants.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import Utils from './utils/util'; /** diff --git a/src/easypost.js b/src/easypost.ts similarity index 99% rename from src/easypost.js rename to src/easypost.ts index b86082806..ea35bbdbf 100644 --- a/src/easypost.js +++ b/src/easypost.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import util from 'util'; import { v4 as uuid } from 'uuid'; diff --git a/src/utils/internal_util.js b/src/utils/internal_util.ts similarity index 93% rename from src/utils/internal_util.js rename to src/utils/internal_util.ts index 99385e7d2..09f27f487 100644 --- a/src/utils/internal_util.js +++ b/src/utils/internal_util.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Utility class of various internal helper functions. * This class is not designed to be used directly by consumers of the library. diff --git a/src/utils/util.js b/src/utils/util.ts similarity index 99% rename from src/utils/util.js rename to src/utils/util.ts index ab26d7804..6c6be45a2 100644 --- a/src/utils/util.js +++ b/src/utils/util.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import crypto from 'crypto'; import util from 'util'; diff --git a/tsconfig.build.json b/tsconfig.build.json index e301a68b4..f4bfc21ac 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -3,6 +3,7 @@ "compilerOptions": { "allowJs": true, "checkJs": false, + "noImplicitAny": false, "declaration": true, "noEmit": true }, diff --git a/vite.config.js b/vite.config.js index 901662487..653e064df 100644 --- a/vite.config.js +++ b/vite.config.js @@ -10,7 +10,7 @@ export default defineConfig({ // drop node 12 support in the future, change this to the next min version target: 'node12', lib: { - entry: path.resolve(__dirname, 'src/easypost.js'), + entry: path.resolve(__dirname, 'src/easypost.ts'), fileName: 'easypost', }, sourcemap: isDev, @@ -32,7 +32,7 @@ export default defineConfig({ }, resolve: { - extensions: ['.js'], + extensions: ['.ts', '.js'], alias: { '@': path.resolve(__dirname, 'src'), }, From a1c30e407183c131966c95c98dbec9d5f7916472 Mon Sep 17 00:00:00 2001 From: Justintime50 <39606064+Justintime50@users.noreply.github.com> Date: Fri, 7 Aug 2026 13:24:48 -0600 Subject: [PATCH 2/3] tsm-04: remove ts-nocheck and add explicit permissive types --- src/constants.ts | 1 - src/easypost.ts | 141 +++++++++++++++++++++++++++---------- src/utils/internal_util.ts | 1 - src/utils/util.ts | 38 +++++++--- 4 files changed, 132 insertions(+), 49 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 2a52b4697..7a714e907 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import Utils from './utils/util'; /** diff --git a/src/easypost.ts b/src/easypost.ts index ea35bbdbf..7800c3343 100644 --- a/src/easypost.ts +++ b/src/easypost.ts @@ -1,8 +1,6 @@ -// @ts-nocheck import util from 'util'; import { v4 as uuid } from 'uuid'; -import pkg from '../package.json'; import Constants from './constants'; import ErrorHandler from './errors/error_handler'; import MissingParameterError from './errors/general/missing_parameter_error'; @@ -40,6 +38,35 @@ import UserService from './services/user_service'; import WebhookService from './services/webhook_service'; import Utils from './utils/util'; +const pkgVersion = process.env.npm_package_version ?? 'unknown'; + +type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'; +type RequestHeaders = Record; + +type ClientOptions = { + apiKey?: string; + useProxy?: boolean; + timeout?: number; + baseUrl?: string; + httpMiddleware?: any; + requestMiddleware?: any; + httpClient?: any; +}; + +type HookValue = { + method: string; + path: string; + requestBody: unknown; + headers: RequestHeaders; + requestTimestamp: number; + requestUUID: string; + httpStatus?: number; + responseBody?: unknown; + responseTimestamp?: number; +}; + +type HookHandler = any; + /** * The client used to access services of the EasyPost API. * This client is configured to use the latest production version of the EasyPost API. @@ -47,7 +74,25 @@ import Utils from './utils/util'; * @param {Object} [options] Additional options to use for the underlying HTTP client (e.g. middleware, proxy configuration). */ export default class EasyPostClient { - constructor(key, options = {}) { + static MS_SECOND: number; + static DEFAULT_TIMEOUT: number; + static DEFAULT_BASE_URL: string; + static DEFAULT_HEADERS: RequestHeaders; + static METHODS: Record<'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', HttpMethod>; + static SERVICES: Record; + + [key: string]: any; + key?: string; + useProxy?: boolean; + timeout: number; + baseUrl: string; + httpClient: any; + requestMiddleware?: any; + requestHooks: HookHandler[]; + responseHooks: HookHandler[]; + Utils: Utils; + + constructor(key?: string, options: ClientOptions = {}) { const { useProxy, timeout, baseUrl, httpMiddleware, requestMiddleware, httpClient } = options; if (!key && !useProxy) { @@ -60,7 +105,13 @@ export default class EasyPostClient { this.timeout = timeout || EasyPostClient.DEFAULT_TIMEOUT; this.baseUrl = baseUrl || EasyPostClient.DEFAULT_BASE_URL; this.httpClient = - httpClient || (typeof fetch === 'function' ? (...args) => fetch(...args) : undefined); + httpClient || + (typeof fetch === 'function' + ? (input: RequestInfo | URL, init?: RequestInit) => fetch(input, init) + : async () => { + throw new Error('No global fetch implementation found. Node 18+ is required.'); + }); + this.useProxy = useProxy; this.requestMiddleware = requestMiddleware; this.requestHooks = []; this.responseHooks = []; @@ -81,20 +132,20 @@ export default class EasyPostClient { * Add a request hook function. * @param {(config: object) => void} hook */ - addRequestHook(hook) { + addRequestHook(hook: HookHandler): void { this.requestHooks = [...this.requestHooks, hook]; } /** * Remove a request hook function. * @param {(config: object) => void} hook */ - removeRequestHook(hook) { + removeRequestHook(hook: HookHandler): void { this.requestHooks = this.requestHooks.filter((h) => h !== hook); } /** * Clear all request hooks. */ - clearRequestHooks() { + clearRequestHooks(): void { this.requestHooks = []; } @@ -102,20 +153,20 @@ export default class EasyPostClient { * Add a response hook function. * @param {(config: object) => void} hook */ - addResponseHook(hook) { + addResponseHook(hook: HookHandler): void { this.responseHooks = [...this.responseHooks, hook]; } /** * Remove a response hook function. * @param {(config: object) => void} hook */ - removeResponseHook(hook) { + removeResponseHook(hook: HookHandler): void { this.responseHooks = this.responseHooks.filter((h) => h !== hook); } /** * Clear all response hooks. */ - clearResponseHooks() { + clearResponseHooks(): void { this.responseHooks = []; } @@ -130,7 +181,11 @@ export default class EasyPostClient { * @param {Object} [params] - The parameters to send with the request. * @returns {Promise} The response from the API call. */ - async makeApiCall(method, endpoint, params = {}) { + async makeApiCall( + method: string, + endpoint: string, + params: Record = {}, + ): Promise { const response = await this._request(endpoint, method, params); return response.body; @@ -142,7 +197,7 @@ export default class EasyPostClient { * @param {Object} [options] The options to override. * @returns {EasyPostClient} A new `EasyPostClient` instance. */ - static copyClient(client, options = {}) { + static copyClient(client: EasyPostClient, options: ClientOptions = {}): EasyPostClient { const { apiKey, useProxy, timeout, baseUrl, httpMiddleware, requestMiddleware, httpClient } = options; const nextHttpClient = @@ -162,7 +217,7 @@ export default class EasyPostClient { * @param {string} method - The method passed in by callers. * @returns {string} lowercase method suitable for fetch. */ - static _normalizeMethod(method = EasyPostClient.METHODS.GET) { + static _normalizeMethod(method: string = EasyPostClient.METHODS.GET): string { return method.toLowerCase(); } @@ -170,7 +225,7 @@ export default class EasyPostClient { * Executes a fetch request with timeout support. * @private */ - async _fetchWithTimeout(url, init) { + async _fetchWithTimeout(url: string, init: RequestInit): Promise { if (typeof AbortSignal !== 'undefined' && typeof AbortSignal.timeout === 'function') { return this.httpClient(url, { ...init, @@ -195,7 +250,7 @@ export default class EasyPostClient { * Parse an HTTP response body. * @private */ - async _parseResponseBody(response) { + async _parseResponseBody(response: Response): Promise { const text = await response.text(); if (!text) { return {}; @@ -212,7 +267,7 @@ export default class EasyPostClient { * Encodes a string to base64 in both Node and edge runtimes. * @private */ - static _toBase64(value) { + static _toBase64(value: string): string { if (typeof Buffer !== 'undefined') { return Buffer.from(value).toString('base64'); } @@ -225,7 +280,7 @@ export default class EasyPostClient { * @param {Object} [additionalHeaders] Additional headers to combine or override with the default headers. * @returns {Object} The headers to use for the request. */ - static _buildHeaders(additionalHeaders = {}) { + static _buildHeaders(additionalHeaders: RequestHeaders = {}): RequestHeaders { return { ...EasyPostClient.DEFAULT_HEADERS, 'User-Agent': EasyPostClient._buildUserAgent(), @@ -238,7 +293,7 @@ export default class EasyPostClient { * do not expose Node globals/modules. * @returns {string} The default User-Agent header value. */ - static _buildUserAgent() { + static _buildUserAgent(): string { let nodeVersion = 'unknown'; let osName = 'unknown'; let osVersion = 'unknown'; @@ -253,14 +308,14 @@ export default class EasyPostClient { osVersion; } - return `EasyPost/v2 NodejsClient/${pkg.version} Nodejs/${nodeVersion} OS/${osName} OSVersion/${osVersion} OSArch/${osArch}`; + return `EasyPost/v2 NodejsClient/${pkgVersion} Nodejs/${nodeVersion} OS/${osName} OSVersion/${osVersion} OSArch/${osArch}`; } /** * Attach services to an {@link EasyPostClient} instance. * @param {Map} services - A map of {@link BaseService}-based service classes to construct and attach to the client. */ - _attachServices(services) { + _attachServices(services: Record): void { Object.keys(services).forEach((s) => { this[s] = services[s](this); }); @@ -271,7 +326,7 @@ export default class EasyPostClient { * @param {string} path - The path to build. * @returns {string} The full path to use for the HTTP request. */ - _buildPath(path = '') { + _buildPath(path = ''): string { if (path.indexOf('http') === 0) { return path; } @@ -291,7 +346,7 @@ export default class EasyPostClient { * @param {Object} response - the response from the HTTP request * @returns {Object} - the value to be passed to the responseHooks */ - _createResponseHooksValue(baseHooksValue, response) { + _createResponseHooksValue(baseHooksValue: HookValue, response: any): HookValue { return { ...baseHooksValue, httpStatus: response.status, @@ -310,7 +365,12 @@ export default class EasyPostClient { * @returns {*} The response from the HTTP request. * @throws {ApiError} If the request fails. */ - async _request(path = '', method = EasyPostClient.METHODS.GET, params = {}, headers = {}) { + async _request( + path = '', + method: string = EasyPostClient.METHODS.GET, + params: Record = {}, + headers: RequestHeaders = {}, + ): Promise { const urlPath = this._buildPath(path); const normalizedMethod = EasyPostClient._normalizeMethod(method); const requestHeaders = EasyPostClient._buildHeaders(headers); @@ -323,7 +383,7 @@ export default class EasyPostClient { if (params !== undefined) { if (isQueryMethod) { Object.entries(params).forEach(([key, value]) => { - url.searchParams.append(key, value); + url.searchParams.append(key, String(value)); }); } else { requestBody = params; @@ -344,7 +404,7 @@ export default class EasyPostClient { }, query: (queryParams = {}) => { Object.entries(queryParams).forEach(([key, value]) => { - url.searchParams.append(key, value); + url.searchParams.append(key, String(value)); }); compatibilityRequest.url = url.toString(); return compatibilityRequest; @@ -387,7 +447,7 @@ export default class EasyPostClient { middlewareResponse = middlewareRequest.send(params); } - const baseHooksValue = { + const baseHooksValue: HookValue = { method, path: middlewareRequest.url || url.toString(), requestBody: middlewareRequest._data, @@ -447,16 +507,21 @@ export default class EasyPostClient { return response; } catch (error) { - if (error.statusCode && error.body) { - const responseHooksValue = this._createResponseHooksValue(baseHooksValue, error); + const handledError = error as any; + + if (handledError.statusCode && handledError.body) { + const responseHooksValue = this._createResponseHooksValue(baseHooksValue, handledError); this.responseHooks.forEach((fn) => fn(responseHooksValue)); - throw ErrorHandler.handleApiError(error); - } else if (error.response && error.response.body) { - const responseHooksValue = this._createResponseHooksValue(baseHooksValue, error.response); + throw ErrorHandler.handleApiError(handledError); + } else if (handledError.response && handledError.response.body) { + const responseHooksValue = this._createResponseHooksValue( + baseHooksValue, + handledError.response, + ); this.responseHooks.forEach((fn) => fn(responseHooksValue)); - throw ErrorHandler.handleApiError(error.response); + throw ErrorHandler.handleApiError(handledError.response); } else { - throw error; + throw handledError; } } } @@ -468,7 +533,7 @@ export default class EasyPostClient { * @param {Object} [headers] - Additional headers to send with the request. * @returns {*} The response from the HTTP request. */ - _get(path, params = {}, headers = {}) { + _get(path: string, params: Record = {}, headers: RequestHeaders = {}): Promise { return this._request(path, EasyPostClient.METHODS.GET, params, headers); } @@ -479,7 +544,7 @@ export default class EasyPostClient { * @param {Object} [headers] - Additional headers to send with the request. * @returns {*} The response from the HTTP request. */ - _post(path, params = {}, headers = {}) { + _post(path: string, params: Record = {}, headers: RequestHeaders = {}): Promise { return this._request(path, EasyPostClient.METHODS.POST, params, headers); } @@ -490,7 +555,7 @@ export default class EasyPostClient { * @param {Object} [headers] - Additional headers to send with the request. * @returns {*} The response from the HTTP request. */ - _put(path, params = {}, headers = {}) { + _put(path: string, params: Record = {}, headers: RequestHeaders = {}): Promise { return this._request(path, EasyPostClient.METHODS.PUT, params, headers); } @@ -501,7 +566,7 @@ export default class EasyPostClient { * @param {Object} [headers] - Additional headers to send with the request. * @returns {*} The response from the HTTP request. */ - _patch(path, params = {}, headers = {}) { + _patch(path: string, params: Record = {}, headers: RequestHeaders = {}): Promise { return this._request(path, EasyPostClient.METHODS.PATCH, params, headers); } @@ -512,7 +577,7 @@ export default class EasyPostClient { * @param {Object} [headers] - Additional headers to send with the request. * @returns {*} The response from the HTTP request. */ - _delete(path, params = {}, headers = {}) { + _delete(path: string, params: Record = {}, headers: RequestHeaders = {}): Promise { return this._request(path, EasyPostClient.METHODS.DELETE, params, headers); } } diff --git a/src/utils/internal_util.ts b/src/utils/internal_util.ts index 09f27f487..99385e7d2 100644 --- a/src/utils/internal_util.ts +++ b/src/utils/internal_util.ts @@ -1,4 +1,3 @@ -// @ts-nocheck /** * Utility class of various internal helper functions. * This class is not designed to be used directly by consumers of the library. diff --git a/src/utils/util.ts b/src/utils/util.ts index 6c6be45a2..280c4f753 100644 --- a/src/utils/util.ts +++ b/src/utils/util.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import crypto from 'crypto'; import util from 'util'; @@ -7,6 +6,17 @@ import FilteringError from '../errors/general/filtering_error'; import InvalidParameterError from '../errors/general/invalid_parameter_error'; import SignatureVerificationError from '../errors/general/signature_verification_error'; +type SmartRate = { + rate: string; + time_in_transit: Record; +}; + +type Rate = { + rate: string; + carrier: string; + service: string; +}; + /** * Utility class of various publicly-available helper functions. * @public @@ -23,7 +33,11 @@ export default class Utils { * @throws {FilteringError} - If no applicable rates are found * @throws {InvalidParameterError} - If the deliveryAccuracy value is invalid */ - getLowestSmartRate(smartrates, deliveryDays, deliveryAccuracy) { + getLowestSmartRate( + smartrates: SmartRate[], + deliveryDays: number | string, + deliveryAccuracy: string, + ): SmartRate { const validDeliveryAccuracyValues = new Set([ 'percentile_50', 'percentile_75', @@ -33,13 +47,13 @@ export default class Utils { 'percentile_97', 'percentile_99', ]); - let lowestSmartRate = null; + let lowestSmartRate: SmartRate | null = null; const lowercaseDeliveryAccuracy = deliveryAccuracy.toLowerCase(); if (!validDeliveryAccuracyValues.has(lowercaseDeliveryAccuracy)) { throw new InvalidParameterError({ - message: `Invalid deliveryAccuracy value, must be one of: ${new Array( - ...validDeliveryAccuracyValues, + message: `Invalid deliveryAccuracy value, must be one of: ${Array.from( + validDeliveryAccuracyValues, ).join(', ')}`, }); } @@ -47,7 +61,9 @@ export default class Utils { for (let i = 0; i < smartrates.length; i += 1) { const rate = smartrates[i]; - if (rate.time_in_transit[lowercaseDeliveryAccuracy] > parseInt(deliveryDays, 10)) { + if ( + rate.time_in_transit[lowercaseDeliveryAccuracy] > parseInt(String(deliveryDays), 10) + ) { // eslint-disable-next-line no-continue continue; } else if ( @@ -74,7 +90,7 @@ export default class Utils { * @returns {Rate} - The lowest rate * @throws {FilteringError} - If no applicable rates are found */ - getLowestRate(rates, carriers = null, services = null) { + getLowestRate(rates: Rate[], carriers: string[] | null = null, services: string[] | null = null): Rate { if (carriers) { const carriersLower = carriers.map((carrier) => carrier.toLowerCase()); // eslint-disable-next-line no-param-reassign @@ -112,8 +128,12 @@ export default class Utils { * @returns {object} - The JSON-parsed webhook event body if the signature could be verified * @throws {SignatureVerificationError} - If the signature could not be verified */ - validateWebhook(eventBody, headers, webhookSecret) { - let webhook = {}; + validateWebhook( + eventBody: Buffer | string, + headers: Record, + webhookSecret: string, + ): Record { + let webhook: Record = {}; const easypostHmacSignature = headers['X-Hmac-Signature'] ?? headers['x-hmac-signature'] ?? null; From 4f9c892cf76b4d4ba43bf34a9aeb097bdb81cda4 Mon Sep 17 00:00:00 2001 From: Justintime50 <39606064+Justintime50@users.noreply.github.com> Date: Fri, 7 Aug 2026 14:06:09 -0600 Subject: [PATCH 3/3] chore(tsm-04): format converted TS files for lint --- src/easypost.ts | 30 +++++++++++++++++++++++++----- src/utils/util.ts | 10 ++++++---- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/easypost.ts b/src/easypost.ts index 7800c3343..40f6c9fe1 100644 --- a/src/easypost.ts +++ b/src/easypost.ts @@ -533,7 +533,11 @@ export default class EasyPostClient { * @param {Object} [headers] - Additional headers to send with the request. * @returns {*} The response from the HTTP request. */ - _get(path: string, params: Record = {}, headers: RequestHeaders = {}): Promise { + _get( + path: string, + params: Record = {}, + headers: RequestHeaders = {}, + ): Promise { return this._request(path, EasyPostClient.METHODS.GET, params, headers); } @@ -544,7 +548,11 @@ export default class EasyPostClient { * @param {Object} [headers] - Additional headers to send with the request. * @returns {*} The response from the HTTP request. */ - _post(path: string, params: Record = {}, headers: RequestHeaders = {}): Promise { + _post( + path: string, + params: Record = {}, + headers: RequestHeaders = {}, + ): Promise { return this._request(path, EasyPostClient.METHODS.POST, params, headers); } @@ -555,7 +563,11 @@ export default class EasyPostClient { * @param {Object} [headers] - Additional headers to send with the request. * @returns {*} The response from the HTTP request. */ - _put(path: string, params: Record = {}, headers: RequestHeaders = {}): Promise { + _put( + path: string, + params: Record = {}, + headers: RequestHeaders = {}, + ): Promise { return this._request(path, EasyPostClient.METHODS.PUT, params, headers); } @@ -566,7 +578,11 @@ export default class EasyPostClient { * @param {Object} [headers] - Additional headers to send with the request. * @returns {*} The response from the HTTP request. */ - _patch(path: string, params: Record = {}, headers: RequestHeaders = {}): Promise { + _patch( + path: string, + params: Record = {}, + headers: RequestHeaders = {}, + ): Promise { return this._request(path, EasyPostClient.METHODS.PATCH, params, headers); } @@ -577,7 +593,11 @@ export default class EasyPostClient { * @param {Object} [headers] - Additional headers to send with the request. * @returns {*} The response from the HTTP request. */ - _delete(path: string, params: Record = {}, headers: RequestHeaders = {}): Promise { + _delete( + path: string, + params: Record = {}, + headers: RequestHeaders = {}, + ): Promise { return this._request(path, EasyPostClient.METHODS.DELETE, params, headers); } } diff --git a/src/utils/util.ts b/src/utils/util.ts index 280c4f753..c355313cc 100644 --- a/src/utils/util.ts +++ b/src/utils/util.ts @@ -61,9 +61,7 @@ export default class Utils { for (let i = 0; i < smartrates.length; i += 1) { const rate = smartrates[i]; - if ( - rate.time_in_transit[lowercaseDeliveryAccuracy] > parseInt(String(deliveryDays), 10) - ) { + if (rate.time_in_transit[lowercaseDeliveryAccuracy] > parseInt(String(deliveryDays), 10)) { // eslint-disable-next-line no-continue continue; } else if ( @@ -90,7 +88,11 @@ export default class Utils { * @returns {Rate} - The lowest rate * @throws {FilteringError} - If no applicable rates are found */ - getLowestRate(rates: Rate[], carriers: string[] | null = null, services: string[] | null = null): Rate { + getLowestRate( + rates: Rate[], + carriers: string[] | null = null, + services: string[] | null = null, + ): Rate { if (carriers) { const carriersLower = carriers.map((carrier) => carrier.toLowerCase()); // eslint-disable-next-line no-param-reassign