universal-parcel-scraper 0.802.1-main.4309 → 0.802.2-main.4316
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.
- package/README.md +1 -1
- package/dist/browser/scraper.js +4 -4
- package/dist/carriers/china-post/status.js +2 -0
- package/dist/carriers/china-post/statuses.json +9 -0
- package/dist/carriers/elta/status.js +5 -0
- package/dist/carriers/elta/statuses.json +3 -0
- package/dist/carriers/spring-gds/status.js +3 -1
- package/dist/carriers/spring-gds/statuses.json +8 -0
- package/dist/carriers/wanbexpress/status.js +1 -1
- package/dist/carriers/wanbexpress/statuses.json +7 -0
- package/dist/core/status/language.js +12 -8
- package/dist/providers/parcelsapp/adapter.js +1 -13
- package/dist/providers/shared/china.d.ts +2 -0
- package/dist/providers/shared/china.js +13 -0
- package/dist/providers/shared/result.d.ts +1 -1
- package/dist/providers/shared/result.js +22 -2
- package/dist/server/openapi.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -161,7 +161,7 @@ the command line's `track --source ParcelsApp` does the same.
|
|
|
161
161
|
<!-- GENERATED:stages -->
|
|
162
162
|
<img src="docs/assets/stages.svg" alt="DHL: Die Sendung wurde in das Zustellfahrzeug geladen.; Mondial Relay: En cours de livraison; Correios Brazil: Objeto saiu para entrega ao destinatário; Correos Express: EN REPARTO; Yamato Transport: 配達中; La Poste / Colissimo: DISTOU. All are filed under out_for_delivery." width="760">
|
|
163
163
|
|
|
164
|
-
The carrier folders record 17,
|
|
164
|
+
The carrier folders record 17,602 such statuses, each filed under one stage.
|
|
165
165
|
<!-- /GENERATED:stages -->
|
|
166
166
|
|
|
167
167
|
Wording nobody recorded yet goes through a classifier that reads seven European languages.
|
package/dist/browser/scraper.js
CHANGED
|
@@ -32348,7 +32348,7 @@ function Ml(e) {
|
|
|
32348
32348
|
if (/will be transported|\barrange (?:a )?(?:truck|train|rail|road) transfer\b|sera (?:transporte|achemine)|wird.*transportiert|sara trasportat/.test(t) || /will be available|sera disponible|(?:sera|va etre|doit etre) (?:distribue|remis|mis en (?:livraison|distribution))|wird.*verfugbar|sara disponibile|to be delivered|a livrer|noch zuzustellen|da consegnare|(?:once|when|as soon as) (?:the |your )?(?:shipment|parcel|package|item) is out for delivery/.test(t) || /\bestara disponi(?:ble|vel)\b|\bpor entregar\b|\bpendiente de (?:entrega|entregar|reparto)\b|\bpendente de entrega\b|\b(?:aguarda|aguardando|a aguardar) (?:a )?entrega\b|\bsera (?:enviad|transportad|expedid|encaminhad)[oa]s?\b/.test(t)) return "in_transit";
|
|
32349
32349
|
if (/\border (?:details|information|info|data) (?:(?:has|have) been |was |were )?received\b(?:[^.;]*)\bready (?:for|to be) (?:pick ?up|picked up|collect)/.test(t)) return "registered";
|
|
32350
32350
|
if (/ready for (?:pick ?up|collection)|ready to collect|ready to be (?:picked up|collected)\b(?! (?:by|from) (?:the |a |an |our |your )?(?:courier|carrier|driver|sender|shipper|seller|merchant|warehouse)\b)|available for (?:pick ?up|collection)|(?<!\bnot (?:yet )?)\bavailable (?:at|in|from) (?:the |a |an |your |our )?(?:[\w-]+ )?(?:retrieval point|pick ?up (?:point|location|station)|parcel ?shop|service ?point|access point|collection point|relay point|parcel locker)\b|\bwaiting for you (?:at|in) (?:the |a |an |your )?(?:[\w-]+ )?(?:collection point|pick ?up (?:point|location|station)|parcel ?shop|service ?point|access point|relay point|parcel locker|locker|post office)\b|awaiting (?:customer |recipient |your )?(?:pick ?up|collection)\b(?! (?:by|from) (?:the |a |an |our |your )?(?:local |destination |last[- ]mile )?(?:courier|carrier|driver|sender|shipper|seller|merchant|warehouse)\b)|pret.*(?:retrait|retire)|disponible.*(?:retrait|collecte)|vous attend (?:au|en|dans|chez|a)\b|mise? a disposition (?:au|en|dans|a)\b.*(?:point (?:de )?retrait|relais|consigne|locker|bureau de poste|agence)|jours? restants? pour (?:le )?retirer|abholbereit|zur abholung bereit|pront[oa] per il ritiro|disponibile per il ritiro|(?:deposited|depose|hinterlegt|depositat[oa]).*mypost24/.test(t) || /(?<!\b(?:no|nao|ya no|ja nao) (?:(?:esta|estara|se encuentra|se encontra|e|era|foi) )?)\bdisponi(?:ble|vel) (?:para (?:su |ser )?(?:recoger|recogida|recogid[oa]|retirar|retiro|retirada|retirad[oa]|levantamento|levantar|levantad[oa]|recolha|recolher)|(?:en|no|na|num|numa|em) (?:el |la |un |una |su |tu |nuestr[oa] )?(?:punto|oficina|tienda|locker|taquilla|consigna|citypaq|parcel ?shop|buzon inteligente|agencia|delegacion|sucursal|ponto|loja|cacifo|estacao|balcao|payshop|posto|unidade))\b|\blist[oa] para (?:su |ser )?(?:recoger|recogida|recogid[oa]|retirar|retiro)\b|\bpront[oa] (?:para|a) (?:ser )?(?:levantamento|levantar|levantad[oa]|recolha|recolher|retirada|retirar)\b|\b(?:ya )?(?:puede|puedes|podra|podras) (?:pasar a )?recoger(?:lo|la)?\b|\b(?:aguarda|aguardando|a aguardar) (?:o |a )?(?:levantamento|retirada)\b|\besperando (?:su|tu) recogida\b|\b(?:pendiente de|esperando|a la espera de) (?:ser )?recogid[oa] por (?:el |la )?destinatari[oa]\b/.test(t)) return "ready_for_pickup";
|
|
32351
|
-
if (/label (?:created|printed)|(?:created|generated) a (?:new )?(?:shipment |shipping )?label|etiquette.*(?:cree|imprime)|cree une etiquette|versandetikett.*(?:erstellt|gedruckt)|etikett erstellt|etichetta.*(?:creata|stampata)|creato un'etichetta|elektronisch|electroni(?:c|que|sch)|elettronic|pre.?advi[cs]|preannunciat|vorangemeldet|preannonce|data.*entered|donnees.*saisies|daten.*erfasst|dati.*inseriti|\bpre ?(?:registered|registration|registr?ad[oa]s?|registrat[oa]|enregistree?s?)\b|\bprerregistr(?:ad[oa]s?|o)\b|\bvorregistriert\b|\bwstepnie zarejestrowan[aey]\b/.test(t) || /\border (?:details|information|info|data) (?:(?:has|have) been |was |were )?(?:received|submitted|transmitted)\b|\breceived (?:your |the )?order (?:details|information|data)\b|\b(?:details|informations|donnees) de (?:la |votre )?commande (?:ont ete )?(?:recu|transmis)e?s?\b|\b(?:auftrags|bestell)daten (?:wurden |sind )?(?:erhalten|ubermittelt|eingegangen)\b|\b(?:dati|dettagli) (?:dell'ordine|ordine) (?:sono stati )?ricevuti\b|\b(?:datos|detalles|informacion) del pedido (?:han sido |fueron )?recibid[oa]s?\b|\b(?:dados|detalhes|informacoes?) d[oa] (?:pedido|encomenda) (?:foram )?recebid[oa]s?\b|\bdane zamowienia (?:zostaly )?(?:otrzymane|przyjete)\b|\botrzymano dane zamowienia\b/.test(t) || /shipment information (?:received|sent to)|\binformation about the (?:shipment|parcel|package) (?:has been |was )?received\b|\bdata received\b|^transferred data$|(?:package|parcel|shipment) data (?:was |has been )?sent to|\bpre ?notification\b|informations d'expedition recues|sendungsinformationen erhalten|informazioni.*spedizione ricevute|(?:consignment|shipment|parcel|package) recorded by|envoi enregistre par|sendung.*absender.*erfasst|spedizione registrata dal/.test(t) || /\b(?:we're|we are) expecting (?:your|the) (?:parcel|package|item|shipment) to arrive with us\b/.test(t) || /\bcreated by the sender\b.*\bwaiting for it to be (?:entrusted|handed(?: over)?) to us\b/.test(t) || /^pre[ -]?alerted (?:shipment|parcel|package|item|consignment)\b|^(?:the |your )?(?:shipment|parcel|package|item|consignment) (?:(?:has been|was|is) )?pre[ -]?alerted$/.test(t) || /^expected from (?!\d{1,2}(?:[:.h]\d{2})?\s*(?:am|pm)?\b|(?:today|tomorrow|(?:mon|tues|wednes|thurs|fri|satur|sun)day)\b)\S/.test(t) || /\bletrejott a rendszerunkben\b.*\bfelado meg nem adta at\b/.test(t) || /preparation chez.*expediteur|preparation.*expediteur|preparazione.*mittente|being prepared.*sender|(?:shipper|sender)(?: that)? (?:they are|is|are) preparing|beim absender.*vorbereitet|warehouse of the sender|shippers warehouse|entrepot de l'expediteur|lager des absenders|magazzino del mittente|demande d'envoi.*prise en compte|collection request.*(?:received|recorded)|^(?:the |your )?collection (?:has been |was )?registered$|abholauftrag.*erfasst|richiesta.*ritiro.*registrata/.test(t) || /\border submitted(?:,| and)? pending (?:to )?rece(?:iv|ipt)|\bshipment data uploaded\b|^sender preparing item\b|^sender (?:has despatched|despatching) item$|^shipping info(?:rmation)? sent to (?!(?:the |your? )?(?:recipient|customer|consignee|addressee|buyer)\b)|\bwe have received your shipment information\b|\bhemos recibido la informacion de su envio\b|\bwe will pick up (?:the|your) (?:package|parcel) from the sender\b|^booked for collection$|\bpending shipping by (?:the )?(?:seller|sender|shipper|merchant)\b|\
|
|
32351
|
+
if (/label (?:created|printed)|(?:created|generated) a (?:new )?(?:shipment |shipping )?label|etiquette.*(?:cree|imprime)|cree une etiquette|versandetikett.*(?:erstellt|gedruckt)|etikett erstellt|etichetta.*(?:creata|stampata)|creato un'etichetta|elektronisch|electroni(?:c|que|sch)|elettronic|pre.?advi[cs]|preannunciat|vorangemeldet|preannonce|data.*entered|donnees.*saisies|daten.*erfasst|dati.*inseriti|\bpre ?(?:registered|registration|registr?ad[oa]s?|registrat[oa]|enregistree?s?)\b|\bprerregistr(?:ad[oa]s?|o)\b|\bvorregistriert\b|\bwstepnie zarejestrowan[aey]\b/.test(t) || /\border (?:details|information|info|data) (?:(?:has|have) been |was |were )?(?:received|submitted|transmitted)\b|\breceived (?:your |the )?order (?:details|information|data)\b|\b(?:details|informations|donnees) de (?:la |votre )?commande (?:ont ete )?(?:recu|transmis)e?s?\b|\b(?:auftrags|bestell)daten (?:wurden |sind )?(?:erhalten|ubermittelt|eingegangen)\b|\b(?:dati|dettagli) (?:dell'ordine|ordine) (?:sono stati )?ricevuti\b|\b(?:datos|detalles|informacion) del pedido (?:han sido |fueron )?recibid[oa]s?\b|\b(?:dados|detalhes|informacoes?) d[oa] (?:pedido|encomenda) (?:foram )?recebid[oa]s?\b|\bdane zamowienia (?:zostaly )?(?:otrzymane|przyjete)\b|\botrzymano dane zamowienia\b/.test(t) || /shipment information (?:received|sent to)|\binformation about the (?:shipment|parcel|package) (?:has been |was )?received\b|\bdata received\b|^transferred data$|(?:package|parcel|shipment) data (?:was |has been )?sent to|\bpre ?notification\b|informations d'expedition recues|sendungsinformationen erhalten|informazioni.*spedizione ricevute|(?:consignment|shipment|parcel|package) recorded by|envoi enregistre par|sendung.*absender.*erfasst|spedizione registrata dal/.test(t) || /\b(?:we're|we are) expecting (?:your|the) (?:parcel|package|item|shipment) to arrive with us\b/.test(t) || /\bcreated by the sender\b.*\bwaiting for it to be (?:entrusted|handed(?: over)?) to us\b/.test(t) || /^pre[ -]?alerted (?:shipment|parcel|package|item|consignment)\b|^(?:the |your )?(?:shipment|parcel|package|item|consignment) (?:(?:has been|was|is) )?pre[ -]?alerted$/.test(t) || /^expected from (?!\d{1,2}(?:[:.h]\d{2})?\s*(?:am|pm)?\b|(?:today|tomorrow|(?:mon|tues|wednes|thurs|fri|satur|sun)day)\b)\S/.test(t) || /\bletrejott a rendszerunkben\b.*\bfelado meg nem adta at\b/.test(t) || /preparation chez.*expediteur|preparation.*expediteur|preparazione.*mittente|being prepared.*sender|(?:shipper|sender)(?: that)? (?:they are|is|are) preparing|beim absender.*vorbereitet|warehouse of the sender|shippers warehouse|entrepot de l'expediteur|lager des absenders|magazzino del mittente|demande d'envoi.*prise en compte|collection request.*(?:received|recorded)|^(?:the |your )?collection (?:has been |was )?registered$|abholauftrag.*erfasst|richiesta.*ritiro.*registrata/.test(t) || /\border submitted(?:,| and)? pending (?:to )?rece(?:iv|ipt)|\bshipment data uploaded\b|^sender preparing item\b|^sender (?:has despatched|despatching) item$|^shipping info(?:rmation)? sent to (?!(?:the |your? )?(?:recipient|customer|consignee|addressee|buyer)\b)|\bwe have received your shipment information\b|\bhemos recibido la informacion de su envio\b|\bwe will pick up (?:the|your) (?:package|parcel) from the sender\b|^booked for collection$|\bpending shipping by (?:the )?(?:seller|sender|shipper|merchant)\b|\bship(?:ment|ping) order created\b/.test(t) || /^forecast has been received$/.test(t)) return "registered";
|
|
32352
32352
|
if (!/\b(?:at|in|by) (?:the )?(?:destination|delivery|recipient|consignee|addressee|customer|customs|office of exchange)\b/.test(t)) {
|
|
32353
32353
|
let e = t.replace(sl, " ");
|
|
32354
32354
|
if (e !== t) return Ml(e.replace(/^[\s,;:.!?]+|[\s,;:]+$/g, "")) ?? (fl.test(t) ? !pl.test(t) && ml.test(t) ? "in_transit" : "customs" : "registered");
|
|
@@ -32368,9 +32368,9 @@ function Ml(e) {
|
|
|
32368
32368
|
if (/^parcel stored by (?:the )?customer$/.test(t)) return "accepted";
|
|
32369
32369
|
if (/^scan out hub$/.test(t)) return "in_transit";
|
|
32370
32370
|
if (/^attempted but unfinished drop[- ]?off at (?:the |a )?locker$/.test(t)) return "registered";
|
|
32371
|
-
if (/^(?:(?:the |your )?(?:item|parcel|package|shipment) )?(?:(?:has been|was) )?received by (?:the |a |our )?partner carrier
|
|
32371
|
+
if (/^(?:(?:the |your )?(?:item|parcel|package|shipment) )?(?:(?:has been|was) )?received by (?:the |a |our )?partner carrier$|^(?:(?:the |your )?(?:item|parcel|package|shipment) )?received by in [a-z]{3}\d{2}\.?$/.test(t)) return "in_transit";
|
|
32372
32372
|
if (/^operation cent(?:er|re) is processing (?:the )?(?:package|parcel|shipment) information$/.test(t)) return "registered";
|
|
32373
|
-
if (/^preparing to leave (?:the )?(?:[a-z]+ ){0,3}operation cent(?:er|re)$/.test(t)) return "in_transit";
|
|
32373
|
+
if (/^(?:preparing to leave|(?:the )?goods leav(?:e|ing)) (?:the )?(?:[a-z]+ ){0,3}operation cent(?:er|re)$/.test(t)) return "in_transit";
|
|
32374
32374
|
if (/^(?:the )?item is ready for shipment$/.test(t)) return "registered";
|
|
32375
32375
|
if (/^consignment received at (?:the )?postnl acceptance cent(?:re|er)$/.test(t)) return "accepted";
|
|
32376
32376
|
if (/^shipment expected,? but not yet arrived or processed at postnl$/.test(t)) return "registered";
|
|
@@ -32380,7 +32380,7 @@ function Ml(e) {
|
|
|
32380
32380
|
if (/^(?:received in office|export to foreign provider)$/.test(t) || /^(?:(?:the )?(?:shipment|parcel|package|item) )?(?:(?:has been|was) )?(?:sent|dispatched|forwarded) abroad$/.test(t) || /^sending (?:the )?(?:package|parcel|item|shipment) from (?!.*\b(?:point|locker|shop|sender|branch)\b)[a-z][a-z .'-]{1,40}$/.test(t)) return "in_transit";
|
|
32381
32381
|
if (/^(?:posting\/collection|posted|origin scan)$|received at (?:our |the )?(?:[a-z]+ )?origin (?:office|facility|hub)|dropped off (?:after|before) (?:the )?latest drop ?off time/.test(t)) return "accepted";
|
|
32382
32382
|
if (/(?:\b(?:not|never)|n't)(?: (?:be|been|being))? accepted\b/.test(t)) return "exception";
|
|
32383
|
-
if (/accepted|picked up|pick up was successful|^drop off$|pick ?up scan|prepared the package for return to ups or pickup by ups|handed (?:over )?to (?:dpd|gls)|package received at dhl|item booked|consignment was mailed|posted at a postal point|pris en charge|prise en charge|collecte.*(?:reussi|effectue)|recupere.*boite aux lettres|depose.*point postal|remis a (?:dpd|gls)|envoi.*depose|abholung.*erfolgreich|^(?:die sendung wurde )?erfolgreich abgeholt$|eingeliefert|an (?:dpd|gls) ubergeben|paket.*(?:angenommen|ubernommen)|ritiro.*(?:riuscito|effettuato)|pres[oa] in carico|affidat[oa] a (?:dpd|gls)|depositat.*punto postale|spedizione.*impostata/.test(t) ||
|
|
32383
|
+
if (/accepted|picked up|pick up was successful|^drop off$|pick ?up scan|prepared the package for return to ups or pickup by ups|handed (?:over )?to (?:dpd|gls)|package received at dhl|item booked|consignment was mailed|posted at a postal point|pris en charge|prise en charge|collecte.*(?:reussi|effectue)|recupere.*boite aux lettres|depose.*point postal|remis a (?:dpd|gls)|envoi.*depose|abholung.*erfolgreich|^(?:die sendung wurde )?erfolgreich abgeholt$|eingeliefert|an (?:dpd|gls) ubergeben|paket.*(?:angenommen|ubernommen)|ritiro.*(?:riuscito|effettuato)|pres[oa] in carico|affidat[oa] a (?:dpd|gls)|depositat.*punto postale|spedizione.*impostata/.test(t) || /^到达收货点|^item received by royal mail$|\btaken over by one of our operators\b|\bwe've received your (?:parcel|package|item) at the parcel ?shop\b|^(?:(?:the |your )?(?:item|parcel|package|shipment) )?(?:was|has been) dropped off at (?:the |a )?parcel ?shop$|^(?![^,]*\b(?:recipient|consignee|receiver|customer|addressee|buyer|pick ?up point|parcel ?shop|locker|destination)\b)[a-z][\w&' -]{0,40} has received the goods(?:, [^,]{1,40}){0,2}\.?$|^the shipment has been deposited at a seur pickup point$|^(?:the |your )?collection (?:has been |was )?(?:carried out|completed)$|^已入库|^(?:(?:the |your )?(?:item|parcel|package|shipment) )?(?:has been |was )?put into storage$/.test(t) || /^sender advised item dropped off at parcel locker$|^dropped off at postbox$/.test(t) || /^(?:the )?shipment has been taken over at the post (?:office|locker) point$/.test(t) || /^spedizione affidata a una fedex location\b/.test(t) || /^die sendung wurde vom absender (?:im|in der|in einem|in einer) (?:[\w-]+ )?(?:paketshop|parcelshop|filiale)\b(?!.*\bnicht\b).*\babgegeben$/.test(t) || /^(?:the |your )?(?:package|parcel|shipment) (?:was|has been) dropped off by the sender at (?:the |a )?(?:hermes )?(?:paketshop|parcel ?shop)\b/.test(t) || /^sending the (?:package|parcel) at the pick ?up point$|^handing over the (?:package|parcel) to the courier$/.test(t)) return "accepted";
|
|
32384
32384
|
if (/^acceptance of the (?:package|parcel) at the delivery branch abroad$/.test(t)) return "in_transit";
|
|
32385
32385
|
if (/^acceptance of the (?:package|parcel) at the pick ?up point$/.test(t)) return "ready_for_pickup";
|
|
32386
32386
|
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";
|
|
@@ -65,6 +65,8 @@ const STATES = {
|
|
|
65
65
|
'待取件': { status: 'in_transit', stage: 'ready_for_pickup' },
|
|
66
66
|
'已签收': DELIVERED,
|
|
67
67
|
'派件异常': EXCEPTION,
|
|
68
|
+
// The web preview's label for a failed delivery, which the relayed feeds give as 投递失败.
|
|
69
|
+
'派送异常': { status: 'exception', stage: 'failed_attempt' },
|
|
68
70
|
'邮件异常': EXCEPTION,
|
|
69
71
|
'退回寄件人': RETURNED,
|
|
70
72
|
'待退回': RETURNED,
|
|
@@ -356,6 +356,15 @@
|
|
|
356
356
|
"firstSeen": "2026-10-08",
|
|
357
357
|
"note": "State label from the app's own state table; consulted only for scan codes without a mapping. The English is a plain rendering."
|
|
358
358
|
},
|
|
359
|
+
{
|
|
360
|
+
"wording": "派送异常",
|
|
361
|
+
"language": "zh",
|
|
362
|
+
"english": "Delivery failed",
|
|
363
|
+
"stage": "failed_attempt",
|
|
364
|
+
"confirmedBy": "live",
|
|
365
|
+
"firstSeen": "2026-10-28",
|
|
366
|
+
"note": "State label of the web preview's newest scan on an item whose relayed feeds give its latest scans as failed deliveries (投递失败); consulted only for scan codes without a mapping. The English is a plain rendering."
|
|
367
|
+
},
|
|
359
368
|
{
|
|
360
369
|
"wording": "邮件异常",
|
|
361
370
|
"language": "zh",
|
|
@@ -6,7 +6,12 @@ import { normalizeStatusWording } from '../../core/status/statusMap.js';
|
|
|
6
6
|
* out with a courier or waiting at a post office.
|
|
7
7
|
*/
|
|
8
8
|
export const ELTA_SCANS = {
|
|
9
|
+
// The sender's label, then the item handed in at a post office, which the shared rules read as delivered.
|
|
10
|
+
'Label printed by customer': 'registered',
|
|
11
|
+
'Item deposited at ELTA': 'accepted',
|
|
9
12
|
'Shipment in transit': 'in_transit',
|
|
13
|
+
// At Athens airport's hub, before the item leaves Greece.
|
|
14
|
+
'Arrival at the airport': 'in_transit',
|
|
10
15
|
'With Courier for delivery': 'out_for_delivery',
|
|
11
16
|
// The courier's attempt: the notice left and its reason, at the same minute.
|
|
12
17
|
'Notification of attempted delivery': 'failed_attempt',
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"carrier": "elta",
|
|
3
3
|
"entries": [
|
|
4
|
+
{"wording": "Label printed by customer", "stage": "registered", "language": "en", "confirmedBy": "live", "note": "The sender's own label, before ELTA has the item."},
|
|
5
|
+
{"wording": "Item deposited at ELTA", "stage": "accepted", "language": "en", "confirmedBy": "live", "note": "The sender handed the item in at the post office the scan names, minutes after the label; then it goes on in transit."},
|
|
6
|
+
{"wording": "Arrival at the airport", "stage": "in_transit", "language": "en", "confirmedBy": "live", "note": "At Athens airport's hub, after the domestic legs of an item leaving Greece."},
|
|
4
7
|
{"wording": "Shipment in transit", "stage": "in_transit", "language": "en", "confirmedBy": "live", "note": "Sent on from the station the scan names, from the sender's agency onwards."},
|
|
5
8
|
{"wording": "Arrival in", "stage": "in_transit", "language": "en", "confirmedBy": "live", "note": "The tracker follows it with the name of the station the scan names; the map reads the opening words."},
|
|
6
9
|
{"wording": "With Courier for delivery", "stage": "out_for_delivery", "language": "en", "confirmedBy": "live"},
|
|
@@ -49,11 +49,13 @@ export function postNLStatus(category, description) {
|
|
|
49
49
|
}
|
|
50
50
|
/**
|
|
51
51
|
* Labels of PostNL's domestic tracker seen on parcels, lowercase without final
|
|
52
|
-
* punctuation: those the shared wording rules read wrong, and its
|
|
52
|
+
* punctuation: those the shared wording rules read wrong, and its pre-advice and
|
|
53
|
+
* sorting scans.
|
|
53
54
|
* Its observations carry no category.
|
|
54
55
|
*/
|
|
55
56
|
const DOMESTIC_STAGE = new Map([
|
|
56
57
|
['shipment expected, but not yet arrived or processed at postnl', 'registered'],
|
|
58
|
+
['not yet processed by postnl', 'registered'],
|
|
57
59
|
['shipment received by postnl', 'accepted'],
|
|
58
60
|
['driver is en route', 'out_for_delivery'],
|
|
59
61
|
['shipment sorted in sorting centre', 'in_transit'],
|
|
@@ -232,6 +232,14 @@
|
|
|
232
232
|
"firstSeen": "2026-10-24",
|
|
233
233
|
"note": "A label of PostNL's domestic tracker; the shared wording rules read it as in transit."
|
|
234
234
|
},
|
|
235
|
+
{
|
|
236
|
+
"wording": "Not yet processed by PostNL",
|
|
237
|
+
"language": "en",
|
|
238
|
+
"stage": "registered",
|
|
239
|
+
"confirmedBy": "live",
|
|
240
|
+
"firstSeen": "2026-10-27",
|
|
241
|
+
"note": "A label of PostNL's domestic tracker, with observation code M02, after the shipment was expected and before PostNL has it."
|
|
242
|
+
},
|
|
235
243
|
{
|
|
236
244
|
"wording": "Shipment received by PostNL",
|
|
237
245
|
"language": "en",
|
|
@@ -3,7 +3,7 @@ const STAGES = {
|
|
|
3
3
|
OriginalWarehouseProcess: 'in_transit', OriginalWarehouseDeparture: 'in_transit',
|
|
4
4
|
LinehaulAgencyReceive: 'in_transit', LinehaulAgencyDeparture: 'in_transit', LinehaulDeparture: 'in_transit',
|
|
5
5
|
LinehaulArrival: 'in_transit', CustomsCleared: 'in_transit', SupplierAndLastMileReceive: 'in_transit',
|
|
6
|
-
LastMileOutForDelivery: 'out_for_delivery', LastMileDelivered: 'delivered',
|
|
6
|
+
LastMileInTransit: 'in_transit', LastMileOutForDelivery: 'out_for_delivery', LastMileDelivered: 'delivered',
|
|
7
7
|
};
|
|
8
8
|
export const statusMap = {
|
|
9
9
|
stage: code => code && Object.hasOwn(STAGES, code) ? STAGES[code] : undefined, gaps: [],
|
|
@@ -81,6 +81,13 @@
|
|
|
81
81
|
"stage": "in_transit",
|
|
82
82
|
"confirmedBy": "live"
|
|
83
83
|
},
|
|
84
|
+
{
|
|
85
|
+
"code": "LastMileInTransit",
|
|
86
|
+
"wording": "In transit along Poste Italiane’s logistic network",
|
|
87
|
+
"language": "en",
|
|
88
|
+
"stage": "in_transit",
|
|
89
|
+
"confirmedBy": "live"
|
|
90
|
+
},
|
|
84
91
|
{
|
|
85
92
|
"code": "LastMileOutForDelivery",
|
|
86
93
|
"wording": "Parcel is out for delivery.",
|
|
@@ -420,8 +420,9 @@ export function trackingLanguageStage(description) {
|
|
|
420
420
|
if (/preparation chez.*expediteur|preparation.*expediteur|preparazione.*mittente|being prepared.*sender|(?:shipper|sender)(?: that)? (?:they are|is|are) preparing|beim absender.*vorbereitet|warehouse of the sender|shippers warehouse|entrepot de l'expediteur|lager des absenders|magazzino del mittente|demande d'envoi.*prise en compte|collection request.*(?:received|recorded)|^(?:the |your )?collection (?:has been |was )?registered$|abholauftrag.*erfasst|richiesta.*ritiro.*registrata/.test(text))
|
|
421
421
|
return 'registered';
|
|
422
422
|
// The sender's order or data reached the carrier, not the parcel: "Order submitted, pending to
|
|
423
|
-
// receive", Royal Mail's "Sender preparing item", "Sender despatching item" and "Sender has despatched item", "Shipping info sent to BRT"
|
|
424
|
-
|
|
423
|
+
// receive", Royal Mail's "Sender preparing item", "Sender despatching item" and "Sender has despatched item", "Shipping info sent to BRT",
|
|
424
|
+
// and a line's "Shipping Order Created".
|
|
425
|
+
if (/\border submitted(?:,| and)? pending (?:to )?rece(?:iv|ipt)|\bshipment data uploaded\b|^sender preparing item\b|^sender (?:has despatched|despatching) item$|^shipping info(?:rmation)? sent to (?!(?:the |your? )?(?:recipient|customer|consignee|addressee|buyer)\b)|\bwe have received your shipment information\b|\bhemos recibido la informacion de su envio\b|\bwe will pick up (?:the|your) (?:package|parcel) from the sender\b|^booked for collection$|\bpending shipping by (?:the )?(?:seller|sender|shipper|merchant)\b|\bship(?:ment|ping) order created\b/.test(text))
|
|
425
426
|
return 'registered';
|
|
426
427
|
// A Shenzhen forwarder's pre-advice from the shipper, before its warehouse has the parcel.
|
|
427
428
|
if (/^forecast has been received$/.test(text))
|
|
@@ -534,14 +535,16 @@ export function trackingLanguageStage(description) {
|
|
|
534
535
|
if (/^attempted but unfinished drop[- ]?off at (?:the |a )?locker$/.test(text))
|
|
535
536
|
return 'registered';
|
|
536
537
|
// A partner network taking the parcel over mid-journey, as ParcelsApp relays it between a post's export
|
|
537
|
-
// scans and the destination's freight scans
|
|
538
|
-
|
|
538
|
+
// scans and the destination's freight scans, and a line's US hub after the flight ("Parcel received by in
|
|
539
|
+
// JFK01.").
|
|
540
|
+
if (/^(?:(?:the |your )?(?:item|parcel|package|shipment) )?(?:(?:has been|was) )?received by (?:the |a |our )?partner carrier$|^(?:(?:the |your )?(?:item|parcel|package|shipment) )?received by in [a-z]{3}\d{2}\.?$/.test(text))
|
|
539
541
|
return 'in_transit';
|
|
540
542
|
// MeiHoo Pegasus's scans at its operation centre, as 17TRACK relays them after the order: the centre handling
|
|
541
|
-
// the package's data, which does not say it has the parcel, then the parcel about to leave the centre.
|
|
543
|
+
// the package's data, which does not say it has the parcel, then the parcel about to leave the centre. The
|
|
544
|
+
// Hualei platform's lines word the departure "Goods leave the operation center".
|
|
542
545
|
if (/^operation cent(?:er|re) is processing (?:the )?(?:package|parcel|shipment) information$/.test(text))
|
|
543
546
|
return 'registered';
|
|
544
|
-
if (/^preparing to leave (?:the )?(?:[a-z]+ ){0,3}operation cent(?:er|re)$/.test(text))
|
|
547
|
+
if (/^(?:preparing to leave|(?:the )?goods leav(?:e|ing)) (?:the )?(?:[a-z]+ ){0,3}operation cent(?:er|re)$/.test(text))
|
|
545
548
|
return 'in_transit';
|
|
546
549
|
// PostNL's international scans as providers relay them without its categories, read as Spring GDS's map reads
|
|
547
550
|
// them: the item prepared before its bulk handover, then PostNL's acceptance centre taking it in.
|
|
@@ -584,8 +587,9 @@ export function trackingLanguageStage(description) {
|
|
|
584
587
|
// Taken in by the carrier: Royal Mail's "Item received by Royal Mail", a parcel shop's or a warehouse's
|
|
585
588
|
// receipt, a forwarder's ("<company> has received the goods, <town>, <country>."), the sender's drop-off at a
|
|
586
589
|
// SEUR pickup point, a collection carried out, and its English "Has been put into storage". A bare "Item
|
|
587
|
-
// received" names no receiver and stays unread.
|
|
588
|
-
|
|
590
|
+
// received" names no receiver and stays unread. The Hualei platform's arrival at a line's receiving point
|
|
591
|
+
// (到达收货点) is a receipt too.
|
|
592
|
+
if (/^到达收货点|^item received by royal mail$|\btaken over by one of our operators\b|\bwe've received your (?:parcel|package|item) at the parcel ?shop\b|^(?:(?:the |your )?(?:item|parcel|package|shipment) )?(?:was|has been) dropped off at (?:the |a )?parcel ?shop$|^(?![^,]*\b(?:recipient|consignee|receiver|customer|addressee|buyer|pick ?up point|parcel ?shop|locker|destination)\b)[a-z][\w&' -]{0,40} has received the goods(?:, [^,]{1,40}){0,2}\.?$|^the shipment has been deposited at a seur pickup point$|^(?:the |your )?collection (?:has been |was )?(?:carried out|completed)$|^已入库|^(?:(?:the |your )?(?:item|parcel|package|shipment) )?(?:has been |was )?put into storage$/.test(text))
|
|
589
593
|
return 'accepted';
|
|
590
594
|
// Royal Mail's sender drop-offs at a parcel locker and a postbox, as providers relay them.
|
|
591
595
|
if (/^sender advised item dropped off at parcel locker$|^dropped off at postbox$/.test(text))
|
|
@@ -30,6 +30,7 @@ import { jsExpressChinaClock } from '../../carriers/js-express/clock.js';
|
|
|
30
30
|
import { pitneyBowesPlatformClock, pitneyBowesPostalRelay } from '../../carriers/pitney-bowes/clock.js';
|
|
31
31
|
import { pocztaPolskaPartnerClock } from '../../carriers/poczta-polska/clock.js';
|
|
32
32
|
import { facilityZone, LatestScan, relaysFacilityClock } from '../shared/facilityClock.js';
|
|
33
|
+
import { CHINESE_CITIES, CHINESE_PROVINCES } from '../shared/china.js';
|
|
33
34
|
import { brandCarrierForNumber, universalCarrierHints } from '../shared/hints.js';
|
|
34
35
|
import { event, isNotice, localEvent, numberOf, place as reportedPlace, result } from '../shared/result.js';
|
|
35
36
|
import { carrierScan, markLaterReceipts, markReturnLeg } from '../shared/scans.js';
|
|
@@ -644,19 +645,6 @@ const POSTAL_ORIGIN_LEG = wordings([
|
|
|
644
645
|
]);
|
|
645
646
|
// The posting itself, UPU's "Posting/Collection" and EMS's "Posted" (EMA).
|
|
646
647
|
const POSTAL_POSTING = wordings(['posting/collection', 'posted']);
|
|
647
|
-
// Mainland China's provinces, regions and municipalities, as China Post's scans name them.
|
|
648
|
-
const CHINESE_PROVINCES = new Set([
|
|
649
|
-
'anhui', 'beijing', 'chongqing', 'fujian', 'gansu', 'guangdong', 'guangxi', 'guizhou', 'hainan', 'hebei', 'heilongjiang', 'henan',
|
|
650
|
-
'hubei', 'hunan', 'innermongolia', 'jiangsu', 'jiangxi', 'jilin', 'liaoning', 'ningxia', 'qinghai', 'shaanxi', 'shandong',
|
|
651
|
-
'shanghai', 'shanxi', 'sichuan', 'tianjin', 'tibet', 'xinjiang', 'xizang', 'yunnan', 'zhejiang',
|
|
652
|
-
]);
|
|
653
|
-
// Mainland cities of China Post's provincial and export processing centres, which its scans can name alone.
|
|
654
|
-
const CHINESE_CITIES = new Set([
|
|
655
|
-
'changchun', 'changsha', 'chengdu', 'dalian', 'dongguan', 'foshan', 'fuzhou', 'guangzhou', 'guiyang', 'haikou', 'hangzhou', 'harbin',
|
|
656
|
-
'hefei', 'hohhot', 'huizhou', 'jinan', 'jinhua', 'kunming', 'lanzhou', 'lhasa', 'nanchang', 'nanjing', 'nanning', 'ningbo', 'putian',
|
|
657
|
-
'qingdao', 'quanzhou', 'shantou', 'shenyang', 'shenzhen', 'shijiazhuang', 'suzhou', 'taiyuan', 'urumqi', 'wenzhou', 'wuhan', 'wuxi',
|
|
658
|
-
'xiamen', 'xian', 'xining', 'yinchuan', 'yiwu', 'zhengzhou', 'zhongshan',
|
|
659
|
-
]);
|
|
660
648
|
/**
|
|
661
649
|
* Whether a China Post scan is on Beijing's clock: its place is written in
|
|
662
650
|
* Chinese ("示例市 12345678"), ends with a mainland province ("Example City,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Mainland China's provinces, regions and municipalities, as China Post's scans name them.
|
|
2
|
+
export const CHINESE_PROVINCES = new Set([
|
|
3
|
+
'anhui', 'beijing', 'chongqing', 'fujian', 'gansu', 'guangdong', 'guangxi', 'guizhou', 'hainan', 'hebei', 'heilongjiang', 'henan',
|
|
4
|
+
'hubei', 'hunan', 'innermongolia', 'jiangsu', 'jiangxi', 'jilin', 'liaoning', 'ningxia', 'qinghai', 'shaanxi', 'shandong',
|
|
5
|
+
'shanghai', 'shanxi', 'sichuan', 'tianjin', 'tibet', 'xinjiang', 'xizang', 'yunnan', 'zhejiang',
|
|
6
|
+
]);
|
|
7
|
+
// Mainland cities of China Post's provincial and export processing centres, which its scans can name alone.
|
|
8
|
+
export const CHINESE_CITIES = new Set([
|
|
9
|
+
'changchun', 'changsha', 'chengdu', 'dalian', 'dongguan', 'foshan', 'fuzhou', 'guangzhou', 'guiyang', 'haikou', 'hangzhou', 'harbin',
|
|
10
|
+
'hefei', 'hohhot', 'huizhou', 'jinan', 'jinhua', 'kunming', 'lanzhou', 'lhasa', 'nanchang', 'nanjing', 'nanning', 'ningbo', 'putian',
|
|
11
|
+
'qingdao', 'quanzhou', 'shantou', 'shenyang', 'shenzhen', 'shijiazhuang', 'suzhou', 'taiyuan', 'urumqi', 'wenzhou', 'wuhan', 'wuxi',
|
|
12
|
+
'xiamen', 'xian', 'xining', 'yinchuan', 'yiwu', 'zhengzhou', 'zhongshan',
|
|
13
|
+
]);
|
|
@@ -11,7 +11,7 @@ export declare function hasPrivateDeliveryDetails(description: string): boolean;
|
|
|
11
11
|
* area, a "Country" label or a status given before the place, unless it is a
|
|
12
12
|
* label or placeholder ("--") that names no place, holds private delivery
|
|
13
13
|
* details or is Posti's "abroad" label. A postcode given alone is the country
|
|
14
|
-
* its code names, if any.
|
|
14
|
+
* its code names, if any. A country a feed added goes (`withoutAddedCountry`).
|
|
15
15
|
*/
|
|
16
16
|
export declare function place(value: unknown): string;
|
|
17
17
|
/** A place written in brackets after the wording, "Airline received【Hong Kong】": the wording before it and the place. */
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { DateTime } from 'luxon';
|
|
12
12
|
import { trackingLanguageStage } from '../../core/status/index.js';
|
|
13
13
|
import { countryCode } from '../../core/time/index.js';
|
|
14
|
+
import { CHINESE_CITIES, CHINESE_PROVINCES } from './china.js';
|
|
14
15
|
import { deliveryForecastRemainder, nonterminalEnglishReturn } from '../../core/status/language.js';
|
|
15
16
|
import { IndeterminateError, InvalidInputError, NoHistoryError } from '../../core/errors/index.js';
|
|
16
17
|
import { PROGRESS } from '../../core/result/partial.js';
|
|
@@ -82,6 +83,25 @@ function postcodeCountry(location) {
|
|
|
82
83
|
const code = postcode[1] && countryCode(postcode[1]) === postcode[1] && !NOT_COUNTRIES.test(postcode[1]) ? postcode[1] : undefined;
|
|
83
84
|
return code ? ENGLISH_REGIONS.of(code) ?? '' : '';
|
|
84
85
|
}
|
|
86
|
+
// Countries whose places can be written in Chinese characters.
|
|
87
|
+
const HAN_COUNTRIES = new Set(['CN', 'HK', 'MO', 'TW', 'JP', 'KR', 'SG']);
|
|
88
|
+
/**
|
|
89
|
+
* A place without a country a feed added: the destination's, which lines
|
|
90
|
+
* append to their warehouses in China ("广州,US") and ParcelsApp spells out
|
|
91
|
+
* ("Shanghai, United States"), or a country given twice ("Example State,
|
|
92
|
+
* United States, United States").
|
|
93
|
+
*/
|
|
94
|
+
function withoutAddedCountry(location) {
|
|
95
|
+
const parts = location.split(',').map((part) => part.trim());
|
|
96
|
+
const country = parts.length > 1 ? countryCode(parts.at(-1)) : null;
|
|
97
|
+
if (!country)
|
|
98
|
+
return location;
|
|
99
|
+
const doubled = parts.length > 2 && countryCode(parts.at(-2)) === country;
|
|
100
|
+
const key = (part) => part.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
101
|
+
const chinese = !HAN_COUNTRIES.has(country) && parts.slice(0, -1).some((part) => /\p{Script=Han}/u.test(part)
|
|
102
|
+
|| CHINESE_PROVINCES.has(key(part)) || CHINESE_CITIES.has(key(part)));
|
|
103
|
+
return doubled || chinese ? parts.slice(0, -1).join(', ') : location;
|
|
104
|
+
}
|
|
85
105
|
/** The place a status given as a location names in 【】 or before its airport, '' when it names none, or undefined for any other location. */
|
|
86
106
|
function statusPlace(location) {
|
|
87
107
|
const status = STATUS_PLACE.exec(location);
|
|
@@ -96,11 +116,11 @@ function statusPlace(location) {
|
|
|
96
116
|
* area, a "Country" label or a status given before the place, unless it is a
|
|
97
117
|
* label or placeholder ("--") that names no place, holds private delivery
|
|
98
118
|
* details or is Posti's "abroad" label. A postcode given alone is the country
|
|
99
|
-
* its code names, if any.
|
|
119
|
+
* its code names, if any. A country a feed added goes (`withoutAddedCountry`).
|
|
100
120
|
*/
|
|
101
121
|
export function place(value) {
|
|
102
122
|
const read = text(value).slice(0, 200).replace(DEPOT_PREFIX, '').replace(BRACKETED_POSTCODE, '').replace(OFFICE_CODE, '').replace(COUNTRY_LABEL, '');
|
|
103
|
-
const location = statusPlace(read) ?? postcodeCountry(read) ?? read;
|
|
123
|
+
const location = statusPlace(read) ?? postcodeCountry(read) ?? withoutAddedCountry(read);
|
|
104
124
|
return /[\p{L}\p{N}]/u.test(location) && !NOT_PLACES.test(location) && !hasPrivateDeliveryDetails(location) && !isPostiAbroadLabel(location)
|
|
105
125
|
? location : '';
|
|
106
126
|
}
|
package/dist/server/openapi.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "universal-parcel-scraper",
|
|
3
|
-
"version": "0.802.
|
|
3
|
+
"version": "0.802.2-main.4316",
|
|
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",
|