Files
redefined-designs/backend/src/usps.ts
T
bermudalamb 9ab689e624
SonarQube Analysis / sonarqube (pull_request) Failing after 59s
Tests / backend-unit (pull_request) Successful in 34s
Tests / backend-integration (pull_request) Failing after 1m33s
Tests / frontend-e2e (pull_request) Failing after 1m5s
feat: add customer cart with expiry, shipping addresses with USPS validation, and multi-item PayPal checkout
2026-08-14 14:02:25 -05:00

83 lines
2.6 KiB
TypeScript

interface UspsToken {
accessToken: string;
expiresAt: number;
}
let cachedToken: UspsToken | null = null;
const USPS_BASE =
process.env.USPS_ENV === 'production'
? 'https://apis.usps.com'
: 'https://apis-tem.usps.com';
export function uspsConfigured(): boolean {
return !!(process.env.USPS_CLIENT_ID && process.env.USPS_CLIENT_SECRET);
}
async function getToken(): Promise<string> {
if (cachedToken && cachedToken.expiresAt > Date.now() + 60_000) {
return cachedToken.accessToken;
}
const resp = await fetch(`${USPS_BASE}/oauth2/v3/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: process.env.USPS_CLIENT_ID,
client_secret: process.env.USPS_CLIENT_SECRET,
grant_type: 'client_credentials',
scope: 'addresses'
})
});
const data = await resp.json();
if (!resp.ok) throw new Error('USPS auth failed: ' + JSON.stringify(data));
cachedToken = {
accessToken: data.access_token,
expiresAt: Date.now() + (parseInt(data.expires_in, 10) || 3000) * 1000
};
return cachedToken.accessToken;
}
export interface AddressInput {
addressLine1: string;
addressLine2?: string | null;
city: string;
state: string;
postalCode: string;
}
export interface UspsValidationResult {
validated: boolean;
deliverable: boolean | null;
standardized: Record<string, unknown> | null;
reason?: string;
}
// Only validates domestic US addresses — USPS Addresses API has no international coverage.
export async function validateAddress(address: AddressInput): Promise<UspsValidationResult> {
if (!uspsConfigured()) {
return { validated: false, deliverable: null, standardized: null, reason: 'USPS not configured' };
}
try {
const token = await getToken();
const params = new URLSearchParams({
streetAddress: address.addressLine1,
city: address.city,
state: address.state,
ZIPCode: address.postalCode
});
if (address.addressLine2) params.set('secondaryAddress', address.addressLine2);
const resp = await fetch(`${USPS_BASE}/addresses/v3/address?${params.toString()}`, {
headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' }
});
const data = await resp.json();
if (!resp.ok) {
return { validated: false, deliverable: null, standardized: null, reason: data.error?.message || 'USPS lookup failed' };
}
const deliverable = data.additionalInfo?.DPVConfirmation === 'Y';
return { validated: true, deliverable, standardized: data };
} catch (err) {
return { validated: false, deliverable: null, standardized: null, reason: (err as Error).message };
}
}