1+ interface TrackingResult {
2+ trackingNumber : string ;
3+ carrier : string ;
4+ status : 'pending' | 'in_transit' | 'delivered' | 'failed' ;
5+ lastUpdate : string ;
6+ destination ?: string ;
7+ estimatedDelivery ?: string ;
8+ events ?: Array < {
9+ timestamp : string ;
10+ location : string ;
11+ status : string ;
12+ } > ;
13+ }
14+
15+ interface TrackingService {
16+ trackPackage ( trackingNumber : string , carrier : string , apiKey : string ) : Promise < TrackingResult > ;
17+ }
18+
19+ export const trackingService : TrackingService = {
20+ async trackPackage ( trackingNumber : string , carrier : string , apiKey : string ) : Promise < TrackingResult > {
21+ const normalized = trackingNumber . toUpperCase ( ) . trim ( ) ;
22+
23+ try {
24+ const response = await fetch ( 'https://api.17track.net/track/v2/trackinfo' , {
25+ method : 'POST' ,
26+ headers : {
27+ 'Content-Type' : 'application/json' ,
28+ 'Authorization' : `Bearer ${ apiKey } `
29+ } ,
30+ body : JSON . stringify ( {
31+ tracking_number : normalized ,
32+ carrier_code : this . normalizeCarrier ( carrier )
33+ } )
34+ } ) ;
35+
36+ if ( ! response . ok ) {
37+ throw new Error ( `17Track API error: ${ response . status } ` ) ;
38+ }
39+
40+ const data = await response . json ( ) ;
41+
42+ return this . formatTrackingResult ( data , normalized , carrier ) ;
43+ } catch ( error ) {
44+ console . error ( '[17Track API Error]' , error ) ;
45+ throw new Error ( 'Failed to fetch tracking information from 17Track' ) ;
46+ }
47+ } ,
48+
49+ normalizeCarrier ( carrier : string ) : string {
50+ const carrierMap : Record < string , string > = {
51+ 'UPS' : 'ups' ,
52+ 'FedEx' : 'fedex' ,
53+ 'USPS' : 'usps' ,
54+ 'DHL' : 'dhl' ,
55+ 'Amazon Logistics' : 'amazoncn' ,
56+ 'Other' : 'other'
57+ } ;
58+ return carrierMap [ carrier ] || carrier . toLowerCase ( ) ;
59+ } ,
60+
61+ formatTrackingResult ( data : any , trackingNumber : string , carrier : string ) : TrackingResult {
62+ const trackInfo = data . data ?. [ 0 ] ;
63+
64+ if ( ! trackInfo ) {
65+ throw new Error ( 'No tracking information found' ) ;
66+ }
67+
68+ const statusMap : Record < number , 'pending' | 'in_transit' | 'delivered' | 'failed' > = {
69+ 0 : 'pending' ,
70+ 1 : 'in_transit' ,
71+ 2 : 'delivered' ,
72+ 3 : 'failed' ,
73+ 4 : 'in_transit' ,
74+ 5 : 'failed'
75+ } ;
76+
77+ const events = ( trackInfo . events || [ ] ) . map ( ( event : any ) => ( {
78+ timestamp : new Date ( event . time * 1000 ) . toISOString ( ) ,
79+ location : event . location || 'Unknown' ,
80+ status : event . status_text || event . status || 'Update'
81+ } ) ) ;
82+
83+ const lastEvent = events [ events . length - 1 ] ;
84+
85+ return {
86+ trackingNumber,
87+ carrier,
88+ status : statusMap [ trackInfo . status ] || 'pending' ,
89+ lastUpdate : lastEvent ?. timestamp || new Date ( ) . toISOString ( ) ,
90+ destination : trackInfo . dest_city || undefined ,
91+ estimatedDelivery : trackInfo . estimated_delivery
92+ ? new Date ( trackInfo . estimated_delivery * 1000 ) . toISOString ( )
93+ : undefined ,
94+ events
95+ } ;
96+ }
97+ } ;
0 commit comments