universal-parcel-scraper 0.7.0-main.326 → 0.7.1-main.327

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -116,16 +116,23 @@ const AIRPORT_PLACES = {
116
116
  FRA: { name: 'Frankfurt Airport', country: 'Germany' },
117
117
  CDG: { name: 'Paris Charles de Gaulle Airport', country: 'France' },
118
118
  };
119
- function departureAirport(office) {
119
+ function officeAirport(office) {
120
120
  return /^Office - ([A-Z]{3})\b/.exec(office)?.[1];
121
121
  }
122
122
  /** Flight remarks have a narrow format; unrelated remarks can contain recipient details. */
123
- function flightDescription(remarks, office) {
123
+ function flightDetails(providerCode, remarks, office) {
124
+ if (providerCode !== TAKE_OFF_CODE && providerCode !== 'MailArrived')
125
+ return null;
124
126
  const match = /^Flight No:\s*([A-Z0-9]{2}\d{1,4}[A-Z]?)\s*\(From ([A-Z]{3}) To ([A-Z]{3})\)$/.exec(clean(remarks, 500));
125
- if (!match || match[2] !== departureAirport(office))
126
- return 'Aircraft Departure';
127
+ if (!match || match[2] !== officeAirport(office))
128
+ return null;
127
129
  const airport = (code) => AIRPORT_PLACES[code] ? `${AIRPORT_PLACES[code].name} (${code})` : code;
128
- return `Flight ${match[1]} departed: ${airport(match[2])} → ${airport(match[3])}`;
130
+ const departed = providerCode === TAKE_OFF_CODE;
131
+ // MailArrived retains the sending office. Its flight route names the arrival airport.
132
+ return {
133
+ description: `Flight ${match[1]} ${departed ? 'departed' : 'arrived'}: ${airport(match[2])} → ${airport(match[3])}`,
134
+ airport: match[departed ? 2 : 3],
135
+ };
129
136
  }
130
137
  /**
131
138
  * The zone a take-off row's clock is kept in. Its `tracked_at` is the
@@ -138,7 +145,7 @@ function flightDescription(remarks, office) {
138
145
  function takeOffZone(providerCode, office, trackedAt) {
139
146
  if (providerCode !== TAKE_OFF_CODE || !UTC_LABEL.test(trackedAt))
140
147
  return null;
141
- const airport = departureAirport(office);
148
+ const airport = officeAirport(office);
142
149
  return airport ? AIRPORT_ZONES[airport] ?? null : null;
143
150
  }
144
151
  /**
@@ -191,14 +198,15 @@ export function parseIndiaPostTrackingHtml(html, trackingNumber) {
191
198
  ? mislabeledLocalTime(rawEvent.tracked_at, zone, 100)
192
199
  : isoTime(rawEvent.tracked_at, 'Asia/Kolkata', 100);
193
200
  const takeOff = providerCode === TAKE_OFF_CODE;
194
- const description = takeOff ? flightDescription(rawEvent.remarks, office) : eventText(clean(rawEvent.event));
201
+ const flight = flightDetails(providerCode, rawEvent.remarks, office);
202
+ const description = flight?.description ?? (takeOff ? 'Aircraft Departure' : eventText(clean(rawEvent.event)));
195
203
  if (!time || !description)
196
204
  return;
197
205
  const pincode = /^\d{6}$/.test(clean(rawEvent.pincode, 6))
198
206
  ? clean(rawEvent.pincode, 6)
199
207
  : '';
200
- const point = officePoint(rawEvent, office);
201
- const airportCode = takeOff ? departureAirport(office) : undefined;
208
+ const airportCode = flight?.airport ?? (takeOff ? officeAirport(office) : undefined);
209
+ const point = airportCode ? null : officePoint(rawEvent, office);
202
210
  const airport = airportCode ? AIRPORT_PLACES[airportCode] : undefined;
203
211
  const identity = JSON.stringify([time.iso, description, office, pincode, providerCode]);
204
212
  if (seen.has(identity))
@@ -211,7 +219,8 @@ export function parseIndiaPostTrackingHtml(html, trackingNumber) {
211
219
  // deliberately never retained.
212
220
  event: {
213
221
  time: time.iso,
214
- location: airport ? `${airport.name} (${airportCode}), ${airport.country}` : [office, pincode].filter(Boolean).join(' '),
222
+ location: airport ? `${airport.name} (${airportCode}), ${airport.country}`
223
+ : flight && !takeOff ? `${flight.airport} Airport` : [office, pincode].filter(Boolean).join(' '),
215
224
  description,
216
225
  stage: classified.stage,
217
226
  ...(providerCode ? { provider_code: providerCode } : {}),
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Universal Parcel Scraper",
5
- "version": "0.7.0"
5
+ "version": "0.7.1"
6
6
  },
7
7
  "paths": {
8
8
  "/health": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-parcel-scraper",
3
- "version": "0.7.0-main.326",
3
+ "version": "0.7.1-main.327",
4
4
  "description": "Self-hosted parcel tracking: carrier detection, dedicated scrapers and optional universal providers.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",