export type AddressInput = { street: string; city: string; state: string; zip: string; place_id: string; formatted_address: string; selected_from_suggestions: boolean; /** MotherShip 联想候选项 ID(用户确认后必填) */ mothership_option_id?: string; /** MotherShip 下拉展示文案,RPA 精确点选 */ mothership_display_label?: string; /** 用户已从 MotherShip 多候选中确认 */ selected_from_mothership?: boolean; }; export type WeightInput = { value: number; unit: "lb" | "kg"; }; export type DimensionsInput = { length: number; width: number; height: number; unit: "in" | "cm"; }; export type QuoteRequestBody = { request_id: string; customer_id: string; pickup_address: AddressInput; delivery_address: AddressInput; weight: WeightInput; dimensions: DimensionsInput; pallet_count: number; cargo_type: string; service_level?: "standard" | "guaranteed"; rate_option?: "lowest" | "fastest"; display_unit?: "imperial" | "metric"; /** 候选 RPA 会话 ID(可选,10 分钟内有效) */ quote_session_id?: string; }; export type NormalizedCargo = { requestId: string; customerId: string; pickupAddress: AddressInput; deliveryAddress: AddressInput; weightLb: number; dimLIn: number; dimWIn: number; dimHIn: number; palletCount: number; cargoType: string; serviceLevel: "standard" | "guaranteed"; rateOption: "lowest" | "fastest"; cargoHash: string; pickupSerialized: string; deliverySerialized: string; quoteSessionId?: string; }; export type QuoteSubmitResult = { quoteId: string; status: "processing" | "done"; cached?: boolean; }; export type L2CachePayload = { quotes: Array<{ service_level: string; rate_option: string; carrier: string; transit_days: string; transit_description: string; raw_freight: number; surcharges: number; raw_total: number; }>; }; export class ValidationError extends Error { readonly code = "VALIDATION_FAILED"; constructor(message: string) { super(message); this.name = "ValidationError"; } } /** SQL 注入等安全校验失败(task-105 / TC-504) */ export class SecurityValidationError extends ValidationError { readonly isSecurity = true; constructor(message: string) { super(message); this.name = "SecurityValidationError"; } } export class QuoteIdConflictError extends Error { readonly code = "INTERNAL_ERROR"; constructor(message: string) { super(message); this.name = "QuoteIdConflictError"; } } export class RpaDataInvalidError extends Error { readonly code = "RPA_DATA_INVALID"; constructor(message: string) { super(message); this.name = "RpaDataInvalidError"; } }