universal-parcel-scraper 0.158.0-main.1233 → 0.159.0-main.1237
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 +2 -2
- package/data/catalog.json +34 -6
- package/data/coverage-summary.json +1 -1
- package/data/detection-golden.json +132 -0
- package/dist/browser/scraper.js +27 -7
- package/dist/carriers/gati/adapter.d.ts +20 -0
- package/dist/carriers/gati/adapter.js +105 -0
- package/dist/carriers/gati/carrier.json +49 -7
- package/dist/carriers/gati/numbers.json +67 -7
- package/dist/carriers/gati/parser.d.ts +13 -0
- package/dist/carriers/gati/parser.js +173 -0
- package/dist/carriers/gati/status.d.ts +7 -0
- package/dist/carriers/gati/status.js +37 -0
- package/dist/carriers/gati/statuses.json +12 -1
- package/dist/carriers/shadowfax/adapter.d.ts +19 -0
- package/dist/carriers/shadowfax/adapter.js +93 -0
- package/dist/carriers/shadowfax/carrier.json +55 -7
- package/dist/carriers/shadowfax/numbers.json +144 -8
- package/dist/carriers/shadowfax/parser.d.ts +28 -0
- package/dist/carriers/shadowfax/parser.js +206 -0
- package/dist/carriers/shadowfax/status.d.ts +12 -0
- package/dist/carriers/shadowfax/status.js +77 -0
- package/dist/carriers/shadowfax/statuses.json +16 -1
- package/dist/carriers/total-express/adapter.d.ts +15 -0
- package/dist/carriers/total-express/adapter.js +85 -0
- package/dist/carriers/total-express/carrier.json +81 -10
- package/dist/carriers/total-express/numbers.json +115 -1
- package/dist/carriers/total-express/parser.d.ts +24 -0
- package/dist/carriers/total-express/parser.js +195 -0
- package/dist/carriers/total-express/status.d.ts +7 -0
- package/dist/carriers/total-express/status.js +138 -0
- package/dist/carriers/total-express/statuses.json +101 -7
- package/dist/core/catalog/statusMaps.js +7 -3
- package/dist/data/catalog.json +34 -6
- package/dist/generated/catalog.d.ts +23 -6
- package/dist/generated/catalog.js +35 -7
- package/dist/generated/recognition.js +3 -0
- package/dist/generated/registry.js +9 -3
- package/dist/server/openapi.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ The engine behind [Peek](https://peektracker.com) ([GitHub](https://github.com/p
|
|
|
13
13
|
[](LICENSE)
|
|
14
14
|
|
|
15
15
|
<!-- GENERATED:summary -->
|
|
16
|
-
**3,500+ carriers** through **
|
|
16
|
+
**3,500+ carriers** through **221 dedicated adapters** and **5 universal fallbacks**
|
|
17
17
|
|
|
18
18
|
<sub>358 catalog entries · 91 countries represented</sub>
|
|
19
19
|
<!-- /GENERATED:summary -->
|
|
@@ -155,7 +155,7 @@ createTracker({ providers: ['ParcelsApp', 'Ship24', '17TRACK', 'Postal Ninja', '
|
|
|
155
155
|
<!-- GENERATED:stages -->
|
|
156
156
|
<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">
|
|
157
157
|
|
|
158
|
-
The carrier folders record 7,
|
|
158
|
+
The carrier folders record 7,762 such statuses, each filed under one stage.
|
|
159
159
|
<!-- /GENERATED:stages -->
|
|
160
160
|
|
|
161
161
|
Wording nobody recorded yet goes through a classifier that reads seven European languages.
|
package/data/catalog.json
CHANGED
|
@@ -8858,7 +8858,8 @@
|
|
|
8858
8858
|
"timezone": "Asia/Kolkata",
|
|
8859
8859
|
"tracking": {
|
|
8860
8860
|
"mode": "automatic",
|
|
8861
|
-
"adapter": "
|
|
8861
|
+
"adapter": "gati",
|
|
8862
|
+
"recognitionRank": 43
|
|
8862
8863
|
},
|
|
8863
8864
|
"canaryUrl": "https://www.allcargologistics.com/track-shipment",
|
|
8864
8865
|
"trackingSearchUrl": "https://www.allcargologistics.com/track-shipment",
|
|
@@ -13037,7 +13038,8 @@
|
|
|
13037
13038
|
"timezone": "Asia/Kolkata",
|
|
13038
13039
|
"tracking": {
|
|
13039
13040
|
"mode": "automatic",
|
|
13040
|
-
"adapter": "
|
|
13041
|
+
"adapter": "shadowfax",
|
|
13042
|
+
"recognitionRank": 595
|
|
13041
13043
|
},
|
|
13042
13044
|
"canaryUrl": "https://www.shadowfax.in/track",
|
|
13043
13045
|
"trackingUrlTemplate": "https://tracker.shadowfax.in/#/awb/{trackingNumber}",
|
|
@@ -14043,11 +14045,37 @@
|
|
|
14043
14045
|
"timezone": "America/Sao_Paulo",
|
|
14044
14046
|
"tracking": {
|
|
14045
14047
|
"mode": "automatic",
|
|
14046
|
-
"adapter": "
|
|
14048
|
+
"adapter": "total-express",
|
|
14049
|
+
"recognitionRank": 975,
|
|
14050
|
+
"localClocks": true
|
|
14047
14051
|
},
|
|
14048
|
-
"canaryUrl": "https://totalexpress.com.br/
|
|
14049
|
-
"
|
|
14050
|
-
"
|
|
14052
|
+
"canaryUrl": "https://totalconecta.totalexpress.com.br/rastreamento",
|
|
14053
|
+
"trackingUrlTemplate": "https://totalconecta.totalexpress.com.br/rastreamento?codigo={trackingNumber}",
|
|
14054
|
+
"trackingSearchUrl": "https://totalconecta.totalexpress.com.br/rastreamento",
|
|
14055
|
+
"linkRules": [
|
|
14056
|
+
{
|
|
14057
|
+
"domains": [
|
|
14058
|
+
"totalconecta.totalexpress.com.br"
|
|
14059
|
+
],
|
|
14060
|
+
"path": "^/rastreamento/rastreamento/encomendas/([^/?#]+)/?$"
|
|
14061
|
+
},
|
|
14062
|
+
{
|
|
14063
|
+
"domains": [
|
|
14064
|
+
"totalconecta.totalexpress.com.br"
|
|
14065
|
+
],
|
|
14066
|
+
"pathPattern": "^/rastreamento/?$",
|
|
14067
|
+
"params": [
|
|
14068
|
+
"codigo"
|
|
14069
|
+
],
|
|
14070
|
+
"ownNumbersOnly": true
|
|
14071
|
+
}
|
|
14072
|
+
],
|
|
14073
|
+
"detectionRules": [
|
|
14074
|
+
{
|
|
14075
|
+
"pattern": "^(?:TX[A-Z]{2}|AMZB)\\d{9}TX$",
|
|
14076
|
+
"confidence": "high"
|
|
14077
|
+
}
|
|
14078
|
+
]
|
|
14051
14079
|
},
|
|
14052
14080
|
"trackon": {
|
|
14053
14081
|
"displayName": "Trackon Couriers",
|
|
@@ -10096,6 +10096,12 @@
|
|
|
10096
10096
|
"dhl-ecommerce-pl"
|
|
10097
10097
|
]
|
|
10098
10098
|
},
|
|
10099
|
+
{
|
|
10100
|
+
"input": "139815455",
|
|
10101
|
+
"carrier": "unknown",
|
|
10102
|
+
"confidence": "none",
|
|
10103
|
+
"candidates": []
|
|
10104
|
+
},
|
|
10099
10105
|
{
|
|
10100
10106
|
"input": "13CF4B49016730467J",
|
|
10101
10107
|
"carrier": "zeleris",
|
|
@@ -23536,6 +23542,20 @@
|
|
|
23536
23542
|
"dhl-ecommerce-pl"
|
|
23537
23543
|
]
|
|
23538
23544
|
},
|
|
23545
|
+
{
|
|
23546
|
+
"input": "412933252",
|
|
23547
|
+
"carrier": "unknown",
|
|
23548
|
+
"confidence": "low",
|
|
23549
|
+
"candidates": [
|
|
23550
|
+
"tnt"
|
|
23551
|
+
],
|
|
23552
|
+
"preferred": [
|
|
23553
|
+
"tnt"
|
|
23554
|
+
],
|
|
23555
|
+
"asked": [
|
|
23556
|
+
"tnt"
|
|
23557
|
+
]
|
|
23558
|
+
},
|
|
23539
23559
|
{
|
|
23540
23560
|
"input": "41505910017980",
|
|
23541
23561
|
"carrier": "unknown",
|
|
@@ -37360,6 +37380,12 @@
|
|
|
37360
37380
|
"brt"
|
|
37361
37381
|
]
|
|
37362
37382
|
},
|
|
37383
|
+
{
|
|
37384
|
+
"input": "988397715",
|
|
37385
|
+
"carrier": "unknown",
|
|
37386
|
+
"confidence": "none",
|
|
37387
|
+
"candidates": []
|
|
37388
|
+
},
|
|
37363
37389
|
{
|
|
37364
37390
|
"input": "988C01701257F",
|
|
37365
37391
|
"carrier": "unknown",
|
|
@@ -38894,6 +38920,14 @@
|
|
|
38894
38920
|
"mtscn"
|
|
38895
38921
|
]
|
|
38896
38922
|
},
|
|
38923
|
+
{
|
|
38924
|
+
"input": "AMZB664764467tx",
|
|
38925
|
+
"carrier": "total-express",
|
|
38926
|
+
"confidence": "high",
|
|
38927
|
+
"candidates": [
|
|
38928
|
+
"total-express"
|
|
38929
|
+
]
|
|
38930
|
+
},
|
|
38897
38931
|
{
|
|
38898
38932
|
"input": "AN725955",
|
|
38899
38933
|
"carrier": "unknown",
|
|
@@ -51474,6 +51508,20 @@
|
|
|
51474
51508
|
"confidence": "low",
|
|
51475
51509
|
"candidates": [
|
|
51476
51510
|
"shadowfax"
|
|
51511
|
+
],
|
|
51512
|
+
"asked": [
|
|
51513
|
+
"shadowfax"
|
|
51514
|
+
]
|
|
51515
|
+
},
|
|
51516
|
+
{
|
|
51517
|
+
"input": "R1858467302TIU",
|
|
51518
|
+
"carrier": "unknown",
|
|
51519
|
+
"confidence": "low",
|
|
51520
|
+
"candidates": [
|
|
51521
|
+
"shadowfax"
|
|
51522
|
+
],
|
|
51523
|
+
"asked": [
|
|
51524
|
+
"shadowfax"
|
|
51477
51525
|
]
|
|
51478
51526
|
},
|
|
51479
51527
|
{
|
|
@@ -53556,6 +53604,12 @@
|
|
|
53556
53604
|
"shadowfax"
|
|
53557
53605
|
]
|
|
53558
53606
|
},
|
|
53607
|
+
{
|
|
53608
|
+
"input": "SF1904798183E",
|
|
53609
|
+
"carrier": "unknown",
|
|
53610
|
+
"confidence": "none",
|
|
53611
|
+
"candidates": []
|
|
53612
|
+
},
|
|
53559
53613
|
{
|
|
53560
53614
|
"input": "SF211225399443FPL",
|
|
53561
53615
|
"carrier": "shadowfax",
|
|
@@ -53572,6 +53626,22 @@
|
|
|
53572
53626
|
"shadowfax"
|
|
53573
53627
|
]
|
|
53574
53628
|
},
|
|
53629
|
+
{
|
|
53630
|
+
"input": "SF2917969609ARA",
|
|
53631
|
+
"carrier": "shadowfax",
|
|
53632
|
+
"confidence": "high",
|
|
53633
|
+
"candidates": [
|
|
53634
|
+
"shadowfax"
|
|
53635
|
+
]
|
|
53636
|
+
},
|
|
53637
|
+
{
|
|
53638
|
+
"input": "SF3033213302ARA",
|
|
53639
|
+
"carrier": "shadowfax",
|
|
53640
|
+
"confidence": "high",
|
|
53641
|
+
"candidates": [
|
|
53642
|
+
"shadowfax"
|
|
53643
|
+
]
|
|
53644
|
+
},
|
|
53575
53645
|
{
|
|
53576
53646
|
"input": "SF332188411FPL",
|
|
53577
53647
|
"carrier": "shadowfax",
|
|
@@ -53596,6 +53666,28 @@
|
|
|
53596
53666
|
"shadowfax"
|
|
53597
53667
|
]
|
|
53598
53668
|
},
|
|
53669
|
+
{
|
|
53670
|
+
"input": "SF3667163853YWR",
|
|
53671
|
+
"carrier": "shadowfax",
|
|
53672
|
+
"confidence": "high",
|
|
53673
|
+
"candidates": [
|
|
53674
|
+
"shadowfax"
|
|
53675
|
+
]
|
|
53676
|
+
},
|
|
53677
|
+
{
|
|
53678
|
+
"input": "SF3772148429KR",
|
|
53679
|
+
"carrier": "unknown",
|
|
53680
|
+
"confidence": "none",
|
|
53681
|
+
"candidates": []
|
|
53682
|
+
},
|
|
53683
|
+
{
|
|
53684
|
+
"input": "SF4073772682DEU",
|
|
53685
|
+
"carrier": "shadowfax",
|
|
53686
|
+
"confidence": "high",
|
|
53687
|
+
"candidates": [
|
|
53688
|
+
"shadowfax"
|
|
53689
|
+
]
|
|
53690
|
+
},
|
|
53599
53691
|
{
|
|
53600
53692
|
"input": "SF6042542297687",
|
|
53601
53693
|
"carrier": "sf-express",
|
|
@@ -54761,6 +54853,46 @@
|
|
|
54761
54853
|
"tsjy"
|
|
54762
54854
|
]
|
|
54763
54855
|
},
|
|
54856
|
+
{
|
|
54857
|
+
"input": "TXAQ243268174TX",
|
|
54858
|
+
"carrier": "total-express",
|
|
54859
|
+
"confidence": "high",
|
|
54860
|
+
"candidates": [
|
|
54861
|
+
"total-express"
|
|
54862
|
+
]
|
|
54863
|
+
},
|
|
54864
|
+
{
|
|
54865
|
+
"input": "TXAQ402565477tx",
|
|
54866
|
+
"carrier": "total-express",
|
|
54867
|
+
"confidence": "high",
|
|
54868
|
+
"candidates": [
|
|
54869
|
+
"total-express"
|
|
54870
|
+
]
|
|
54871
|
+
},
|
|
54872
|
+
{
|
|
54873
|
+
"input": "TXAQ549180149tx",
|
|
54874
|
+
"carrier": "total-express",
|
|
54875
|
+
"confidence": "high",
|
|
54876
|
+
"candidates": [
|
|
54877
|
+
"total-express"
|
|
54878
|
+
]
|
|
54879
|
+
},
|
|
54880
|
+
{
|
|
54881
|
+
"input": "TXAQ589033943TX",
|
|
54882
|
+
"carrier": "total-express",
|
|
54883
|
+
"confidence": "high",
|
|
54884
|
+
"candidates": [
|
|
54885
|
+
"total-express"
|
|
54886
|
+
]
|
|
54887
|
+
},
|
|
54888
|
+
{
|
|
54889
|
+
"input": "TXAS426107751tx",
|
|
54890
|
+
"carrier": "total-express",
|
|
54891
|
+
"confidence": "high",
|
|
54892
|
+
"candidates": [
|
|
54893
|
+
"total-express"
|
|
54894
|
+
]
|
|
54895
|
+
},
|
|
54764
54896
|
{
|
|
54765
54897
|
"input": "TYPQYU501214190",
|
|
54766
54898
|
"carrier": "unknown",
|
package/dist/browser/scraper.js
CHANGED
|
@@ -6903,7 +6903,8 @@ var Ae = {
|
|
|
6903
6903
|
timezone: "Asia/Kolkata",
|
|
6904
6904
|
tracking: {
|
|
6905
6905
|
mode: "automatic",
|
|
6906
|
-
adapter: "
|
|
6906
|
+
adapter: "gati",
|
|
6907
|
+
recognitionRank: 43
|
|
6907
6908
|
},
|
|
6908
6909
|
canaryUrl: "https://www.allcargologistics.com/track-shipment",
|
|
6909
6910
|
trackingSearchUrl: "https://www.allcargologistics.com/track-shipment",
|
|
@@ -10043,7 +10044,8 @@ var Ae = {
|
|
|
10043
10044
|
timezone: "Asia/Kolkata",
|
|
10044
10045
|
tracking: {
|
|
10045
10046
|
mode: "automatic",
|
|
10046
|
-
adapter: "
|
|
10047
|
+
adapter: "shadowfax",
|
|
10048
|
+
recognitionRank: 595
|
|
10047
10049
|
},
|
|
10048
10050
|
canaryUrl: "https://www.shadowfax.in/track",
|
|
10049
10051
|
trackingUrlTemplate: "https://tracker.shadowfax.in/#/awb/{trackingNumber}",
|
|
@@ -10762,11 +10764,26 @@ var Ae = {
|
|
|
10762
10764
|
timezone: "America/Sao_Paulo",
|
|
10763
10765
|
tracking: {
|
|
10764
10766
|
mode: "automatic",
|
|
10765
|
-
adapter: "
|
|
10767
|
+
adapter: "total-express",
|
|
10768
|
+
recognitionRank: 975,
|
|
10769
|
+
localClocks: !0
|
|
10766
10770
|
},
|
|
10767
|
-
canaryUrl: "https://totalexpress.com.br/
|
|
10768
|
-
|
|
10769
|
-
|
|
10771
|
+
canaryUrl: "https://totalconecta.totalexpress.com.br/rastreamento",
|
|
10772
|
+
trackingUrlTemplate: "https://totalconecta.totalexpress.com.br/rastreamento?codigo={trackingNumber}",
|
|
10773
|
+
trackingSearchUrl: "https://totalconecta.totalexpress.com.br/rastreamento",
|
|
10774
|
+
linkRules: [{
|
|
10775
|
+
domains: ["totalconecta.totalexpress.com.br"],
|
|
10776
|
+
path: "^/rastreamento/rastreamento/encomendas/([^/?#]+)/?$"
|
|
10777
|
+
}, {
|
|
10778
|
+
domains: ["totalconecta.totalexpress.com.br"],
|
|
10779
|
+
pathPattern: "^/rastreamento/?$",
|
|
10780
|
+
params: ["codigo"],
|
|
10781
|
+
ownNumbersOnly: !0
|
|
10782
|
+
}],
|
|
10783
|
+
detectionRules: [{
|
|
10784
|
+
pattern: "^(?:TX[A-Z]{2}|AMZB)\\d{9}TX$",
|
|
10785
|
+
confidence: "high"
|
|
10786
|
+
}]
|
|
10770
10787
|
},
|
|
10771
10788
|
trackon: {
|
|
10772
10789
|
displayName: "Trackon Couriers",
|
|
@@ -11965,7 +11982,7 @@ var Ae = {
|
|
|
11965
11982
|
"tforce-freight": [],
|
|
11966
11983
|
thhy: ["thhy-1"],
|
|
11967
11984
|
toptrans: [],
|
|
11968
|
-
"total-express": [],
|
|
11985
|
+
"total-express": ["total-express-awb"],
|
|
11969
11986
|
trackon: [],
|
|
11970
11987
|
"trans-o-flex": [],
|
|
11971
11988
|
"trendyol-express": [],
|
|
@@ -17118,6 +17135,7 @@ var nl = {
|
|
|
17118
17135
|
"fan-courier": 330,
|
|
17119
17136
|
"four-px": 570,
|
|
17120
17137
|
foxpost: 200,
|
|
17138
|
+
gati: 43,
|
|
17121
17139
|
geis: 90,
|
|
17122
17140
|
"geniki-taxydromiki": 140,
|
|
17123
17141
|
"geodis-pl": 994,
|
|
@@ -17178,6 +17196,7 @@ var nl = {
|
|
|
17178
17196
|
saia: 12,
|
|
17179
17197
|
sameday: 370,
|
|
17180
17198
|
seur: 870,
|
|
17199
|
+
shadowfax: 595,
|
|
17181
17200
|
"slovak-parcel-service": 180,
|
|
17182
17201
|
"slovenska-posta": 170,
|
|
17183
17202
|
speedaf: 989,
|
|
@@ -17189,6 +17208,7 @@ var nl = {
|
|
|
17189
17208
|
thhy: 987,
|
|
17190
17209
|
tipsa: 680,
|
|
17191
17210
|
tnt: 880,
|
|
17211
|
+
"total-express": 975,
|
|
17192
17212
|
tsjy: 992,
|
|
17193
17213
|
"ubi-smart-parcel": 45,
|
|
17194
17214
|
ukrposhta: 490,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type AdapterFactory, type TrackingContext } from '../../core/adapter/index.js';
|
|
2
|
+
import type { CarrierResult } from '../../core/result/index.js';
|
|
3
|
+
import { type StepRecorder } from '../../core/telemetry/index.js';
|
|
4
|
+
/** The page token the tracking page on www.allcargologistics.com asks for when it loads. */
|
|
5
|
+
export declare const GATI_TOKEN_URL = "https://admin.allcargologistics.com/api/frontend/token";
|
|
6
|
+
/** The lookup the tracking page makes for the docket number typed in. */
|
|
7
|
+
export declare const GATI_TRACKING_URL = "https://admin.allcargologistics.com/api/track-shipment";
|
|
8
|
+
export declare class GatiTracker {
|
|
9
|
+
private readonly options;
|
|
10
|
+
constructor(options?: {
|
|
11
|
+
fetcher?: typeof fetch;
|
|
12
|
+
recorder?: StepRecorder;
|
|
13
|
+
userAgent?: string;
|
|
14
|
+
});
|
|
15
|
+
fetch(raw: string, context?: TrackingContext): Promise<CarrierResult>;
|
|
16
|
+
private read;
|
|
17
|
+
/** A page token, as the tracking page gets one on every visit; it lasts five minutes. */
|
|
18
|
+
private token;
|
|
19
|
+
}
|
|
20
|
+
export declare const adapter: AdapterFactory;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { accepted, recognizeFromLookup } from '../../core/adapter/index.js';
|
|
2
|
+
import { ChallengeError, SchemaError, TransportError, UpstreamHttpError, UpstreamNetworkError } from '../../core/errors/index.js';
|
|
3
|
+
import { runSteps } from '../../core/runner/index.js';
|
|
4
|
+
import { NOOP_RECORDER } from '../../core/telemetry/index.js';
|
|
5
|
+
import { decodeText, fetchBounded, userAgentOf } from '../../core/transport/index.js';
|
|
6
|
+
import { isRecord } from '../../core/types.js';
|
|
7
|
+
import { GATI_MAX_BYTES, normalizeGatiNumber, parseGati, PROVIDER } from './parser.js';
|
|
8
|
+
/** The page token the tracking page on www.allcargologistics.com asks for when it loads. */
|
|
9
|
+
export const GATI_TOKEN_URL = 'https://admin.allcargologistics.com/api/frontend/token';
|
|
10
|
+
/** The lookup the tracking page makes for the docket number typed in. */
|
|
11
|
+
export const GATI_TRACKING_URL = 'https://admin.allcargologistics.com/api/track-shipment';
|
|
12
|
+
// The site answers the lookup only for its own pages.
|
|
13
|
+
const ORIGIN = 'https://www.allcargologistics.com';
|
|
14
|
+
const REDIRECTS = [301, 302, 303, 307, 308];
|
|
15
|
+
// Bot checks a CDN or firewall could put in place of the reply.
|
|
16
|
+
const CHALLENGE = /_cf_chl_opt|cf-turnstile|<title>\s*Just a moment|AwsWafIntegration|awswaf\.com|g-recaptcha|h-captcha/i;
|
|
17
|
+
// The token is a number, a bar and forty letters and digits.
|
|
18
|
+
const TOKEN = /^[\w|.~+/=-]{8,512}$/;
|
|
19
|
+
function json(bytes) {
|
|
20
|
+
const body = decodeText(bytes);
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(body);
|
|
23
|
+
}
|
|
24
|
+
catch (cause) {
|
|
25
|
+
if (CHALLENGE.test(body.slice(0, 64_000)))
|
|
26
|
+
throw new ChallengeError(PROVIDER, 'AllcargoGATI answered with a browser check', { cause });
|
|
27
|
+
throw new SchemaError(PROVIDER, 'AllcargoGATI returned a reply that is not JSON', { cause });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The same failure without the request details fetchBounded attaches: they
|
|
32
|
+
* hold the page token.
|
|
33
|
+
*/
|
|
34
|
+
function withoutToken(error) {
|
|
35
|
+
if (error instanceof UpstreamHttpError)
|
|
36
|
+
return new UpstreamHttpError(error.provider, error.status, error.retryAfterMs);
|
|
37
|
+
if (error instanceof UpstreamNetworkError)
|
|
38
|
+
return new UpstreamNetworkError(error.provider, error.cause);
|
|
39
|
+
return error;
|
|
40
|
+
}
|
|
41
|
+
export class GatiTracker {
|
|
42
|
+
options;
|
|
43
|
+
constructor(options = {}) {
|
|
44
|
+
this.options = options;
|
|
45
|
+
}
|
|
46
|
+
async fetch(raw, context = {}) {
|
|
47
|
+
const number = normalizeGatiNumber(raw);
|
|
48
|
+
// One read with the whole budget: the site waits up to thirty seconds for
|
|
49
|
+
// the tracking service behind it, which some dockets never answer.
|
|
50
|
+
return runSteps({ carrier: 'gati', budgetMs: context.budgetMs ?? 20_000, signal: context.signal,
|
|
51
|
+
recorder: this.options.recorder ?? NOOP_RECORDER }, [
|
|
52
|
+
{ id: 'direct', run: ({ signal, remainingMs }) => this.read(number, signal, remainingMs) },
|
|
53
|
+
]);
|
|
54
|
+
}
|
|
55
|
+
async read(number, signal, budgetMs) {
|
|
56
|
+
const deadline = performance.now() + budgetMs;
|
|
57
|
+
const timeoutMs = () => Math.max(1, Math.floor(deadline - performance.now()));
|
|
58
|
+
const userAgent = userAgentOf(this.options.userAgent);
|
|
59
|
+
const token = await this.token(userAgent, signal, timeoutMs());
|
|
60
|
+
signal.throwIfAborted();
|
|
61
|
+
try {
|
|
62
|
+
const { response, bytes } = await fetchBounded(GATI_TRACKING_URL, { method: 'POST', signal, headers: {
|
|
63
|
+
Accept: 'application/json', 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, Origin: ORIGIN, 'User-Agent': userAgent,
|
|
64
|
+
}, body: JSON.stringify({ docketNo: number }) }, { provider: PROVIDER, timeoutMs: timeoutMs(), maxBytes: GATI_MAX_BYTES,
|
|
65
|
+
redirect: 'manual', fetcher: this.options.fetcher, allowHttpStatuses: [...REDIRECTS, 401, 403, 404, 410, 422] });
|
|
66
|
+
if (REDIRECTS.includes(response.status))
|
|
67
|
+
throw new TransportError(PROVIDER, 'AllcargoGATI redirected its tracking lookup');
|
|
68
|
+
if (response.status === 404 || response.status === 410)
|
|
69
|
+
throw new TransportError(PROVIDER, 'AllcargoGATI tracking lookup is unavailable');
|
|
70
|
+
// The token was just issued and the origin is the site's own, so a refusal is a changed gate.
|
|
71
|
+
if (response.status === 401 || response.status === 403) {
|
|
72
|
+
throw new ChallengeError(PROVIDER, 'AllcargoGATI refused the tracking page token', { status: response.status });
|
|
73
|
+
}
|
|
74
|
+
// A refused number is HTTP 422 with the reasons, which the parser reads.
|
|
75
|
+
return parseGati(json(bytes), number);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
throw withoutToken(error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** A page token, as the tracking page gets one on every visit; it lasts five minutes. */
|
|
82
|
+
async token(userAgent, signal, timeoutMs) {
|
|
83
|
+
const { response, bytes } = await fetchBounded(GATI_TOKEN_URL, { method: 'POST', signal, headers: {
|
|
84
|
+
Accept: 'application/json', 'Content-Type': 'application/json', Origin: ORIGIN, 'User-Agent': userAgent,
|
|
85
|
+
}, body: '{}' }, { provider: PROVIDER, timeoutMs, maxBytes: 64_000, redirect: 'manual', fetcher: this.options.fetcher,
|
|
86
|
+
allowHttpStatuses: [...REDIRECTS, 404, 410] });
|
|
87
|
+
if (REDIRECTS.includes(response.status) || response.status === 404 || response.status === 410) {
|
|
88
|
+
throw new TransportError(PROVIDER, 'AllcargoGATI tracking page token is unavailable');
|
|
89
|
+
}
|
|
90
|
+
const grant = json(bytes);
|
|
91
|
+
const token = isRecord(grant) && typeof grant.token === 'string' ? grant.token : '';
|
|
92
|
+
if (!TOKEN.test(token) || !isRecord(grant) || String(grant.type).toLowerCase() !== 'bearer') {
|
|
93
|
+
throw new SchemaError(PROVIDER, 'AllcargoGATI did not issue a tracking page token');
|
|
94
|
+
}
|
|
95
|
+
return token;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export const adapter = (environment) => {
|
|
99
|
+
const tracker = new GatiTracker({ fetcher: environment.fetcher, recorder: environment.recorder, userAgent: environment.userAgent });
|
|
100
|
+
return {
|
|
101
|
+
id: 'gati', recordsSteps: true, steps: ['direct'],
|
|
102
|
+
track: (input, context) => tracker.fetch(input.number, context),
|
|
103
|
+
recognize: (number, context) => recognizeFromLookup(() => tracker.fetch(number, context), () => accepted(() => normalizeGatiNumber(number))),
|
|
104
|
+
};
|
|
105
|
+
};
|
|
@@ -22,17 +22,59 @@
|
|
|
22
22
|
"timezone": "Asia/Kolkata",
|
|
23
23
|
"tracking": {
|
|
24
24
|
"mode": "automatic",
|
|
25
|
-
"adapter": "
|
|
26
|
-
"steps": [
|
|
25
|
+
"adapter": "gati",
|
|
26
|
+
"steps": [
|
|
27
|
+
"direct"
|
|
28
|
+
],
|
|
29
|
+
"recognition": {
|
|
30
|
+
"rank": 43
|
|
31
|
+
}
|
|
27
32
|
},
|
|
28
|
-
"capabilities": [
|
|
33
|
+
"capabilities": [
|
|
34
|
+
"history",
|
|
35
|
+
"location",
|
|
36
|
+
"provider_code",
|
|
37
|
+
"delivered_at",
|
|
38
|
+
"eta",
|
|
39
|
+
"weight"
|
|
40
|
+
],
|
|
29
41
|
"portal": {
|
|
30
42
|
"searchUrl": "https://www.allcargologistics.com/track-shipment",
|
|
31
43
|
"canaryUrl": "https://www.allcargologistics.com/track-shipment",
|
|
32
|
-
"shows": [
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
44
|
+
"shows": [
|
|
45
|
+
"status",
|
|
46
|
+
"history",
|
|
47
|
+
"origin",
|
|
48
|
+
"departure_date",
|
|
49
|
+
"destination",
|
|
50
|
+
"delivered_at",
|
|
51
|
+
"eta",
|
|
52
|
+
"recipient_name",
|
|
53
|
+
"remarks",
|
|
54
|
+
"proof_of_delivery"
|
|
55
|
+
],
|
|
56
|
+
"scraped": [
|
|
57
|
+
"status",
|
|
58
|
+
"history",
|
|
59
|
+
"location",
|
|
60
|
+
"provider_code",
|
|
61
|
+
"delivered_at",
|
|
62
|
+
"eta",
|
|
63
|
+
"weight"
|
|
64
|
+
],
|
|
65
|
+
"discarded": [
|
|
66
|
+
"origin",
|
|
67
|
+
"departure_date",
|
|
68
|
+
"destination",
|
|
69
|
+
"recipient_name",
|
|
70
|
+
"remarks",
|
|
71
|
+
"proof_of_delivery"
|
|
72
|
+
],
|
|
73
|
+
"unavailable": [
|
|
74
|
+
"offset_timestamps",
|
|
75
|
+
"pickup_point",
|
|
76
|
+
"delivery_partner"
|
|
77
|
+
]
|
|
36
78
|
},
|
|
37
79
|
"links": [
|
|
38
80
|
{
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"access": "full_page"
|
|
89
89
|
},
|
|
90
90
|
"context": {
|
|
91
|
-
"assessment": "
|
|
91
|
+
"assessment": "confirmed"
|
|
92
92
|
},
|
|
93
93
|
"expect": {
|
|
94
94
|
"carrier": "unknown",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"access": "full_page"
|
|
108
108
|
},
|
|
109
109
|
"context": {
|
|
110
|
-
"assessment": "
|
|
110
|
+
"assessment": "confirmed"
|
|
111
111
|
},
|
|
112
112
|
"expect": {
|
|
113
113
|
"carrier": "unknown",
|
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
"access": "full_page"
|
|
127
127
|
},
|
|
128
128
|
"context": {
|
|
129
|
-
"assessment": "
|
|
129
|
+
"assessment": "confirmed"
|
|
130
130
|
},
|
|
131
131
|
"expect": {
|
|
132
132
|
"carrier": "unknown",
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
"access": "full_page"
|
|
146
146
|
},
|
|
147
147
|
"context": {
|
|
148
|
-
"assessment": "
|
|
148
|
+
"assessment": "confirmed"
|
|
149
149
|
},
|
|
150
150
|
"expect": {
|
|
151
151
|
"carrier": "unknown",
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
"access": "full_page"
|
|
165
165
|
},
|
|
166
166
|
"context": {
|
|
167
|
-
"assessment": "
|
|
167
|
+
"assessment": "confirmed"
|
|
168
168
|
},
|
|
169
169
|
"expect": {
|
|
170
170
|
"carrier": "unknown",
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
"access": "full_page"
|
|
184
184
|
},
|
|
185
185
|
"context": {
|
|
186
|
-
"assessment": "
|
|
186
|
+
"assessment": "confirmed"
|
|
187
187
|
},
|
|
188
188
|
"expect": {
|
|
189
189
|
"carrier": "unknown",
|
|
@@ -202,7 +202,7 @@
|
|
|
202
202
|
"access": "full_page"
|
|
203
203
|
},
|
|
204
204
|
"context": {
|
|
205
|
-
"assessment": "
|
|
205
|
+
"assessment": "confirmed"
|
|
206
206
|
},
|
|
207
207
|
"expect": {
|
|
208
208
|
"carrier": "unknown",
|
|
@@ -247,6 +247,66 @@
|
|
|
247
247
|
"confidence": "none"
|
|
248
248
|
},
|
|
249
249
|
"note": "A customer review on TrackingMore's GATI Courier review page asks for delivery of this number."
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"number": "412933252",
|
|
253
|
+
"role": "shipment",
|
|
254
|
+
"evidence": "public_shipment_report",
|
|
255
|
+
"source": {
|
|
256
|
+
"url": "https://www.trackingmore.com/review-gati-kwe.html",
|
|
257
|
+
"date": "2021-11-15",
|
|
258
|
+
"dateKind": "comment",
|
|
259
|
+
"access": "full_page"
|
|
260
|
+
},
|
|
261
|
+
"context": {
|
|
262
|
+
"assessment": "confirmed"
|
|
263
|
+
},
|
|
264
|
+
"expect": {
|
|
265
|
+
"carrier": "unknown",
|
|
266
|
+
"confidence": "low",
|
|
267
|
+
"candidates": [
|
|
268
|
+
"tnt"
|
|
269
|
+
]
|
|
270
|
+
},
|
|
271
|
+
"note": "A customer review on TrackingMore's Gati KWE review page asks where the courier with this number is."
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"number": "988397715",
|
|
275
|
+
"role": "shipment",
|
|
276
|
+
"evidence": "public_shipment_report",
|
|
277
|
+
"source": {
|
|
278
|
+
"url": "https://www.trackingmore.com/review-gati-kwe.html",
|
|
279
|
+
"date": "2021-09-03",
|
|
280
|
+
"dateKind": "comment",
|
|
281
|
+
"access": "full_page"
|
|
282
|
+
},
|
|
283
|
+
"context": {
|
|
284
|
+
"assessment": "candidate"
|
|
285
|
+
},
|
|
286
|
+
"expect": {
|
|
287
|
+
"carrier": "unknown",
|
|
288
|
+
"confidence": "none"
|
|
289
|
+
},
|
|
290
|
+
"note": "A customer review on TrackingMore's Gati KWE review page gives it as a Gati courier number."
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"number": "139815455",
|
|
294
|
+
"role": "shipment",
|
|
295
|
+
"evidence": "public_shipment_report",
|
|
296
|
+
"source": {
|
|
297
|
+
"url": "https://www.trackingmore.com/review-gaticn.html",
|
|
298
|
+
"date": "2020-12-16",
|
|
299
|
+
"dateKind": "comment",
|
|
300
|
+
"access": "full_page"
|
|
301
|
+
},
|
|
302
|
+
"context": {
|
|
303
|
+
"assessment": "confirmed"
|
|
304
|
+
},
|
|
305
|
+
"expect": {
|
|
306
|
+
"carrier": "unknown",
|
|
307
|
+
"confidence": "none"
|
|
308
|
+
},
|
|
309
|
+
"note": "A customer review on TrackingMore's GATI Courier review page gives it as the docket of a shipment that arrived on time."
|
|
250
310
|
}
|
|
251
311
|
]
|
|
252
312
|
}
|