/** * ONE (Ocean Network Express) Connector * * Implements CarrierConnectorPort for ONE API */ import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { CarrierConnectorPort, CarrierRateSearchInput, CarrierAvailabilityInput, } from '@domain/ports/out/carrier-connector.port'; import { RateQuote } from '@domain/entities/rate-quote.entity'; import { BaseCarrierConnector, CarrierConfig } from '../base-carrier.connector'; import { ONERequestMapper } from './one.mapper'; @Injectable() export class ONEConnectorAdapter extends BaseCarrierConnector implements CarrierConnectorPort { private readonly apiUrl: string; private readonly username: string; private readonly password: string; constructor( private readonly configService: ConfigService, private readonly requestMapper: ONERequestMapper ) { const config: CarrierConfig = { name: 'ONE', code: 'ONEY', baseUrl: configService.get('ONE_API_URL', 'https://api.one-line.com/v1'), timeout: 5000, maxRetries: 3, circuitBreakerThreshold: 50, circuitBreakerTimeout: 30000, }; super(config); this.apiUrl = config.baseUrl; this.username = this.configService.get('ONE_USERNAME', ''); this.password = this.configService.get('ONE_PASSWORD', ''); } async searchRates(input: CarrierRateSearchInput): Promise { this.logger.log(`Searching ONE rates: ${input.origin} -> ${input.destination}`); try { const oneRequest = this.requestMapper.toONERequest(input); // ONE uses Basic Auth const authHeader = Buffer.from(`${this.username}:${this.password}`).toString('base64'); const response = await this.makeRequest({ url: `${this.apiUrl}/rates/instant-quotes`, method: 'POST', data: oneRequest, headers: { Authorization: `Basic ${authHeader}`, 'Content-Type': 'application/json', }, }); const rateQuotes = this.requestMapper.fromONEResponse(response.data, input); this.logger.log(`Found ${rateQuotes.length} ONE rates`); return rateQuotes; } catch (error: any) { this.logger.error(`ONE API error: ${error?.message || 'Unknown error'}`); if (error?.response?.status === 400) { this.logger.warn('ONE invalid request parameters'); } return []; } } async checkAvailability(input: CarrierAvailabilityInput): Promise { try { const authHeader = Buffer.from(`${this.username}:${this.password}`).toString('base64'); const response = await this.makeRequest({ url: `${this.apiUrl}/capacity/slots`, method: 'POST', data: { origin_port: input.origin, destination_port: input.destination, cargo_cutoff_date: input.departureDate, equipment_type: input.containerType, quantity: input.quantity, }, headers: { Authorization: `Basic ${authHeader}`, }, }); return (response.data as any).slots_available || 0; } catch (error: any) { this.logger.error(`ONE availability check error: ${error?.message || 'Unknown error'}`); return 0; } } }