import fp from 'fastify-plugin'; const TRACKER_URL = process.env.TRACKER_URL || 'http://delivery-tracker:4000/'; // delivery-tracker의 carrier ID는 kr. 접두사 필요 const CARRIER_ID_MAP = { cjlogistics: 'kr.cjlogistics', hanjin: 'kr.hanjin', lotte: 'kr.lotte', epost: 'kr.epost', logen: 'kr.logen', }; const TRACK_QUERY = ` query Track($carrierId: ID!, $trackingNumber: String!) { track(carrierId: $carrierId, trackingNumber: $trackingNumber) { trackingNumber lastEvent { status { code name } time location { name } description } events(last: 100) { edges { node { status { code name } time location { name } description } } } } } `; async function trackerPlugin(fastify) { const tracker = { async track(carrierId, trackingNumber) { const graphqlCarrierId = CARRIER_ID_MAP[carrierId] || `kr.${carrierId}`; const res = await fetch(TRACKER_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: TRACK_QUERY, variables: { carrierId: graphqlCarrierId, trackingNumber, }, }), }); const json = await res.json(); if (json.errors) { const msg = json.errors[0]?.message || 'tracking failed'; throw new Error(msg); } const trackInfo = json.data?.track; if (!trackInfo) { return null; } // 이벤트 정리 const events = (trackInfo.events?.edges || []).map((edge) => { const node = edge.node; return { status: node.status?.code || 'UNKNOWN', statusName: node.status?.name || '', description: node.description || '', location: node.location?.name || '', time: node.time || null, }; }); // 마지막 이벤트 const lastEvent = trackInfo.lastEvent ? { status: trackInfo.lastEvent.status?.code || 'UNKNOWN', statusName: trackInfo.lastEvent.status?.name || '', description: trackInfo.lastEvent.description || '', location: trackInfo.lastEvent.location?.name || '', time: trackInfo.lastEvent.time || null, } : null; return { trackingNumber: trackInfo.trackingNumber, lastEvent, events, }; }, }; fastify.decorate('tracker', tracker); } export default fp(trackerPlugin, { name: 'tracker' });