universal-parcel-scraper 0.734.2-main.3759 → 0.735.2-main.3769

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/data/catalog.json CHANGED
@@ -14902,6 +14902,11 @@
14902
14902
  {
14903
14903
  "pattern": "^CLFOX\\d{15}$",
14904
14904
  "confidence": "high"
14905
+ },
14906
+ {
14907
+ "pattern": "^66639\\d{5,15}$",
14908
+ "confidence": "low",
14909
+ "preferred": true
14905
14910
  }
14906
14911
  ]
14907
14912
  },
@@ -20625,6 +20630,16 @@
20625
20630
  "confidence": "low",
20626
20631
  "checksum": "magyar-posta",
20627
20632
  "preferred": true
20633
+ },
20634
+ {
20635
+ "pattern": "^RL\\d{14}$",
20636
+ "confidence": "low",
20637
+ "preferred": true
20638
+ },
20639
+ {
20640
+ "pattern": "^JJH[A-Z0-9]{17}$",
20641
+ "confidence": "low",
20642
+ "preferred": true
20628
20643
  }
20629
20644
  ]
20630
20645
  },
@@ -32531,7 +32546,12 @@
32531
32546
  },
32532
32547
  "canaryUrl": "https://t.17track.net/",
32533
32548
  "linkRules": [],
32534
- "detectionRules": []
32549
+ "detectionRules": [
32550
+ {
32551
+ "pattern": "^ZL[A-Z]{2}\\d{9}$",
32552
+ "confidence": "low"
32553
+ }
32554
+ ]
32535
32555
  },
32536
32556
  "zajil": {
32537
32557
  "displayName": "Zajil Express",
@@ -50473,6 +50473,27 @@
50473
50473
  "heppner"
50474
50474
  ]
50475
50475
  },
50476
+ {
50477
+ "input": "6663900000001",
50478
+ "carrier": "unknown",
50479
+ "confidence": "low",
50480
+ "candidates": [
50481
+ "foxpost",
50482
+ "la-poste",
50483
+ "correos-chile",
50484
+ "delhivery",
50485
+ "yunda",
50486
+ "korea-post"
50487
+ ],
50488
+ "preferred": [
50489
+ "foxpost"
50490
+ ],
50491
+ "asked": [
50492
+ "foxpost",
50493
+ "la-poste",
50494
+ "delhivery"
50495
+ ]
50496
+ },
50476
50497
  {
50477
50498
  "input": "6679804342",
50478
50499
  "carrier": "unknown",
@@ -78103,6 +78124,17 @@
78103
78124
  "posti"
78104
78125
  ]
78105
78126
  },
78127
+ {
78128
+ "input": "JJH30AAAAAPL00000001",
78129
+ "carrier": "unknown",
78130
+ "confidence": "low",
78131
+ "candidates": [
78132
+ "magyar-posta"
78133
+ ],
78134
+ "preferred": [
78135
+ "magyar-posta"
78136
+ ]
78137
+ },
78106
78138
  {
78107
78139
  "input": "JJITA8UW1A2B345678",
78108
78140
  "carrier": "poste-italiane",
@@ -87140,6 +87172,17 @@
87140
87172
  "chronopost"
87141
87173
  ]
87142
87174
  },
87175
+ {
87176
+ "input": "RL15050014358643",
87177
+ "carrier": "unknown",
87178
+ "confidence": "low",
87179
+ "candidates": [
87180
+ "magyar-posta"
87181
+ ],
87182
+ "preferred": [
87183
+ "magyar-posta"
87184
+ ]
87185
+ },
87143
87186
  {
87144
87187
  "input": "RL330279383MD",
87145
87188
  "carrier": "intl-post",
@@ -94754,6 +94797,14 @@
94754
94797
  "tnt-it"
94755
94798
  ]
94756
94799
  },
94800
+ {
94801
+ "input": "ZLXX000000017",
94802
+ "carrier": "unknown",
94803
+ "confidence": "low",
94804
+ "candidates": [
94805
+ "z-leading"
94806
+ ]
94807
+ },
94757
94808
  {
94758
94809
  "input": "ZND170922989053",
94759
94810
  "carrier": "unknown",
@@ -11556,6 +11556,10 @@ var Ze = {
11556
11556
  detectionRules: [{
11557
11557
  pattern: "^CLFOX\\d{15}$",
11558
11558
  confidence: "high"
11559
+ }, {
11560
+ pattern: "^66639\\d{5,15}$",
11561
+ confidence: "low",
11562
+ preferred: !0
11559
11563
  }]
11560
11564
  },
11561
11565
  "franch-express": {
@@ -15788,17 +15792,30 @@ var Ze = {
15788
15792
  pathPattern: "^/nyomkovetes/nyitooldal/?$",
15789
15793
  params: ["searchvalue"]
15790
15794
  }],
15791
- detectionRules: [{
15792
- pattern: "^[A-Z]{2}\\d{9}HU$",
15793
- confidence: "low",
15794
- checksum: "s10",
15795
- preferred: !0
15796
- }, {
15797
- pattern: "^P[A-Z][0-9A-Z]{3}\\d{8}$",
15798
- confidence: "low",
15799
- checksum: "magyar-posta",
15800
- preferred: !0
15801
- }]
15795
+ detectionRules: [
15796
+ {
15797
+ pattern: "^[A-Z]{2}\\d{9}HU$",
15798
+ confidence: "low",
15799
+ checksum: "s10",
15800
+ preferred: !0
15801
+ },
15802
+ {
15803
+ pattern: "^P[A-Z][0-9A-Z]{3}\\d{8}$",
15804
+ confidence: "low",
15805
+ checksum: "magyar-posta",
15806
+ preferred: !0
15807
+ },
15808
+ {
15809
+ pattern: "^RL\\d{14}$",
15810
+ confidence: "low",
15811
+ preferred: !0
15812
+ },
15813
+ {
15814
+ pattern: "^JJH[A-Z0-9]{17}$",
15815
+ confidence: "low",
15816
+ preferred: !0
15817
+ }
15818
+ ]
15802
15819
  },
15803
15820
  mailamericas: {
15804
15821
  displayName: "MailAmericas",
@@ -24568,7 +24585,10 @@ var Ze = {
24568
24585
  },
24569
24586
  canaryUrl: "https://t.17track.net/",
24570
24587
  linkRules: [],
24571
- detectionRules: []
24588
+ detectionRules: [{
24589
+ pattern: "^ZL[A-Z]{2}\\d{9}$",
24590
+ confidence: "low"
24591
+ }]
24572
24592
  },
24573
24593
  zajil: {
24574
24594
  displayName: "Zajil Express",
@@ -25446,7 +25466,7 @@ var Ze = {
25446
25466
  followmont: [],
25447
25467
  "forward-air": [],
25448
25468
  "forza-delivery": ["forza-delivery-1"],
25449
- foxpost: ["foxpost-1"],
25469
+ foxpost: ["foxpost-1", "foxpost-home-delivery"],
25450
25470
  "franch-express": [],
25451
25471
  fukuyama: [],
25452
25472
  gaash: [],
@@ -25608,7 +25628,12 @@ var Ze = {
25608
25628
  "m-one": ["m-one-s10"],
25609
25629
  "madhur-courier": [],
25610
25630
  "maersk-ecommerce": ["maersk-ecommerce-1"],
25611
- "magyar-posta": ["magyar-posta-s10", "magyar-posta-domestic"],
25631
+ "magyar-posta": [
25632
+ "magyar-posta-s10",
25633
+ "magyar-posta-domestic",
25634
+ "magyar-posta-letter",
25635
+ "magyar-posta-europe-standard"
25636
+ ],
25612
25637
  mailamericas: [
25613
25638
  "mailamericas-ml",
25614
25639
  "mailamericas-mmxqp",
@@ -25939,7 +25964,7 @@ var Ze = {
25939
25964
  "yurtici-kargo": [],
25940
25965
  ywe: ["ywe-1"],
25941
25966
  yypost: ["yypost-1"],
25942
- "z-leading": [],
25967
+ "z-leading": ["z-leading-1"],
25943
25968
  zajil: [],
25944
25969
  zeleris: ["zeleris-1"],
25945
25970
  zheldor: [],
@@ -31286,6 +31311,7 @@ var Rl = /* @__PURE__ */ new Map([
31286
31311
  ["DE", "dhl"],
31287
31312
  ["DK", "postnord"],
31288
31313
  ["DZ", "algerie-poste"],
31314
+ ["EE", "omniva"],
31289
31315
  ["EG", "egypt-post"],
31290
31316
  ["ES", "correos-spain"],
31291
31317
  ["FI", "posti"],
@@ -6,13 +6,13 @@ import { type FedExApiCredentials } from './api.js';
6
6
  export declare function normalizeFedExTrackingNumber(raw: string): string;
7
7
  export declare function fedexTrackingUrl(trackingNumber: string): string;
8
8
  /** The structured answer of the tracking page's own API call. */
9
- export declare function parseFedExTrackingResponse(payload: unknown, trackingNumber: string): CarrierResult;
9
+ export declare function parseFedExTrackingResponse(payload: unknown, trackingNumber: string, readAt?: number): CarrierResult;
10
10
  /**
11
11
  * The official Track API's answer (`POST /track/v1/trackingnumbers`). It reads
12
12
  * the scans, the latest status, the delivery dates and the hold location; the
13
13
  * recipient, shipper, signatory, package and service blocks are never read.
14
14
  */
15
- export declare function parseFedExApiResponse(payload: unknown, trackingNumber: string): CarrierResult;
15
+ export declare function parseFedExApiResponse(payload: unknown, trackingNumber: string, readAt?: number): CarrierResult;
16
16
  /**
17
17
  * The page the browser rendered, read only to tell a bot challenge from an
18
18
  * inconclusive load. The page renders its "can't find that tracking number"
@@ -1,4 +1,5 @@
1
1
  import { load } from 'cheerio';
2
+ import { DateTime } from 'luxon';
2
3
  import { recognizeFromBrowserLookup } from '../../core/adapter/index.js';
3
4
  import { fillPartialAnswer } from '../../core/result/partial.js';
4
5
  import { fedexBarcodeTrackingNumber, fedexGroundEconomyUspsNumber } from '../../core/detection/fedex.js';
@@ -6,7 +7,7 @@ import { uspsPackageIdentifier } from '../../core/detection/usps.js';
6
7
  import { ChallengeError, InputRequiredError, InvalidInputError, RateLimitedError, SchemaError, TransportError, UpstreamHttpError, } from '../../core/errors/index.js';
7
8
  import { runSteps } from '../../core/runner/index.js';
8
9
  import { NOOP_RECORDER } from '../../core/telemetry/index.js';
9
- import { calendarDay, explicitOffsetTime } from '../../core/time/index.js';
10
+ import { calendarDay, canadaProvinceTimeZone, countryTimeZone, explicitOffsetTime, firstOccurrence, usStateTimeZone, } from '../../core/time/index.js';
10
11
  import { clean, cleanScalar, TRAWL_TRANSPORT_ALLOWANCE_MS } from '../../core/transport/index.js';
11
12
  import { isRecord } from '../../core/types.js';
12
13
  import { FedExApiClient, fedexApiCredentials } from './api.js';
@@ -85,6 +86,55 @@ function scanClock(scan) {
85
86
  ? calendarDay(Number(day[1]), Number(day[2]), Number(day[3])) : null;
86
87
  return local ? { local_time: local } : {};
87
88
  }
89
+ // US states and Canadian provinces with places on more than one clock, and the
90
+ // countries whose islands keep another clock than the mainland zone they are given.
91
+ const SEVERAL_CLOCKS = new Set(['AK', 'FL', 'ID', 'IN', 'KS', 'KY', 'MI', 'ND', 'NE', 'NV', 'OR', 'SD', 'TN', 'TX',
92
+ 'BC', 'NL', 'NU', 'ON', 'QC', 'ES', 'PT']);
93
+ /** The zone of a place that keeps one clock: its country's, or its US state's or Canadian province's. */
94
+ function placeZone(country, region) {
95
+ if (country === 'US')
96
+ return SEVERAL_CLOCKS.has(region) ? null : usStateTimeZone(region);
97
+ if (country === 'CA')
98
+ return SEVERAL_CLOCKS.has(region) ? null : canadaProvinceTimeZone(region);
99
+ return SEVERAL_CLOCKS.has(country) ? null : countryTimeZone(country);
100
+ }
101
+ /** The page names a US or Canadian scan's state ("MEMPHIS, TN") and any other scan's country ("BOLOGNA IT"). */
102
+ function pageZone(location) {
103
+ const [, comma, code] = /(,?) ([A-Z]{2})$/.exec(location) ?? [];
104
+ if (!code)
105
+ return null;
106
+ if (comma && usStateTimeZone(code))
107
+ return placeZone('US', code);
108
+ if (comma && canadaProvinceTimeZone(code))
109
+ return placeZone('CA', code);
110
+ return placeZone(code, '');
111
+ }
112
+ function apiZone(value) {
113
+ if (!isRecord(value))
114
+ return null;
115
+ return placeZone(cleanScalar(value.countryCode).toUpperCase(), cleanScalar(value.stateOrProvinceCode).toUpperCase());
116
+ }
117
+ /**
118
+ * FedEx labels a scan it records after a clock change with the offset its
119
+ * place has kept since, even when the scan came before: a hub's departure the
120
+ * evening before October's change came as +01:00 among scans it had recorded
121
+ * in time as +02:00. A label that is the place's offset at `readAt` but not at
122
+ * the scan's wall clock is put back on the place's clock. A wall clock the
123
+ * place repeats or skips keeps its label.
124
+ */
125
+ function placeClock(clock, zone, readAt) {
126
+ const shown = clock.time && zone ? DateTime.fromISO(clock.time, { setZone: true }) : null;
127
+ if (!zone || !shown?.isValid || DateTime.fromMillis(readAt, { zone }).offset !== shown.offset)
128
+ return clock;
129
+ const { year, month, day, hour, minute, second } = shown;
130
+ const own = firstOccurrence(DateTime.fromObject({ year, month, day, hour, minute, second }, { zone }));
131
+ if (!own.isValid || own.hour !== hour || own.minute !== minute)
132
+ return clock;
133
+ if (own.getPossibleOffsets().some((possible) => possible.offset === shown.offset))
134
+ return clock;
135
+ const time = own.toISO({ suppressMilliseconds: true });
136
+ return time ? { ...clock, time } : clock;
137
+ }
88
138
  /**
89
139
  * Newest first. A scan with a time sorts by its instant, since each carries
90
140
  * its own offset, and one without a clock comes last. A scan dated by its day
@@ -259,7 +309,7 @@ function shipmentResult(shipment, number) {
259
309
  };
260
310
  }
261
311
  /** The structured answer of the tracking page's own API call. */
262
- export function parseFedExTrackingResponse(payload, trackingNumber) {
312
+ export function parseFedExTrackingResponse(payload, trackingNumber, readAt = Date.now()) {
263
313
  const number = normalizeFedExTrackingNumber(trackingNumber);
264
314
  if (!isRecord(payload) || !isRecord(payload.output)) {
265
315
  throw new SchemaError('FedEx', 'FedEx returned an invalid tracking response');
@@ -303,7 +353,7 @@ export function parseFedExTrackingResponse(payload, trackingNumber) {
303
353
  description: scanDescription(clean(raw.status), clean(raw.scanDetails)),
304
354
  wording: `${clean(raw.status)} ${clean(raw.scanDetails)}`,
305
355
  code: cleanScalar(raw.statusCD).toLocaleUpperCase('en-US'),
306
- clock: scanClock(raw),
356
+ clock: placeClock(scanClock(raw), pageZone(clean(raw.scanLocation)), readAt),
307
357
  location: clean(raw.scanLocation),
308
358
  })),
309
359
  statusText: keyStatus,
@@ -329,7 +379,7 @@ function apiDate(result, ...types) {
329
379
  * the scans, the latest status, the delivery dates and the hold location; the
330
380
  * recipient, shipper, signatory, package and service blocks are never read.
331
381
  */
332
- export function parseFedExApiResponse(payload, trackingNumber) {
382
+ export function parseFedExApiResponse(payload, trackingNumber, readAt = Date.now()) {
333
383
  const number = normalizeFedExTrackingNumber(trackingNumber);
334
384
  const complete = isRecord(payload) && isRecord(payload.output) && Array.isArray(payload.output.completeTrackResults)
335
385
  ? payload.output.completeTrackResults.filter(isRecord) : null;
@@ -369,7 +419,7 @@ export function parseFedExApiResponse(payload, trackingNumber) {
369
419
  description: scanDescription(clean(raw.eventDescription), clean(raw.exceptionDescription)),
370
420
  wording: `${clean(raw.eventDescription)} ${clean(raw.exceptionDescription)}`,
371
421
  code: cleanScalar(raw.eventType).toLocaleUpperCase('en-US'),
372
- clock: apiClock(raw.date),
422
+ clock: placeClock(apiClock(raw.date), apiZone(raw.scanLocation), readAt),
373
423
  location: apiPlace(raw.scanLocation),
374
424
  })),
375
425
  statusText,
@@ -1,7 +1,11 @@
1
1
  // The official API and the tracking page's own reply can word or place one
2
2
  // scan differently. A scan read from one takes over the row the other stored
3
- // at its instant when both read it as the same step.
3
+ // at its instant when both read it as the same step. FedEx labels a scan it
4
+ // records after a clock change with the offset its place took then, which an
5
+ // earlier release stored, so a scan read on its place's own clock takes over
6
+ // the row that shows its wall clock under the other offset.
4
7
  export const sameInstantIdentityPolicy = {
5
8
  sourceCarrierId: 'fedex', storedSources: ['fedex'], requireProviderCode: false,
6
9
  matches: (incoming, stored) => incoming.stage === stored.stage,
10
+ matchWallClock: true,
7
11
  };
@@ -80,6 +80,12 @@
80
80
  "id": "foxpost-1",
81
81
  "pattern": "^CLFOX\\d{15}$",
82
82
  "confidence": "high"
83
+ },
84
+ {
85
+ "id": "foxpost-home-delivery",
86
+ "pattern": "^66639\\d{5,15}$",
87
+ "confidence": "low",
88
+ "preferred": true
83
89
  }
84
90
  ]
85
91
  }
@@ -228,6 +228,26 @@
228
228
  "confidence": "high"
229
229
  },
230
230
  "note": "Looked up on Foxpost's own tracker, as an archived address shows; the capture was not opened."
231
+ },
232
+ {
233
+ "number": "6663900000001",
234
+ "role": "shipment",
235
+ "evidence": "synthetic",
236
+ "derivedFrom": "official_shape",
237
+ "shapeConfirmed": "2026-10-25",
238
+ "expect": {
239
+ "carrier": "unknown",
240
+ "confidence": "low",
241
+ "candidates": [
242
+ "foxpost",
243
+ "la-poste",
244
+ "correos-chile",
245
+ "delhivery",
246
+ "yunda",
247
+ "korea-post"
248
+ ]
249
+ },
250
+ "note": "Made-up number with the prefix Foxpost's tracking page and help give its home deliveries. No source gives their length; Foxpost's API caps a parcel's barcode at twenty characters."
231
251
  }
232
252
  ]
233
253
  }
@@ -1,6 +1,6 @@
1
1
  import type { CarrierResult } from '../../core/result/index.js';
2
2
  export declare const PROVIDER = "Foxpost";
3
- /** A CLFOX parcel ID, a Z number or a ten-digit number starting 66, as Foxpost's tracker takes them. */
3
+ /** A CLFOX parcel ID, a Z number, a ten-digit number starting 66 or a home delivery's 66639 number, as Foxpost's tracker takes them. */
4
4
  export declare function normalizeFoxpostNumber(raw: string): string;
5
5
  /**
6
6
  * The tracker's reply for one parcel: its scans and the locker it waits at.
@@ -9,9 +9,10 @@ import { firstOccurrence } from '../../core/time/index.js';
9
9
  import { clean } from '../../core/transport/index.js';
10
10
  import { foxpostScanStage } from './status.js';
11
11
  export const PROVIDER = 'Foxpost';
12
- // A Foxpost parcel ID, a Packeta number the tracker also answers for, and the
13
- // ten-digit IDs starting 66 it issues as well.
14
- const NUMBER = /^(?:CLFOX\d{15}|Z\d{10}|66\d{8})$/;
12
+ // A Foxpost parcel ID, a Packeta number the tracker also answers for, the
13
+ // ten-digit IDs starting 66 it issues as well, and its home deliveries' numbers
14
+ // starting 66639, of up to the twenty characters its API allows a barcode.
15
+ const NUMBER = /^(?:CLFOX\d{15}|Z\d{10}|66\d{8}|66639\d{5,15})$/;
15
16
  // The page's answer for a number it does not know.
16
17
  const ABSENT = /^A megadott csomag azonosító nem található a rendszerünkben\b/;
17
18
  const CLOCK = /^(\d{4})\.(\d{2})\.(\d{2}) (\d{2}):(\d{2})$/;
@@ -20,11 +21,11 @@ const POINT_PAGE = /^\/~\/[A-Za-z0-9_-]{1,40}$/;
20
21
  const ZONE = 'Europe/Budapest';
21
22
  const MAX_ROWS = 200;
22
23
  const MAX_EVENTS = 100;
23
- /** A CLFOX parcel ID, a Z number or a ten-digit number starting 66, as Foxpost's tracker takes them. */
24
+ /** A CLFOX parcel ID, a Z number, a ten-digit number starting 66 or a home delivery's 66639 number, as Foxpost's tracker takes them. */
24
25
  export function normalizeFoxpostNumber(raw) {
25
26
  const number = normalizeTrackingNumber(raw);
26
27
  if (!NUMBER.test(number)) {
27
- throw new InvalidInputError(PROVIDER, 'Foxpost tracks CLFOX parcel IDs, Z numbers and ten-digit numbers starting 66');
28
+ throw new InvalidInputError(PROVIDER, 'Foxpost tracks CLFOX parcel IDs, Z numbers, ten-digit numbers starting 66 and home deliveries\' numbers starting 66639');
28
29
  }
29
30
  return number;
30
31
  }
@@ -106,6 +106,18 @@
106
106
  "confidence": "low",
107
107
  "preferred": true,
108
108
  "checksum": "magyar-posta"
109
+ },
110
+ {
111
+ "id": "magyar-posta-letter",
112
+ "pattern": "^RL\\d{14}$",
113
+ "confidence": "low",
114
+ "preferred": true
115
+ },
116
+ {
117
+ "id": "magyar-posta-europe-standard",
118
+ "pattern": "^JJH[A-Z0-9]{17}$",
119
+ "confidence": "low",
120
+ "preferred": true
109
121
  }
110
122
  ]
111
123
  }
@@ -269,6 +269,50 @@
269
269
  ]
270
270
  },
271
271
  "note": "Magyar Posta's tracking API guide lists it in an example reply; it is not described as a live shipment."
272
+ },
273
+ {
274
+ "number": "RL15050014358643",
275
+ "role": "shipment",
276
+ "evidence": "public_shipment_report",
277
+ "source": {
278
+ "url": "https://web.archive.org/web/20220727091109/https://www.posta.hu/nyomkovetes/nyitooldal?searchvalue=RL15050014358643",
279
+ "date": "2022-07-27",
280
+ "dateKind": "capture",
281
+ "access": "full_page"
282
+ },
283
+ "context": {
284
+ "service": "domestic registered letter",
285
+ "assessment": "candidate"
286
+ },
287
+ "expect": {
288
+ "carrier": "unknown",
289
+ "confidence": "low",
290
+ "candidates": [
291
+ "magyar-posta"
292
+ ]
293
+ },
294
+ "note": "Looked up on Magyar Posta's tracker, as an archived address shows; the capture holds only the search form. The tracker names the RL series as its domestic letters, sixteen characters long."
295
+ },
296
+ {
297
+ "number": "JJH30AAAAAPL00000001",
298
+ "role": "shipment",
299
+ "evidence": "official_documentation_example",
300
+ "source": {
301
+ "url": "https://www.posta.hu/ikrnyomkovproxy/",
302
+ "access": "full_page"
303
+ },
304
+ "context": {
305
+ "service": "MPL Europe Standard",
306
+ "assessment": "candidate"
307
+ },
308
+ "expect": {
309
+ "carrier": "unknown",
310
+ "confidence": "low",
311
+ "candidates": [
312
+ "magyar-posta"
313
+ ]
314
+ },
315
+ "note": "Magyar Posta's tracker gives it as the example of an MPL Europe Standard (DHL) parcel number; it is not described as a live shipment."
272
316
  }
273
317
  ]
274
318
  }
@@ -30,5 +30,11 @@
30
30
  "unavailable": []
31
31
  },
32
32
  "links": [],
33
- "detection": []
33
+ "detection": [
34
+ {
35
+ "id": "z-leading-1",
36
+ "pattern": "^ZL[A-Z]{2}\\d{9}$",
37
+ "confidence": "low"
38
+ }
39
+ ]
34
40
  }
@@ -1,5 +1,21 @@
1
1
  {
2
2
  "carrier": "z-leading",
3
3
  "gap": "No public page shows a whole Z-Leading tracking number.",
4
- "records": []
4
+ "records": [
5
+ {
6
+ "number": "ZLXX000000017",
7
+ "role": "shipment",
8
+ "evidence": "synthetic",
9
+ "derivedFrom": "donated_real",
10
+ "shapeConfirmed": "2026-10-25",
11
+ "expect": {
12
+ "carrier": "unknown",
13
+ "confidence": "low",
14
+ "candidates": [
15
+ "z-leading"
16
+ ]
17
+ },
18
+ "note": "Made-up number in the shape of a parcel the app tracked, which two universal providers filed under Zhongling."
19
+ }
20
+ ]
5
21
  }
@@ -59,13 +59,14 @@ const CATALOG_NAMES = new Set([
59
59
  // from France, and dates its own scans on Taiwan time. Pošta Srbije, Pošta
60
60
  // Slovenije, Cyprus Post, MaltaPost, POST Luxembourg and Magyar Posta follow mail
61
61
  // from abroad under the sending post's number; Magyar Posta's lookup opens a
62
- // browser. The host also checks adapter availability and required inputs before
62
+ // browser. Omniva's tracker carries the scans in Estonia of mail from abroad,
63
+ // on UTC clocks. The host also checks adapter availability and required inputs before
63
64
  // making a request.
64
65
  const NATIONAL_POSTS = new Map([
65
66
  ['AM', 'haypost'], ['AR', 'correo-argentino'], ['AT', 'austrian-post'], ['AU', 'australia-post'], ['BD', 'bangladesh-post'],
66
67
  ['BE', 'bpost'], ['BG', 'bulgarian-posts'], ['BR', 'correios-br'], ['BY', 'belpost'], ['CA', 'canada-post'],
67
68
  ['CH', 'swiss-post'], ['CU', 'correos-cuba'], ['CY', 'cyprus-post'], ['CZ', 'ceska-posta'], ['DE', 'dhl'], ['DK', 'postnord'], ['DZ', 'algerie-poste'],
68
- ['EG', 'egypt-post'], ['ES', 'correos-spain'], ['FI', 'posti'], ['FO', 'posta-faroe'], ['FR', 'la-poste'],
69
+ ['EE', 'omniva'], ['EG', 'egypt-post'], ['ES', 'correos-spain'], ['FI', 'posti'], ['FO', 'posta-faroe'], ['FR', 'la-poste'],
69
70
  ['GB', 'royal-mail'], ['GR', 'elta'], ['HR', 'hrvatska-posta'], ['HU', 'magyar-posta'], ['IE', 'an-post'], ['IS', 'posturinn'],
70
71
  ['IT', 'poste-italiane'], ['JO', 'jordan-post'], ['JP', 'japan-post'], ['KE', 'posta-kenya'], ['LT', 'lietuvos-pastas'],
71
72
  ['LU', 'post-luxembourg'], ['LV', 'latvijas-pasts'], ['MA', 'barid-al-maghrib'], ['MK', 'posta-north-macedonia'], ['MT', 'maltapost'],
@@ -14902,6 +14902,11 @@
14902
14902
  {
14903
14903
  "pattern": "^CLFOX\\d{15}$",
14904
14904
  "confidence": "high"
14905
+ },
14906
+ {
14907
+ "pattern": "^66639\\d{5,15}$",
14908
+ "confidence": "low",
14909
+ "preferred": true
14905
14910
  }
14906
14911
  ]
14907
14912
  },
@@ -20625,6 +20630,16 @@
20625
20630
  "confidence": "low",
20626
20631
  "checksum": "magyar-posta",
20627
20632
  "preferred": true
20633
+ },
20634
+ {
20635
+ "pattern": "^RL\\d{14}$",
20636
+ "confidence": "low",
20637
+ "preferred": true
20638
+ },
20639
+ {
20640
+ "pattern": "^JJH[A-Z0-9]{17}$",
20641
+ "confidence": "low",
20642
+ "preferred": true
20628
20643
  }
20629
20644
  ]
20630
20645
  },
@@ -32531,7 +32546,12 @@
32531
32546
  },
32532
32547
  "canaryUrl": "https://t.17track.net/",
32533
32548
  "linkRules": [],
32534
- "detectionRules": []
32549
+ "detectionRules": [
32550
+ {
32551
+ "pattern": "^ZL[A-Z]{2}\\d{9}$",
32552
+ "confidence": "low"
32553
+ }
32554
+ ]
32535
32555
  },
32536
32556
  "zajil": {
32537
32557
  "displayName": "Zajil Express",
@@ -9664,6 +9664,10 @@ export declare const CARRIER_CATALOG: {
9664
9664
  readonly detectionRules: readonly [{
9665
9665
  readonly pattern: "^CLFOX\\d{15}$";
9666
9666
  readonly confidence: "high";
9667
+ }, {
9668
+ readonly pattern: "^66639\\d{5,15}$";
9669
+ readonly confidence: "low";
9670
+ readonly preferred: true;
9667
9671
  }];
9668
9672
  };
9669
9673
  readonly "franch-express": {
@@ -13288,6 +13292,14 @@ export declare const CARRIER_CATALOG: {
13288
13292
  readonly confidence: "low";
13289
13293
  readonly checksum: "magyar-posta";
13290
13294
  readonly preferred: true;
13295
+ }, {
13296
+ readonly pattern: "^RL\\d{14}$";
13297
+ readonly confidence: "low";
13298
+ readonly preferred: true;
13299
+ }, {
13300
+ readonly pattern: "^JJH[A-Z0-9]{17}$";
13301
+ readonly confidence: "low";
13302
+ readonly preferred: true;
13291
13303
  }];
13292
13304
  };
13293
13305
  readonly mailamericas: {
@@ -20790,7 +20802,10 @@ export declare const CARRIER_CATALOG: {
20790
20802
  };
20791
20803
  readonly canaryUrl: "https://t.17track.net/";
20792
20804
  readonly linkRules: readonly [];
20793
- readonly detectionRules: readonly [];
20805
+ readonly detectionRules: readonly [{
20806
+ readonly pattern: "^ZL[A-Z]{2}\\d{9}$";
20807
+ readonly confidence: "low";
20808
+ }];
20794
20809
  };
20795
20810
  readonly zajil: {
20796
20811
  readonly displayName: "Zajil Express";
@@ -14903,6 +14903,11 @@ export const CARRIER_CATALOG = {
14903
14903
  {
14904
14904
  "pattern": "^CLFOX\\d{15}$",
14905
14905
  "confidence": "high"
14906
+ },
14907
+ {
14908
+ "pattern": "^66639\\d{5,15}$",
14909
+ "confidence": "low",
14910
+ "preferred": true
14906
14911
  }
14907
14912
  ]
14908
14913
  },
@@ -20626,6 +20631,16 @@ export const CARRIER_CATALOG = {
20626
20631
  "confidence": "low",
20627
20632
  "checksum": "magyar-posta",
20628
20633
  "preferred": true
20634
+ },
20635
+ {
20636
+ "pattern": "^RL\\d{14}$",
20637
+ "confidence": "low",
20638
+ "preferred": true
20639
+ },
20640
+ {
20641
+ "pattern": "^JJH[A-Z0-9]{17}$",
20642
+ "confidence": "low",
20643
+ "preferred": true
20629
20644
  }
20630
20645
  ]
20631
20646
  },
@@ -32532,7 +32547,12 @@ export const CARRIER_CATALOG = {
32532
32547
  },
32533
32548
  "canaryUrl": "https://t.17track.net/",
32534
32549
  "linkRules": [],
32535
- "detectionRules": []
32550
+ "detectionRules": [
32551
+ {
32552
+ "pattern": "^ZL[A-Z]{2}\\d{9}$",
32553
+ "confidence": "low"
32554
+ }
32555
+ ]
32536
32556
  },
32537
32557
  "zajil": {
32538
32558
  "displayName": "Zajil Express",
@@ -33919,7 +33939,7 @@ export const DETECTION_RULE_IDS = {
33919
33939
  "followmont": [],
33920
33940
  "forward-air": [],
33921
33941
  "forza-delivery": ["forza-delivery-1"],
33922
- "foxpost": ["foxpost-1"],
33942
+ "foxpost": ["foxpost-1", "foxpost-home-delivery"],
33923
33943
  "franch-express": [],
33924
33944
  "fukuyama": [],
33925
33945
  "gaash": [],
@@ -34068,7 +34088,7 @@ export const DETECTION_RULE_IDS = {
34068
34088
  "m-one": ["m-one-s10"],
34069
34089
  "madhur-courier": [],
34070
34090
  "maersk-ecommerce": ["maersk-ecommerce-1"],
34071
- "magyar-posta": ["magyar-posta-s10", "magyar-posta-domestic"],
34091
+ "magyar-posta": ["magyar-posta-s10", "magyar-posta-domestic", "magyar-posta-letter", "magyar-posta-europe-standard"],
34072
34092
  "mailamericas": ["mailamericas-ml", "mailamericas-mmxqp", "mailamericas-domc", "mailamericas-s10"],
34073
34093
  "mailplus-au": ["mailplus-au-1"],
34074
34094
  "mainfreight": ["mainfreight-1"],
@@ -34369,7 +34389,7 @@ export const DETECTION_RULE_IDS = {
34369
34389
  "yurtici-kargo": [],
34370
34390
  "ywe": ["ywe-1"],
34371
34391
  "yypost": ["yypost-1"],
34372
- "z-leading": [],
34392
+ "z-leading": ["z-leading-1"],
34373
34393
  "zajil": [],
34374
34394
  "zeleris": ["zeleris-1"],
34375
34395
  "zheldor": [],
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Universal Parcel Scraper",
5
- "version": "0.734.2"
5
+ "version": "0.735.2"
6
6
  },
7
7
  "paths": {
8
8
  "/health": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-parcel-scraper",
3
- "version": "0.734.2-main.3759",
3
+ "version": "0.735.2-main.3769",
4
4
  "description": "Self-hosted parcel tracking: carrier detection, dedicated scrapers and optional universal providers.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",