universal-parcel-scraper 0.1024.1-main.5562 → 0.1024.2-main.5565

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.
@@ -47000,7 +47000,7 @@ function Au(e) {
47000
47000
  if (/^acceptance of the (?:package|parcel) at the delivery branch abroad$/.test(t)) return "in_transit";
47001
47001
  if (/^acceptance of the (?:package|parcel) at the pick ?up point$/.test(t) || /^(?:(?:the )?item )?(?:arrival|arrived|receive item) at (?:the )?collection point for pick ?up\b/.test(t)) return "ready_for_pickup";
47002
47002
  if (/^(?:package|parcel) received (?:&|and) scanned at (?:the )?carrier's domestic warehouse$/.test(t) || /^(?:the )?goods (?:arrive|arrived|have arrived) at (?:the )?receiving point$/.test(t) || /(?<!\b(?:no|nao) )\badmitid[oa]s?\b|\badmision (?:en origen|pais de origen)\b/.test(t) || /^aceite(?:\.|$)|\b(?:envio|objeto|objecto|encomenda|remessa) foi aceite\b/.test(t)) return "accepted";
47003
- if (/\bcross ?dock(?:ed|ing)?\b|\bready for outbound\b|^(?:(?:item|parcel|package|shipment) )?inbound scan(?:ned|ning)?\b|\b(?:un)?bagg(?:ed|ing)\b|\bmaster (?:air ?way ?bill|awb)(?: (?:number|no))? (?:received|assigned|allocated)\b|\bhand ?over to (?:the |an )?(?:airline|air carrier)\b|^(?:(?:the |your )?(?:item|parcel|package|shipment) )?(?:has )?left (?:the|our) warehouse$|\b(?:flight|leg)\b[^.;]*\b(?:is taking off|took off|has taken off|landed)\b|\bflight (?:take ?off|landing)\b|^(?:initial|final) landing$|\bcargo tally in the supervised warehouse\b|\bprepared for (?:the )?last[- ]mile hand ?over\b/.test(t) || /^(?:the )?noa (?:has been |was )?received$|^noa-notification of arrival\b/.test(t) || /^(?:the |your )?(?:parcel|package|shipment|item) is (?:now )?at (?:the |a )?distribution cent(?:er|re)$/.test(t) || /^l'envoi est dans le reseau de livraison local$/.test(t) || /^there (?:has|have) been (?:a |an )?(?:slight |short |small |unexpected )?delay (?:with|to|in) (?:your |the )?(?:delivery|parcel|package|shipment|order)\.?$/.test(t) || /transit|\bline ?haul\b|en route|on (?:its|the) way|\bfacility\b|airport|\bleaving\b|\bdispatched\b|^delay(?:ed)?$|received by (?:the )?(?:local )?(?:delivery|logistics) company|\btransfer to (?:the |a |an )?(?:local |destination )?(?:acting |delivery |logistics |courier )?(?:company|agent|carrier|partner)\b|received by (?:postnl|uniuni)\b|notification.*sent to the recipient|delivery option requested|instruction de livraison recue|cambio (?:delle )?disposizioni di consegna|expedie (?:depuis|du|de)\b|acheminement|unterwegs|\bin viaggio\b|\bw drodze\b|\bonderweg\b|transport|trasport|arriv|depart|processed|processing completed|processing at (?:the )?(?:origin |destination )?branch\b|\breceipt of (?:the )?(?:package|parcel|shipment) at (?:the )?dpd branch\b|sorted|sorting|\btri\b|\btriee?s?\b|traitement|traite|sortier|bearbeitet|bearbeitung|elaborat|elaborazion|smistat|parcel cent(?:er|re)|delivery cent(?:er|re)|centre.*(?:colis|distribution)|paketzentrum|verteilzentrum|centro.*(?:pacchi|distribuzione)|depot|import scan|scan.*import|importscan|scansione.*import|delivery.*delayed|livraison.*(?:retard|report)|zustellung.*verzogert|consegna.*ritard|transferred|transfere|weitergeleitet|inoltrato|left.*(?:point|center)|quitte|verlassen|raggiunto|close bag|fermeture du sac|sack.*geschlossen|chiusura.*sacco|scanned into|scanned at (?:a |the )?checkpoint|dismantling the board|scanne dans|eingescannt|scansionat|\b(?:un)?loaded\b|^(?:item|parcel|shipment) distributed$|charg.*vehicule de transport|transportfahrzeug.*geladen|caric.*veicolo.*trasporto/.test(t) || /^enviad[oa]$|\bclasificad[oa]s?\b|\bclasificacion\b|\ben ruta\b|\ben camino\b|\bcargad[oa]s? en (?:el )?vehiculo\b|\bllegad[oa]s? (?:a|al|en)\b|\bllegada (?:a|al|en|de)\b|\bha llegado\b|\bllego (?:a|al)\b|\bsalida (?:de|del|desde)\b|\b(?:ha )?salido (?:de|del)\b|\bsalio (?:de|del)\b|\ben destino\b|\b(?:agencia|delegacion|plataforma|oficina|franquicia) (?:de )?destino\b|\b(?:unidad|centro|oficina|delegacion|base|agencia|plataforma) de reparto\b|\bcentro (?:de )?(?:clasificacion|distribucion|tratamiento|logistico|operaciones|operativo)\b|\blectura\b|\bleid[oa]s?\b|\brecepcionad[oa]s?\b|\bprocesad[oa]s?\b|\bexpedid[oa]s?\b|\btriagem\b|\btriad[oa]s?\b|\bem tratamento\b|\btratad[oa]s?\b|\bcentro (?:de )?(?:distribuicao|tratamento|triagem|operacional)\b|\bchegad[ao] (?:a|ao|no|na|em)\b|\bchegou (?:a|ao|no|na|em)\b|\bsaida (?:do|da|de|dos|das)\b|\bsaiu (?:do|da|de|dos|das)\b|\bem rota\b|\ba caminho\b|\bencaminhad[oa]s?\b|\b(?:em )?transferencia\b|\btransferid[oa]s?\b|\bprocessad[oa]s?\b|\brecebid[oa] (?:no|na|em) (?:centro|armazem|unidade|plataforma)\b|\brecibid[oa] en (?:el |la |nuestr[oa] )?(?:almacen|centro|delegacion|plataforma|hub|agencia)\b/.test(t)) return "in_transit";
47003
+ if (/\bcross ?dock(?:ed|ing)?\b|\bready for outbound\b|^(?:(?:item|parcel|package|shipment) )?inbound scan(?:ned|ning)?\b|\b(?:un)?bagg(?:ed|ing)\b|\bmaster (?:air ?way ?bill|awb)(?: (?:number|no))? (?:received|assigned|allocated)\b|\bhand ?over to (?:the |an )?(?:airline|air carrier)\b|^(?:(?:the |your )?(?:item|parcel|package|shipment) )?(?:has )?left (?:the|our) warehouse$|\b(?:flight|leg)\b[^.;]*\b(?:is taking off|took off|has taken off|has left|landed)\b|\bflight (?:take ?off|landing)\b|^(?:initial|final) landing$|\bcargo tally in the supervised warehouse\b|\bprepared for (?:the )?last[- ]mile hand ?over\b/.test(t) || /^(?:the )?noa (?:has been |was )?received$|^noa-notification of arrival\b/.test(t) || /^(?:the |your )?(?:parcel|package|shipment|item) is (?:now )?at (?:the |a )?distribution cent(?:er|re)$/.test(t) || /^l'envoi est dans le reseau de livraison local$/.test(t) || /^there (?:has|have) been (?:a |an )?(?:slight |short |small |unexpected )?delay (?:with|to|in) (?:your |the )?(?:delivery|parcel|package|shipment|order)\.?$/.test(t) || /transit|\bline ?haul\b|en route|on (?:its|the) way|\bfacility\b|airport|\bleaving\b|\bdispatched\b|^delay(?:ed)?$|received by (?:the )?(?:local )?(?:delivery|logistics) company|\btransfer to (?:the |a |an )?(?:local |destination )?(?:acting |delivery |logistics |courier )?(?:company|agent|carrier|partner)\b|received by (?:postnl|uniuni)\b|notification.*sent to the recipient|delivery option requested|instruction de livraison recue|cambio (?:delle )?disposizioni di consegna|expedie (?:depuis|du|de)\b|acheminement|unterwegs|\bin viaggio\b|\bw drodze\b|\bonderweg\b|transport|trasport|arriv|depart|processed|processing completed|processing at (?:the )?(?:origin |destination )?branch\b|\breceipt of (?:the )?(?:package|parcel|shipment) at (?:the )?dpd branch\b|sorted|sorting|\btri\b|\btriee?s?\b|traitement|traite|sortier|bearbeitet|bearbeitung|elaborat|elaborazion|smistat|parcel cent(?:er|re)|delivery cent(?:er|re)|centre.*(?:colis|distribution)|paketzentrum|verteilzentrum|centro.*(?:pacchi|distribuzione)|depot|import scan|scan.*import|importscan|scansione.*import|delivery.*delayed|livraison.*(?:retard|report)|zustellung.*verzogert|consegna.*ritard|transferred|transfere|weitergeleitet|inoltrato|left.*(?:point|center)|quitte|verlassen|raggiunto|close bag|fermeture du sac|sack.*geschlossen|chiusura.*sacco|scanned into|scanned at (?:a |the )?checkpoint|dismantling the board|scanne dans|eingescannt|scansionat|\b(?:un)?loaded\b|^(?:item|parcel|shipment) distributed$|charg.*vehicule de transport|transportfahrzeug.*geladen|caric.*veicolo.*trasporto/.test(t) || /^enviad[oa]$|\bclasificad[oa]s?\b|\bclasificacion\b|\ben ruta\b|\ben camino\b|\bcargad[oa]s? en (?:el )?vehiculo\b|\bllegad[oa]s? (?:a|al|en)\b|\bllegada (?:a|al|en|de)\b|\bha llegado\b|\bllego (?:a|al)\b|\bsalida (?:de|del|desde)\b|\b(?:ha )?salido (?:de|del)\b|\bsalio (?:de|del)\b|\ben destino\b|\b(?:agencia|delegacion|plataforma|oficina|franquicia) (?:de )?destino\b|\b(?:unidad|centro|oficina|delegacion|base|agencia|plataforma) de reparto\b|\bcentro (?:de )?(?:clasificacion|distribucion|tratamiento|logistico|operaciones|operativo)\b|\blectura\b|\bleid[oa]s?\b|\brecepcionad[oa]s?\b|\bprocesad[oa]s?\b|\bexpedid[oa]s?\b|\btriagem\b|\btriad[oa]s?\b|\bem tratamento\b|\btratad[oa]s?\b|\bcentro (?:de )?(?:distribuicao|tratamento|triagem|operacional)\b|\bchegad[ao] (?:a|ao|no|na|em)\b|\bchegou (?:a|ao|no|na|em)\b|\bsaida (?:do|da|de|dos|das)\b|\bsaiu (?:do|da|de|dos|das)\b|\bem rota\b|\ba caminho\b|\bencaminhad[oa]s?\b|\b(?:em )?transferencia\b|\btransferid[oa]s?\b|\bprocessad[oa]s?\b|\brecebid[oa] (?:no|na|em) (?:centro|armazem|unidade|plataforma)\b|\brecibid[oa] en (?:el |la |nuestr[oa] )?(?:almacen|centro|delegacion|plataforma|hub|agencia)\b/.test(t)) return "in_transit";
47004
47004
  if (/^(?:приинято|принято)$/.test(t)) return "accepted";
47005
47005
  if (au.test(t)) return "in_transit";
47006
47006
  }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The zone of the recipient country's clock, which every scan shows, where iMile
3
+ * delivers on one. iMile names a country, never a state or province, so Peru's
4
+ * code is Peru's. Null for a country whose clock the scans do not say.
5
+ */
6
+ export declare function imileCountryClock(country: string): string | null;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The clock iMile's tracker shows a parcel's scans on, which other feeds relaying
3
+ * them keep (providers/ship24).
4
+ */
5
+ import { countryTimeZone } from '../../core/time/index.js';
6
+ import { countryZones } from '../../places/zones.js';
7
+ /**
8
+ * The clock of a country iMile delivers in on several. New Zealand's other zone is
9
+ * the Chatham Islands': its delivery stations keep Auckland's clock. iMile Australia
10
+ * dates every scan on Sydney's, Queensland's included: on Brisbane's clock, its
11
+ * hubs' arrivals there would come after a consumer first saw them.
12
+ */
13
+ const COUNTRY_CLOCKS = { NZ: 'Pacific/Auckland', AU: 'Australia/Sydney' };
14
+ /**
15
+ * The zone of the recipient country's clock, which every scan shows, where iMile
16
+ * delivers on one. iMile names a country, never a state or province, so Peru's
17
+ * code is Peru's. Null for a country whose clock the scans do not say.
18
+ */
19
+ export function imileCountryClock(country) {
20
+ const zones = countryZones(country);
21
+ return countryTimeZone(country) ?? (zones.length === 1 ? zones[0] : COUNTRY_CLOCKS[country] ?? null);
22
+ }
@@ -2,10 +2,10 @@ import { DateTime } from 'luxon';
2
2
  import { normalizeTrackingNumber } from '../../core/detection/index.js';
3
3
  import { IndeterminateError, InvalidInputError, NoHistoryError, NotFoundError, RateLimitedError, SchemaError } from '../../core/errors/index.js';
4
4
  import { languageStageStatus } from '../../core/status/index.js';
5
- import { calendarDay, countryTimeZone, isoTime } from '../../core/time/index.js';
5
+ import { calendarDay, isoTime } from '../../core/time/index.js';
6
6
  import { clean } from '../../core/transport/index.js';
7
7
  import { isRecord } from '../../core/types.js';
8
- import { countryZones } from '../../places/zones.js';
8
+ import { imileCountryClock } from './clock.js';
9
9
  import { imileStage } from './status.js';
10
10
  import { imileDisplayWording } from './wording.js';
11
11
  export const PROVIDER = 'iMile';
@@ -29,16 +29,6 @@ const COUNTRIES = {
29
29
  HND: 'HN', HUN: 'HU', ITA: 'IT', KWT: 'KW', LBN: 'LB', MEX: 'MX', NZL: 'NZ', MKD: 'MK', OMN: 'OM', PER: 'PE',
30
30
  POL: 'PL', QAT: 'QA', KSA: 'SA', SRB: 'RS', SVK: 'SK', RSA: 'ZA', ESP: 'ES', TUR: 'TR', UAE: 'AE', GBR: 'GB', USA: 'US',
31
31
  };
32
- // New Zealand's other zone is the Chatham Islands': its delivery stations keep Auckland's clock.
33
- const MAINLAND_ZONES = { NZ: 'Pacific/Auckland' };
34
- /**
35
- * The zone of the recipient country's clock, where iMile delivers on one. iMile
36
- * names a country, never a state or province, so Peru's code is Peru's.
37
- */
38
- function countryClock(country) {
39
- const zones = countryZones(country);
40
- return countryTimeZone(country) ?? (zones.length === 1 ? zones[0] : MAINLAND_ZONES[country] ?? null);
41
- }
42
32
  /** A number for iMile's tracker, in upper case; anything else is not one it answers. */
43
33
  export function normalizeImileNumber(raw) {
44
34
  const number = raw.length <= 64 ? normalizeTrackingNumber(raw).toUpperCase() : '';
@@ -175,7 +165,7 @@ export function parseImile(payload, raw) {
175
165
  const country = Object.hasOwn(COUNTRIES, code) ? COUNTRIES[code] : undefined;
176
166
  // Every scan shows the recipient country's clock: a country of one zone
177
167
  // places them all, and one of several leaves them local.
178
- const zone = country ? countryClock(country) : null;
168
+ const zone = country ? imileCountryClock(country) : null;
179
169
  const placed = zone ? newestFirst.map(({ local_time, ...event }) => {
180
170
  const time = isoTime(local_time, zone)?.iso;
181
171
  return time ? { time, ...event } : { local_time, ...event };
@@ -748,13 +748,13 @@ export function trackingLanguageStage(description) {
748
748
  // Accepted by CTT: its "Aceite" state, and "O envio foi aceite" in its scans. A return request accepted is no parcel.
749
749
  if (/^aceite(?:\.|$)|\b(?:envio|objeto|objecto|encomenda|remessa) foi aceite\b/.test(text))
750
750
  return 'accepted';
751
- // A cross-dock transfer, a flight taking off or landing, a tally in a bonded
751
+ // A cross-dock transfer, a flight taking off, gone or landing, a tally in a bonded
752
752
  // warehouse, a hand-over to the last mile being prepared or to an airline, a
753
753
  // parcel bagged, unbagged or consolidated onto a master air waybill, a parcel
754
754
  // ready for a facility's outbound dispatch or leaving a warehouse, and a
755
755
  // forwarder's inbound scan at a facility, which may follow in brackets, move
756
756
  // the parcel on.
757
- if (/\bcross ?dock(?:ed|ing)?\b|\bready for outbound\b|^(?:(?:item|parcel|package|shipment) )?inbound scan(?:ned|ning)?\b|\b(?:un)?bagg(?:ed|ing)\b|\bmaster (?:air ?way ?bill|awb)(?: (?:number|no))? (?:received|assigned|allocated)\b|\bhand ?over to (?:the |an )?(?:airline|air carrier)\b|^(?:(?:the |your )?(?:item|parcel|package|shipment) )?(?:has )?left (?:the|our) warehouse$|\b(?:flight|leg)\b[^.;]*\b(?:is taking off|took off|has taken off|landed)\b|\bflight (?:take ?off|landing)\b|^(?:initial|final) landing$|\bcargo tally in the supervised warehouse\b|\bprepared for (?:the )?last[- ]mile hand ?over\b/.test(text))
757
+ if (/\bcross ?dock(?:ed|ing)?\b|\bready for outbound\b|^(?:(?:item|parcel|package|shipment) )?inbound scan(?:ned|ning)?\b|\b(?:un)?bagg(?:ed|ing)\b|\bmaster (?:air ?way ?bill|awb)(?: (?:number|no))? (?:received|assigned|allocated)\b|\bhand ?over to (?:the |an )?(?:airline|air carrier)\b|^(?:(?:the |your )?(?:item|parcel|package|shipment) )?(?:has )?left (?:the|our) warehouse$|\b(?:flight|leg)\b[^.;]*\b(?:is taking off|took off|has taken off|has left|landed)\b|\bflight (?:take ?off|landing)\b|^(?:initial|final) landing$|\bcargo tally in the supervised warehouse\b|\bprepared for (?:the )?last[- ]mile hand ?over\b/.test(text))
758
758
  return 'in_transit';
759
759
  // The airline's notice of arrival (NOA) reaching the destination agent, after the landing and
760
760
  // before clearance, as Shouwu, JRT and the ground handlers word it.
@@ -29,6 +29,7 @@ import { DHLINK_RECORD_ZONE, usClockCopy } from '../../carriers/dhlink/clock.js'
29
29
  import { epostGlobalCopyZone } from '../../carriers/epost-global/status.js';
30
30
  import { FIRST_LINE_CHINA_ZONE, firstLineInChina } from '../../carriers/first-line/clock.js';
31
31
  import { hrvatskaPostaForeignZone } from '../../carriers/hrvatska-posta/parser.js';
32
+ import { imileCountryClock } from '../../carriers/imile/clock.js';
32
33
  import { jsExpressChinaClock } from '../../carriers/js-express/clock.js';
33
34
  import { pitneyBowesPlatformClock, pitneyBowesPostalRelay } from '../../carriers/pitney-bowes/clock.js';
34
35
  import { pocztaPolskaPartnerClock } from '../../carriers/poczta-polska/clock.js';
@@ -1033,8 +1034,10 @@ function carrierClock(payload, state, number, status = '', destination = null) {
1033
1034
  return null;
1034
1035
  if (key === 'sunyousytrack' && SUNYOU_DESTINATION_LEG.test(status.trim()))
1035
1036
  return countryTimeZone(destination) ?? undefined;
1036
- if (carrier === 'imile')
1037
- return IMILE_FORWARDER_COPY.test(status.trim()) ? 'Asia/Shanghai' : countryTimeZone(destination);
1037
+ if (carrier === 'imile') {
1038
+ const country = countryCode(destination);
1039
+ return IMILE_FORWARDER_COPY.test(status.trim()) ? 'Asia/Shanghai' : country ? imileCountryClock(country) : null;
1040
+ }
1038
1041
  if (carrier === 'mailamericas' && MAILAMERICAS_DESTINATION_CUSTOMS.test(status.trim())) {
1039
1042
  return MAILAMERICAS_DESTINATION_ZONES[countryCode(destination) ?? ''] ?? undefined;
1040
1043
  }
@@ -23,6 +23,7 @@ import { correosOriginZone } from '../../carriers/correos-spain/clock.js';
23
23
  import { seventeenFeiaCopyZone } from '../../carriers/17feia/clock.js';
24
24
  import { cttSiteZone, portugalZone } from '../../carriers/ctt/clock.js';
25
25
  import { gofoScanZone } from '../../carriers/gofo/clock.js';
26
+ import { imileCountryClock } from '../../carriers/imile/clock.js';
26
27
  import { swissPostDestinationZone } from '../../carriers/swiss-post/clock.js';
27
28
  import { trackingPlace } from '../../places/trackingLocation.js';
28
29
  import { courierZone, universalCarrierHints } from '../shared/hints.js';
@@ -141,6 +142,8 @@ const RELABELLED_FEEDS = {
141
142
  '4px-tracking': { shift: 'Asia/Shanghai' },
142
143
  // A status is 17FEIA's words, then its label or "OTHER".
143
144
  'feia-tracking': { place: (location, _journey, status) => seventeenFeiaCopyZone(status.replace(/,\s*[^,]*$/, ''), location), walls: true },
145
+ // A country of several clocks keeps its wall clocks, as iMile's adapter does, not iMile's Dubai clock.
146
+ 'imile-tracking': { clock: (journey) => journey.destination ? imileCountryClock(journey.destination) : null, walls: true },
144
147
  };
145
148
  function feedOf(scan) {
146
149
  const code = isRecord(scan.courier) ? scan.courier.crawler_code : null;
@@ -378,7 +381,7 @@ export function parseShip24Response(payload, trackingNumber, timezone = null, no
378
381
  const unnamed = feed || (forwarding && isRecord(raw.courier) && raw.courier.crawler_code === 'mainfreight-tracking');
379
382
  // Correos's copy of an origin post's scan takes that post's clock, or keeps its wall clock.
380
383
  const sent = wall ? correosOriginCopy(raw, journey) : undefined;
381
- const placed = !wall ? null : carrierZone(relayed)
384
+ const placed = !wall ? null : carrierZone(relayed) ?? carrierZone(feed?.clock?.(journey))
382
385
  ?? (sent !== undefined ? carrierZone(sent) : placedZone(journey, raw, wall, feed) ?? (unnamed ? null : carrierZone(namedZone(journey, wall))));
383
386
  readings.push({ event: parsed, wall, feed, country: feed?.country ?? locationCountry(raw.location), zone: placed?.zone ?? null, basis: placed?.basis });
384
387
  }
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Universal Parcel Scraper",
5
- "version": "0.1024.1-main.5562"
5
+ "version": "0.1024.2-main.5565"
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.1024.1-main.5562",
3
+ "version": "0.1024.2-main.5565",
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",