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.
Files changed (49) hide show
  1. package/README.md +2 -2
  2. package/data/catalog.json +38 -9
  3. package/data/coverage-summary.json +1 -1
  4. package/data/detection-golden.json +132 -0
  5. package/dist/browser/scraper.js +31 -10
  6. package/dist/carriers/gati/adapter.d.ts +20 -0
  7. package/dist/carriers/gati/adapter.js +105 -0
  8. package/dist/carriers/gati/carrier.json +49 -7
  9. package/dist/carriers/gati/numbers.json +67 -7
  10. package/dist/carriers/gati/parser.d.ts +13 -0
  11. package/dist/carriers/gati/parser.js +173 -0
  12. package/dist/carriers/gati/status.d.ts +7 -0
  13. package/dist/carriers/gati/status.js +37 -0
  14. package/dist/carriers/gati/statuses.json +12 -1
  15. package/dist/carriers/jne/adapter.d.ts +15 -0
  16. package/dist/carriers/jne/adapter.js +80 -0
  17. package/dist/carriers/jne/carrier.json +49 -9
  18. package/dist/carriers/jne/parser.d.ts +21 -0
  19. package/dist/carriers/jne/parser.js +133 -0
  20. package/dist/carriers/jne/status.d.ts +7 -0
  21. package/dist/carriers/jne/status.js +53 -0
  22. package/dist/carriers/jne/statuses.json +5 -1
  23. package/dist/carriers/loggi/statuses.json +8 -4
  24. package/dist/carriers/shadowfax/adapter.d.ts +19 -0
  25. package/dist/carriers/shadowfax/adapter.js +93 -0
  26. package/dist/carriers/shadowfax/carrier.json +55 -7
  27. package/dist/carriers/shadowfax/numbers.json +144 -8
  28. package/dist/carriers/shadowfax/parser.d.ts +28 -0
  29. package/dist/carriers/shadowfax/parser.js +206 -0
  30. package/dist/carriers/shadowfax/status.d.ts +12 -0
  31. package/dist/carriers/shadowfax/status.js +77 -0
  32. package/dist/carriers/shadowfax/statuses.json +16 -1
  33. package/dist/carriers/total-express/adapter.d.ts +15 -0
  34. package/dist/carriers/total-express/adapter.js +85 -0
  35. package/dist/carriers/total-express/carrier.json +81 -10
  36. package/dist/carriers/total-express/numbers.json +115 -1
  37. package/dist/carriers/total-express/parser.d.ts +24 -0
  38. package/dist/carriers/total-express/parser.js +195 -0
  39. package/dist/carriers/total-express/status.d.ts +7 -0
  40. package/dist/carriers/total-express/status.js +138 -0
  41. package/dist/carriers/total-express/statuses.json +101 -7
  42. package/dist/core/catalog/statusMaps.js +9 -4
  43. package/dist/data/catalog.json +38 -9
  44. package/dist/generated/catalog.d.ts +27 -9
  45. package/dist/generated/catalog.js +39 -10
  46. package/dist/generated/recognition.js +3 -0
  47. package/dist/generated/registry.js +12 -4
  48. package/dist/server/openapi.json +1 -1
  49. 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: Apache-2.0](https://img.shields.io/badge/core-Apache--2.0-blue.svg)](LICENSE)
14
14
 
15
15
  <!-- GENERATED:summary -->
16
- **3,500+ carriers** through **217 dedicated adapters** and **5 universal fallbacks**
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,634 such statuses, each filed under one stage.
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": "universal"
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": "universal"
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": "universal"
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": "universal"
14048
+ "adapter": "total-express",
14049
+ "recognitionRank": 975,
14050
+ "localClocks": true
14046
14051
  },
14047
- "canaryUrl": "https://totalexpress.com.br/rastrear-um-produto/",
14048
- "linkRules": [],
14049
- "detectionRules": []
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",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "catalog": 358,
3
- "activeAdapters": 217,
3
+ "activeAdapters": 221,
4
4
  "countries": 91,
5
5
  "referenceCarriers": 100,
6
6
  "comparison": {
@@ -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",
@@ -6903,7 +6903,8 @@ var Ae = {
6903
6903
  timezone: "Asia/Kolkata",
6904
6904
  tracking: {
6905
6905
  mode: "automatic",
6906
- adapter: "universal"
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: "universal"
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: "universal"
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: "universal"
10767
+ adapter: "total-express",
10768
+ recognitionRank: 975,
10769
+ localClocks: !0
10765
10770
  },
10766
- canaryUrl: "https://totalexpress.com.br/rastrear-um-produto/",
10767
- linkRules: [],
10768
- detectionRules: []
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": "universal",
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
- "scraped": [],
34
- "discarded": [],
35
- "unavailable": []
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
  {