universal-parcel-scraper 0.157.0-main.1229 → 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 +38 -9
- package/data/coverage-summary.json +1 -1
- package/data/detection-golden.json +132 -0
- package/dist/browser/scraper.js +31 -10
- 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/jne/adapter.d.ts +15 -0
- package/dist/carriers/jne/adapter.js +80 -0
- package/dist/carriers/jne/carrier.json +49 -9
- package/dist/carriers/jne/parser.d.ts +21 -0
- package/dist/carriers/jne/parser.js +133 -0
- package/dist/carriers/jne/status.d.ts +7 -0
- package/dist/carriers/jne/status.js +53 -0
- package/dist/carriers/jne/statuses.json +5 -1
- package/dist/carriers/loggi/statuses.json +8 -4
- 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 +9 -4
- package/dist/data/catalog.json +38 -9
- package/dist/generated/catalog.d.ts +27 -9
- package/dist/generated/catalog.js +39 -10
- package/dist/generated/recognition.js +3 -0
- package/dist/generated/registry.js +12 -4
- 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",
|
|
@@ -10167,10 +10168,11 @@
|
|
|
10167
10168
|
"timezone": "Asia/Jakarta",
|
|
10168
10169
|
"tracking": {
|
|
10169
10170
|
"mode": "automatic",
|
|
10170
|
-
"adapter": "
|
|
10171
|
+
"adapter": "jne",
|
|
10172
|
+
"localClocks": true
|
|
10171
10173
|
},
|
|
10172
|
-
"canaryUrl": "https://www.jne.co.id/",
|
|
10173
|
-
"trackingSearchUrl": "https://www.jne.co.id/",
|
|
10174
|
+
"canaryUrl": "https://www.jne.co.id/tracking-package",
|
|
10175
|
+
"trackingSearchUrl": "https://www.jne.co.id/tracking-package",
|
|
10174
10176
|
"linkRules": [],
|
|
10175
10177
|
"detectionRules": [
|
|
10176
10178
|
{
|
|
@@ -13036,7 +13038,8 @@
|
|
|
13036
13038
|
"timezone": "Asia/Kolkata",
|
|
13037
13039
|
"tracking": {
|
|
13038
13040
|
"mode": "automatic",
|
|
13039
|
-
"adapter": "
|
|
13041
|
+
"adapter": "shadowfax",
|
|
13042
|
+
"recognitionRank": 595
|
|
13040
13043
|
},
|
|
13041
13044
|
"canaryUrl": "https://www.shadowfax.in/track",
|
|
13042
13045
|
"trackingUrlTemplate": "https://tracker.shadowfax.in/#/awb/{trackingNumber}",
|
|
@@ -14042,11 +14045,37 @@
|
|
|
14042
14045
|
"timezone": "America/Sao_Paulo",
|
|
14043
14046
|
"tracking": {
|
|
14044
14047
|
"mode": "automatic",
|
|
14045
|
-
"adapter": "
|
|
14048
|
+
"adapter": "total-express",
|
|
14049
|
+
"recognitionRank": 975,
|
|
14050
|
+
"localClocks": true
|
|
14046
14051
|
},
|
|
14047
|
-
"canaryUrl": "https://totalexpress.com.br/
|
|
14048
|
-
"
|
|
14049
|
-
"
|
|
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
|
+
]
|
|
14050
14079
|
},
|
|
14051
14080
|
"trackon": {
|
|
14052
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",
|
|
@@ -7869,10 +7870,11 @@ var Ae = {
|
|
|
7869
7870
|
timezone: "Asia/Jakarta",
|
|
7870
7871
|
tracking: {
|
|
7871
7872
|
mode: "automatic",
|
|
7872
|
-
adapter: "
|
|
7873
|
+
adapter: "jne",
|
|
7874
|
+
localClocks: !0
|
|
7873
7875
|
},
|
|
7874
|
-
canaryUrl: "https://www.jne.co.id/",
|
|
7875
|
-
trackingSearchUrl: "https://www.jne.co.id/",
|
|
7876
|
+
canaryUrl: "https://www.jne.co.id/tracking-package",
|
|
7877
|
+
trackingSearchUrl: "https://www.jne.co.id/tracking-package",
|
|
7876
7878
|
linkRules: [],
|
|
7877
7879
|
detectionRules: [{
|
|
7878
7880
|
pattern: "^JT\\d{11}$",
|
|
@@ -10042,7 +10044,8 @@ var Ae = {
|
|
|
10042
10044
|
timezone: "Asia/Kolkata",
|
|
10043
10045
|
tracking: {
|
|
10044
10046
|
mode: "automatic",
|
|
10045
|
-
adapter: "
|
|
10047
|
+
adapter: "shadowfax",
|
|
10048
|
+
recognitionRank: 595
|
|
10046
10049
|
},
|
|
10047
10050
|
canaryUrl: "https://www.shadowfax.in/track",
|
|
10048
10051
|
trackingUrlTemplate: "https://tracker.shadowfax.in/#/awb/{trackingNumber}",
|
|
@@ -10761,11 +10764,26 @@ var Ae = {
|
|
|
10761
10764
|
timezone: "America/Sao_Paulo",
|
|
10762
10765
|
tracking: {
|
|
10763
10766
|
mode: "automatic",
|
|
10764
|
-
adapter: "
|
|
10767
|
+
adapter: "total-express",
|
|
10768
|
+
recognitionRank: 975,
|
|
10769
|
+
localClocks: !0
|
|
10765
10770
|
},
|
|
10766
|
-
canaryUrl: "https://totalexpress.com.br/
|
|
10767
|
-
|
|
10768
|
-
|
|
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
|
+
}]
|
|
10769
10787
|
},
|
|
10770
10788
|
trackon: {
|
|
10771
10789
|
displayName: "Trackon Couriers",
|
|
@@ -11964,7 +11982,7 @@ var Ae = {
|
|
|
11964
11982
|
"tforce-freight": [],
|
|
11965
11983
|
thhy: ["thhy-1"],
|
|
11966
11984
|
toptrans: [],
|
|
11967
|
-
"total-express": [],
|
|
11985
|
+
"total-express": ["total-express-awb"],
|
|
11968
11986
|
trackon: [],
|
|
11969
11987
|
"trans-o-flex": [],
|
|
11970
11988
|
"trendyol-express": [],
|
|
@@ -17117,6 +17135,7 @@ var nl = {
|
|
|
17117
17135
|
"fan-courier": 330,
|
|
17118
17136
|
"four-px": 570,
|
|
17119
17137
|
foxpost: 200,
|
|
17138
|
+
gati: 43,
|
|
17120
17139
|
geis: 90,
|
|
17121
17140
|
"geniki-taxydromiki": 140,
|
|
17122
17141
|
"geodis-pl": 994,
|
|
@@ -17177,6 +17196,7 @@ var nl = {
|
|
|
17177
17196
|
saia: 12,
|
|
17178
17197
|
sameday: 370,
|
|
17179
17198
|
seur: 870,
|
|
17199
|
+
shadowfax: 595,
|
|
17180
17200
|
"slovak-parcel-service": 180,
|
|
17181
17201
|
"slovenska-posta": 170,
|
|
17182
17202
|
speedaf: 989,
|
|
@@ -17188,6 +17208,7 @@ var nl = {
|
|
|
17188
17208
|
thhy: 987,
|
|
17189
17209
|
tipsa: 680,
|
|
17190
17210
|
tnt: 880,
|
|
17211
|
+
"total-express": 975,
|
|
17191
17212
|
tsjy: 992,
|
|
17192
17213
|
"ubi-smart-parcel": 45,
|
|
17193
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
|
{
|