universal-parcel-scraper 0.372.0-main.2012 → 0.374.0-main.2018

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 (38) hide show
  1. package/README.md +2 -2
  2. package/data/catalog.json +25 -5
  3. package/data/coverage-summary.json +1 -1
  4. package/data/detection-golden.json +18 -0
  5. package/dist/browser/scraper.js +32 -14
  6. package/dist/carriers/posta-shqiptare/adapter.d.ts +15 -0
  7. package/dist/carriers/posta-shqiptare/adapter.js +73 -0
  8. package/dist/carriers/posta-shqiptare/carrier.json +42 -8
  9. package/dist/carriers/posta-shqiptare/numbers.json +32 -12
  10. package/dist/carriers/posta-shqiptare/parser.d.ts +14 -0
  11. package/dist/carriers/posta-shqiptare/parser.js +150 -0
  12. package/dist/carriers/posta-shqiptare/status.d.ts +11 -0
  13. package/dist/carriers/posta-shqiptare/status.js +53 -0
  14. package/dist/carriers/posta-shqiptare/statuses.json +15 -1
  15. package/dist/carriers/urbano/adapter.d.ts +17 -0
  16. package/dist/carriers/urbano/adapter.js +66 -0
  17. package/dist/carriers/urbano/carrier.json +73 -7
  18. package/dist/carriers/urbano/parser.d.ts +17 -0
  19. package/dist/carriers/urbano/parser.js +227 -0
  20. package/dist/carriers/urbano/status.d.ts +9 -0
  21. package/dist/carriers/urbano/status.js +45 -0
  22. package/dist/carriers/urbano/statuses.json +9 -0
  23. package/dist/carriers/zajil/adapter.d.ts +15 -0
  24. package/dist/carriers/zajil/adapter.js +70 -0
  25. package/dist/carriers/zajil/carrier.json +42 -7
  26. package/dist/carriers/zajil/parser.d.ts +18 -0
  27. package/dist/carriers/zajil/parser.js +149 -0
  28. package/dist/carriers/zajil/status.d.ts +7 -0
  29. package/dist/carriers/zajil/status.js +39 -0
  30. package/dist/carriers/zajil/statuses.json +16 -3
  31. package/dist/core/catalog/statusMaps.js +6 -2
  32. package/dist/data/catalog.json +25 -5
  33. package/dist/generated/catalog.d.ts +18 -5
  34. package/dist/generated/catalog.js +26 -6
  35. package/dist/generated/recognition.js +1 -0
  36. package/dist/generated/registry.js +9 -3
  37. package/dist/server/openapi.json +1 -1
  38. 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 **402 dedicated adapters** and **5 universal fallbacks**
16
+ **3,500+ carriers** through **405 dedicated adapters** and **5 universal fallbacks**
17
17
 
18
18
  <sub>727 catalog entries · 133 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 13,584 such statuses, each filed under one stage.
158
+ The carrier folders record 13,619 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
@@ -22117,9 +22117,11 @@
22117
22117
  "timezone": "Europe/Tirane",
22118
22118
  "tracking": {
22119
22119
  "mode": "automatic",
22120
- "adapter": "universal"
22120
+ "adapter": "posta-shqiptare",
22121
+ "recognitionRank": 829,
22122
+ "localClocks": true
22121
22123
  },
22122
- "canaryUrl": "https://www.postashqiptare.al/c/207/tracked",
22124
+ "canaryUrl": "https://eposta.postashqiptare.al/tracking",
22123
22125
  "trackingUrlTemplate": "https://eposta.postashqiptare.al/tracking/{trackingNumber}",
22124
22126
  "trackingSearchUrl": "https://www.postashqiptare.al/c/207/tracked",
22125
22127
  "linkRules": [
@@ -22130,7 +22132,14 @@
22130
22132
  "path": "^/tracking/([^/?#]+)/?$"
22131
22133
  }
22132
22134
  ],
22133
- "detectionRules": []
22135
+ "detectionRules": [
22136
+ {
22137
+ "pattern": "^[A-Z]{2}\\d{9}AL$",
22138
+ "confidence": "low",
22139
+ "checksum": "s10",
22140
+ "preferred": true
22141
+ }
22142
+ ]
22134
22143
  },
22135
22144
  "posta-slovenije": {
22136
22145
  "displayName": "Pošta Slovenije",
@@ -27560,7 +27569,8 @@
27560
27569
  "timezone": "America/Lima",
27561
27570
  "tracking": {
27562
27571
  "mode": "automatic",
27563
- "adapter": "universal"
27572
+ "adapter": "urbano",
27573
+ "localClocks": true
27564
27574
  },
27565
27575
  "canaryUrl": "https://www.urbano.com.pe/tracking/",
27566
27576
  "trackingUrlTemplate": "https://www.urbano.com.pe/tracking/{trackingNumber}",
@@ -27572,6 +27582,15 @@
27572
27582
  ],
27573
27583
  "path": "^/tracking/([^/?#]+)/?$"
27574
27584
  },
27585
+ {
27586
+ "domains": [
27587
+ "urbano.com.pe"
27588
+ ],
27589
+ "pathPattern": "^/tracking/?$",
27590
+ "params": [
27591
+ "guides"
27592
+ ]
27593
+ },
27575
27594
  {
27576
27595
  "domains": [
27577
27596
  "app.urbano.com.pe",
@@ -28760,7 +28779,8 @@
28760
28779
  "timezone": "Asia/Riyadh",
28761
28780
  "tracking": {
28762
28781
  "mode": "automatic",
28763
- "adapter": "universal"
28782
+ "adapter": "zajil",
28783
+ "localClocks": true
28764
28784
  },
28765
28785
  "canaryUrl": "https://zajil-express.com/track",
28766
28786
  "trackingUrlTemplate": "https://zajil-express.com/track?tracking_id={trackingNumber}",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "catalog": 727,
3
- "activeAdapters": 402,
3
+ "activeAdapters": 405,
4
4
  "countries": 133,
5
5
  "referenceCarriers": 100,
6
6
  "comparison": {
@@ -64492,6 +64492,7 @@
64492
64492
  "intl-post"
64493
64493
  ],
64494
64494
  "asked": [
64495
+ "posta-shqiptare",
64495
64496
  "chronopost"
64496
64497
  ]
64497
64498
  },
@@ -64562,6 +64563,7 @@
64562
64563
  "intl-post"
64563
64564
  ],
64564
64565
  "asked": [
64566
+ "posta-shqiptare",
64565
64567
  "chronopost"
64566
64568
  ]
64567
64569
  },
@@ -67006,6 +67008,19 @@
67006
67008
  "intl-post"
67007
67009
  ],
67008
67010
  "asked": [
67011
+ "posta-shqiptare",
67012
+ "chronopost"
67013
+ ]
67014
+ },
67015
+ {
67016
+ "input": "EE200190512AL",
67017
+ "carrier": "intl-post",
67018
+ "confidence": "high",
67019
+ "candidates": [
67020
+ "intl-post"
67021
+ ],
67022
+ "asked": [
67023
+ "posta-shqiptare",
67009
67024
  "chronopost"
67010
67025
  ]
67011
67026
  },
@@ -73651,6 +73666,7 @@
73651
73666
  "intl-post"
73652
73667
  ],
73653
73668
  "asked": [
73669
+ "posta-shqiptare",
73654
73670
  "chronopost"
73655
73671
  ]
73656
73672
  },
@@ -73662,6 +73678,7 @@
73662
73678
  "intl-post"
73663
73679
  ],
73664
73680
  "asked": [
73681
+ "posta-shqiptare",
73665
73682
  "chronopost"
73666
73683
  ]
73667
73684
  },
@@ -73673,6 +73690,7 @@
73673
73690
  "intl-post"
73674
73691
  ],
73675
73692
  "asked": [
73693
+ "posta-shqiptare",
73676
73694
  "chronopost"
73677
73695
  ]
73678
73696
  },
@@ -16778,16 +16778,23 @@ var Pe = {
16778
16778
  timezone: "Europe/Tirane",
16779
16779
  tracking: {
16780
16780
  mode: "automatic",
16781
- adapter: "universal"
16781
+ adapter: "posta-shqiptare",
16782
+ recognitionRank: 829,
16783
+ localClocks: !0
16782
16784
  },
16783
- canaryUrl: "https://www.postashqiptare.al/c/207/tracked",
16785
+ canaryUrl: "https://eposta.postashqiptare.al/tracking",
16784
16786
  trackingUrlTemplate: "https://eposta.postashqiptare.al/tracking/{trackingNumber}",
16785
16787
  trackingSearchUrl: "https://www.postashqiptare.al/c/207/tracked",
16786
16788
  linkRules: [{
16787
16789
  domains: ["eposta.postashqiptare.al"],
16788
16790
  path: "^/tracking/([^/?#]+)/?$"
16789
16791
  }],
16790
- detectionRules: []
16792
+ detectionRules: [{
16793
+ pattern: "^[A-Z]{2}\\d{9}AL$",
16794
+ confidence: "low",
16795
+ checksum: "s10",
16796
+ preferred: !0
16797
+ }]
16791
16798
  },
16792
16799
  "posta-slovenije": {
16793
16800
  displayName: "Pošta Slovenije",
@@ -20742,19 +20749,28 @@ var Pe = {
20742
20749
  timezone: "America/Lima",
20743
20750
  tracking: {
20744
20751
  mode: "automatic",
20745
- adapter: "universal"
20752
+ adapter: "urbano",
20753
+ localClocks: !0
20746
20754
  },
20747
20755
  canaryUrl: "https://www.urbano.com.pe/tracking/",
20748
20756
  trackingUrlTemplate: "https://www.urbano.com.pe/tracking/{trackingNumber}",
20749
20757
  trackingSearchUrl: "https://www.urbano.com.pe/tracking/",
20750
- linkRules: [{
20751
- domains: ["urbano.com.pe"],
20752
- path: "^/tracking/([^/?#]+)/?$"
20753
- }, {
20754
- domains: ["app.urbano.com.pe", "api.urbano.com.pe"],
20755
- pathPattern: "^/plugin/etracking/etracking/?$",
20756
- params: ["guia"]
20757
- }],
20758
+ linkRules: [
20759
+ {
20760
+ domains: ["urbano.com.pe"],
20761
+ path: "^/tracking/([^/?#]+)/?$"
20762
+ },
20763
+ {
20764
+ domains: ["urbano.com.pe"],
20765
+ pathPattern: "^/tracking/?$",
20766
+ params: ["guides"]
20767
+ },
20768
+ {
20769
+ domains: ["app.urbano.com.pe", "api.urbano.com.pe"],
20770
+ pathPattern: "^/plugin/etracking/etracking/?$",
20771
+ params: ["guia"]
20772
+ }
20773
+ ],
20758
20774
  detectionRules: [{
20759
20775
  pattern: "^G\\d{8}$",
20760
20776
  confidence: "low"
@@ -21634,7 +21650,8 @@ var Pe = {
21634
21650
  timezone: "Asia/Riyadh",
21635
21651
  tracking: {
21636
21652
  mode: "automatic",
21637
- adapter: "universal"
21653
+ adapter: "zajil",
21654
+ localClocks: !0
21638
21655
  },
21639
21656
  canaryUrl: "https://zajil-express.com/track",
21640
21657
  trackingUrlTemplate: "https://zajil-express.com/track?tracking_id={trackingNumber}",
@@ -22638,7 +22655,7 @@ var Pe = {
22638
22655
  "posta-moldovei": ["posta-moldovei-1"],
22639
22656
  "posta-north-macedonia": ["posta-north-macedonia-s10"],
22640
22657
  "posta-romana": ["posta-romana-s10"],
22641
- "posta-shqiptare": [],
22658
+ "posta-shqiptare": ["posta-shqiptare-s10"],
22642
22659
  "posta-slovenije": ["posta-slovenije-s10"],
22643
22660
  "posta-srbije": ["posta-srbije-s10"],
22644
22661
  postaplus: [],
@@ -28158,6 +28175,7 @@ var pl = {
28158
28175
  "post-luxembourg": 80,
28159
28176
  "posta-north-macedonia": 899,
28160
28177
  "posta-romana": 948,
28178
+ "posta-shqiptare": 829,
28161
28179
  "posta-slovenije": 130,
28162
28180
  "posta-srbije": 110,
28163
28181
  "poste-italiane": 900,
@@ -0,0 +1,15 @@
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 lookup the e-Posta tracking page makes, with the item's code as the last part of the address. */
5
+ export declare const POSTA_SHQIPTARE_API = "https://eposta.postashqiptare.al:8443/api/mailItemEvents/getTrackApi";
6
+ export declare class PostaShqiptareTracker {
7
+ private readonly options;
8
+ constructor(options?: {
9
+ fetcher?: typeof fetch;
10
+ recorder?: StepRecorder;
11
+ userAgent?: string;
12
+ });
13
+ fetch(raw: string, context?: TrackingContext): Promise<CarrierResult>;
14
+ }
15
+ export declare const adapter: AdapterFactory;
@@ -0,0 +1,73 @@
1
+ import { accepted, recognizeFromLookup } from '../../core/adapter/index.js';
2
+ import { ChallengeError, IndeterminateError, NotFoundError, SchemaError, TransportError } from '../../core/errors/index.js';
3
+ import { runSteps } from '../../core/runner/index.js';
4
+ import { firstAttemptMs, networkRetryStep } from '../../core/runner/networkRetry.js';
5
+ import { NOOP_RECORDER } from '../../core/telemetry/index.js';
6
+ import { decodeText, fetchBounded, userAgentOf } from '../../core/transport/index.js';
7
+ import { normalizePostaShqiptareNumber, parsePostaShqiptare, POSTA_SHQIPTARE_MAX_BYTES, PROVIDER } from './parser.js';
8
+ /** The lookup the e-Posta tracking page makes, with the item's code as the last part of the address. */
9
+ export const POSTA_SHQIPTARE_API = 'https://eposta.postashqiptare.al:8443/api/mailItemEvents/getTrackApi';
10
+ const REDIRECTS = [301, 302, 303, 307, 308];
11
+ // Bot checks a CDN or firewall could put in place of the reply.
12
+ const CHALLENGE = /_cf_chl_opt|cf-turnstile|challenge-platform|<title>\s*(?:Just a moment|Attention Required|Request Rejected|Access Denied)|requested URL was rejected/i;
13
+ function json(body) {
14
+ try {
15
+ return JSON.parse(body);
16
+ }
17
+ catch (cause) {
18
+ if (CHALLENGE.test(body.slice(0, 64_000)))
19
+ throw new ChallengeError(PROVIDER, 'Posta Shqiptare answered with a browser check', { cause });
20
+ throw new SchemaError(PROVIDER, 'Posta Shqiptare returned a reply that is not JSON', { cause });
21
+ }
22
+ }
23
+ /** Whether an error reply is the page's own notice for a missing item. */
24
+ function missing(body) {
25
+ try {
26
+ return JSON.parse(body) === 'package_not_found';
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ export class PostaShqiptareTracker {
33
+ options;
34
+ constructor(options = {}) {
35
+ this.options = options;
36
+ }
37
+ async fetch(raw, context = {}) {
38
+ const number = normalizePostaShqiptareNumber(raw);
39
+ const read = async (signal, timeoutMs) => {
40
+ const { response, bytes } = await fetchBounded(`${POSTA_SHQIPTARE_API}/${number}`, { method: 'GET', signal, headers: {
41
+ Accept: 'application/json', 'User-Agent': userAgentOf(this.options.userAgent),
42
+ } }, { provider: PROVIDER, timeoutMs: Math.max(1, Math.floor(timeoutMs)), maxBytes: POSTA_SHQIPTARE_MAX_BYTES,
43
+ redirect: 'manual', fetcher: this.options.fetcher, allowHttpStatuses: [...REDIRECTS, 400, 404, 410] });
44
+ if (REDIRECTS.includes(response.status))
45
+ throw new TransportError(PROVIDER, 'Posta Shqiptare redirected its tracking lookup');
46
+ const body = decodeText(bytes);
47
+ if (response.status !== 200) {
48
+ if (response.status !== 410 && missing(body))
49
+ throw new NotFoundError(PROVIDER);
50
+ // The tracker answers an unknown code with HTTP 200; a 404 is a moved route.
51
+ if (response.status === 400)
52
+ throw new IndeterminateError(PROVIDER, 'Posta Shqiptare refused the lookup');
53
+ throw new TransportError(PROVIDER, 'Posta Shqiptare tracking lookup is unavailable');
54
+ }
55
+ return parsePostaShqiptare(json(body), number);
56
+ };
57
+ // A request that fails to reach the tracker, or hangs, gets one more try: the
58
+ // first gets half of the budget, so the retry fits in the rest.
59
+ return runSteps({ carrier: 'posta-shqiptare', budgetMs: context.budgetMs ?? 15_000, signal: context.signal,
60
+ recorder: this.options.recorder ?? NOOP_RECORDER }, [
61
+ { id: 'direct', run: ({ signal, remainingMs }) => read(signal, firstAttemptMs(remainingMs)) },
62
+ networkRetryStep(({ signal, remainingMs }) => read(signal, remainingMs)),
63
+ ]);
64
+ }
65
+ }
66
+ export const adapter = (environment) => {
67
+ const tracker = new PostaShqiptareTracker({ fetcher: environment.fetcher, recorder: environment.recorder, userAgent: environment.userAgent });
68
+ return {
69
+ id: 'posta-shqiptare', recordsSteps: true, steps: ['direct', 'retry'],
70
+ track: (input, context) => tracker.fetch(input.number, context),
71
+ recognize: (number, context) => recognizeFromLookup(() => tracker.fetch(number, context), () => accepted(() => normalizePostaShqiptareNumber(number))),
72
+ };
73
+ };
@@ -19,18 +19,44 @@
19
19
  "timezone": "Europe/Tirane",
20
20
  "tracking": {
21
21
  "mode": "automatic",
22
- "adapter": "universal",
23
- "steps": []
22
+ "adapter": "posta-shqiptare",
23
+ "steps": [
24
+ "direct",
25
+ "retry"
26
+ ],
27
+ "recognition": {
28
+ "rank": 829
29
+ },
30
+ "localClocks": true
24
31
  },
25
- "capabilities": [],
32
+ "capabilities": [
33
+ "history",
34
+ "location"
35
+ ],
26
36
  "portal": {
27
37
  "url": "https://eposta.postashqiptare.al/tracking/{trackingNumber}",
28
38
  "searchUrl": "https://www.postashqiptare.al/c/207/tracked",
29
- "canaryUrl": "https://www.postashqiptare.al/c/207/tracked",
30
- "shows": [],
31
- "scraped": [],
39
+ "canaryUrl": "https://eposta.postashqiptare.al/tracking",
40
+ "shows": [
41
+ "status",
42
+ "history",
43
+ "location"
44
+ ],
45
+ "scraped": [
46
+ "status",
47
+ "history",
48
+ "location"
49
+ ],
32
50
  "discarded": [],
33
- "unavailable": []
51
+ "unavailable": [
52
+ "eta",
53
+ "weight",
54
+ "service_name",
55
+ "pickup_point",
56
+ "offset_timestamps",
57
+ "proof_of_delivery",
58
+ "delivery_tracking_number"
59
+ ]
34
60
  },
35
61
  "links": [
36
62
  {
@@ -40,5 +66,13 @@
40
66
  "path": "^/tracking/([^/?#]+)/?$"
41
67
  }
42
68
  ],
43
- "detection": []
69
+ "detection": [
70
+ {
71
+ "id": "posta-shqiptare-s10",
72
+ "pattern": "^[A-Z]{2}\\d{9}AL$",
73
+ "confidence": "low",
74
+ "preferred": true,
75
+ "checksum": "s10"
76
+ }
77
+ ]
44
78
  }
@@ -12,13 +12,13 @@
12
12
  "access": "indexed_excerpt"
13
13
  },
14
14
  "context": {
15
- "assessment": "candidate"
15
+ "assessment": "confirmed"
16
16
  },
17
17
  "expect": {
18
18
  "carrier": "intl-post",
19
19
  "confidence": "high"
20
20
  },
21
- "note": "Looked up on Posta Shqiptare's e-Posta tracker; the opened capture holds only the app shell, which loads the history by script."
21
+ "note": "Looked up on Posta Shqiptare's e-Posta tracker; the opened capture holds only the app shell, which loads the history by script. Posta Shqiptare's own tracker returns its history. Detection selects the generic postal carrier."
22
22
  },
23
23
  {
24
24
  "number": "EE200190509AL",
@@ -30,13 +30,13 @@
30
30
  },
31
31
  "context": {
32
32
  "service": "EMS",
33
- "assessment": "candidate"
33
+ "assessment": "confirmed"
34
34
  },
35
35
  "expect": {
36
36
  "carrier": "intl-post",
37
37
  "confidence": "high"
38
38
  },
39
- "note": "ParcelPanel's Albania Post page offered it as a sample to try; it is not described as a live shipment."
39
+ "note": "ParcelPanel's Albania Post page offered it as a sample to try; Posta Shqiptare's own tracker returns its history. Detection selects the generic postal carrier."
40
40
  },
41
41
  {
42
42
  "number": "CP339538880AL",
@@ -48,13 +48,13 @@
48
48
  },
49
49
  "context": {
50
50
  "service": "Parcel",
51
- "assessment": "candidate"
51
+ "assessment": "confirmed"
52
52
  },
53
53
  "expect": {
54
54
  "carrier": "intl-post",
55
55
  "confidence": "high"
56
56
  },
57
- "note": "ParcelPanel's Albania Post page offered it as a sample to try; it is not described as a live shipment."
57
+ "note": "ParcelPanel's Albania Post page offered it as a sample to try; Posta Shqiptare's own tracker returns its history. Detection selects the generic postal carrier."
58
58
  },
59
59
  {
60
60
  "number": "LG014636582AL",
@@ -65,13 +65,13 @@
65
65
  "access": "full_page"
66
66
  },
67
67
  "context": {
68
- "assessment": "candidate"
68
+ "assessment": "confirmed"
69
69
  },
70
70
  "expect": {
71
71
  "carrier": "intl-post",
72
72
  "confidence": "high"
73
73
  },
74
- "note": "ParcelPanel's Albania Post page offered it as a sample to try; it is not described as a live shipment."
74
+ "note": "ParcelPanel's Albania Post page offered it as a sample to try; Posta Shqiptare's own tracker returns its history. Detection selects the generic postal carrier."
75
75
  },
76
76
  {
77
77
  "number": "LG014771021AL",
@@ -82,13 +82,13 @@
82
82
  "access": "full_page"
83
83
  },
84
84
  "context": {
85
- "assessment": "candidate"
85
+ "assessment": "confirmed"
86
86
  },
87
87
  "expect": {
88
88
  "carrier": "intl-post",
89
89
  "confidence": "high"
90
90
  },
91
- "note": "ParcelPanel's Albania Post page offered it as a sample to try; it is not described as a live shipment."
91
+ "note": "ParcelPanel's Albania Post page offered it as a sample to try; Posta Shqiptare's own tracker returns its history. Detection selects the generic postal carrier."
92
92
  },
93
93
  {
94
94
  "number": "LG010568652AL",
@@ -99,13 +99,33 @@
99
99
  "access": "full_page"
100
100
  },
101
101
  "context": {
102
- "assessment": "candidate"
102
+ "assessment": "confirmed"
103
103
  },
104
104
  "expect": {
105
105
  "carrier": "intl-post",
106
106
  "confidence": "high"
107
107
  },
108
- "note": "ParcelPanel's Albania Post page offered it as a sample to try; it is not described as a live shipment."
108
+ "note": "ParcelPanel's Albania Post page offered it as a sample to try; Posta Shqiptare's own tracker returns its history. Detection selects the generic postal carrier."
109
+ },
110
+ {
111
+ "number": "EE200190512AL",
112
+ "role": "shipment",
113
+ "evidence": "public_shipment_report",
114
+ "source": {
115
+ "url": "https://www.parcelpanel.com/couriers/posta-shqiptare/",
116
+ "date": "2026-10-18",
117
+ "dateKind": "capture",
118
+ "access": "full_page"
119
+ },
120
+ "context": {
121
+ "service": "EMS",
122
+ "assessment": "confirmed"
123
+ },
124
+ "expect": {
125
+ "carrier": "intl-post",
126
+ "confidence": "high"
127
+ },
128
+ "note": "ParcelPanel's Albania Post page offered it as a sample to try; Posta Shqiptare's own tracker returns its history, with the scans of the courier that carried it abroad. Detection selects the generic postal carrier."
109
129
  }
110
130
  ]
111
131
  }
@@ -0,0 +1,14 @@
1
+ import type { CarrierResult } from '../../core/result/index.js';
2
+ export declare const PROVIDER = "Posta Shqiptare";
3
+ export declare const POSTA_SHQIPTARE_MAX_BYTES: number;
4
+ /** Posta Shqiptare's tracker follows S10 item codes: its own, ending AL, and those other posts send to Albania. */
5
+ export declare function normalizePostaShqiptareNumber(raw: string): string;
6
+ /**
7
+ * The reply of the e-Posta tracker's `getTrackApi` for one item: its scans,
8
+ * newest first, each with a wall clock, the wording and the office or the
9
+ * foreign post's country. The reply does not repeat the number; the request's
10
+ * address holds the whole of it. A code without scans gets an empty list,
11
+ * which the page reports as having no events, and the page's own notices for
12
+ * a missing item are read the same way.
13
+ */
14
+ export declare function parsePostaShqiptare(payload: unknown, raw: string): CarrierResult;