universal-parcel-scraper 0.310.0-main.1813 → 0.311.0-main.1817

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
@@ -3616,6 +3616,11 @@
3616
3616
  {
3617
3617
  "pattern": "^LP\\d{13}CN$",
3618
3618
  "confidence": "low"
3619
+ },
3620
+ {
3621
+ "pattern": "^EM\\d{16}CA$",
3622
+ "confidence": "low",
3623
+ "preferred": true
3619
3624
  }
3620
3625
  ]
3621
3626
  },
@@ -11181,6 +11186,10 @@
11181
11186
  {
11182
11187
  "pattern": "^EM\\d{12}CA$",
11183
11188
  "confidence": "low"
11189
+ },
11190
+ {
11191
+ "pattern": "^EM\\d{16}CA$",
11192
+ "confidence": "low"
11184
11193
  }
11185
11194
  ]
11186
11195
  },
@@ -64581,6 +64581,22 @@
64581
64581
  "paxel"
64582
64582
  ]
64583
64583
  },
64584
+ {
64585
+ "input": "EM0000000000000001CA",
64586
+ "carrier": "unknown",
64587
+ "confidence": "low",
64588
+ "candidates": [
64589
+ "four-px",
64590
+ "emile"
64591
+ ],
64592
+ "preferred": [
64593
+ "four-px"
64594
+ ],
64595
+ "asked": [
64596
+ "four-px",
64597
+ "emile"
64598
+ ]
64599
+ },
64584
64600
  {
64585
64601
  "input": "EM020412924TR",
64586
64602
  "carrier": "intl-post",
@@ -3079,13 +3079,21 @@ var Me = {
3079
3079
  pathPattern: "^/$",
3080
3080
  fragment: "^/result/0/([A-Z0-9]+)$"
3081
3081
  }],
3082
- detectionRules: [{
3083
- pattern: "^4PX\\d{13}CN$",
3084
- confidence: "high"
3085
- }, {
3086
- pattern: "^LP\\d{13}CN$",
3087
- confidence: "low"
3088
- }]
3082
+ detectionRules: [
3083
+ {
3084
+ pattern: "^4PX\\d{13}CN$",
3085
+ confidence: "high"
3086
+ },
3087
+ {
3088
+ pattern: "^LP\\d{13}CN$",
3089
+ confidence: "low"
3090
+ },
3091
+ {
3092
+ pattern: "^EM\\d{16}CA$",
3093
+ confidence: "low",
3094
+ preferred: !0
3095
+ }
3096
+ ]
3089
3097
  },
3090
3098
  "blue-dart": {
3091
3099
  displayName: "Blue Dart",
@@ -8697,6 +8705,9 @@ var Me = {
8697
8705
  detectionRules: [{
8698
8706
  pattern: "^EM\\d{12}CA$",
8699
8707
  confidence: "low"
8708
+ }, {
8709
+ pattern: "^EM\\d{16}CA$",
8710
+ confidence: "low"
8700
8711
  }]
8701
8712
  },
8702
8713
  "emirates-post": {
@@ -20130,7 +20141,11 @@ var Me = {
20130
20141
  "correios-br": ["correios-br-1"],
20131
20142
  "correos-chile": ["correos-chile-1", "correos-chile-2"],
20132
20143
  yunexpress: ["yunexpress-1"],
20133
- "four-px": ["four-px-1", "four-px-cainiao-reference"],
20144
+ "four-px": [
20145
+ "four-px-1",
20146
+ "four-px-cainiao-reference",
20147
+ "four-px-emile-reference"
20148
+ ],
20134
20149
  "blue-dart": ["blue-dart-1"],
20135
20150
  delhivery: ["delhivery-1"],
20136
20151
  "nz-post": [
@@ -20410,7 +20425,7 @@ var Me = {
20410
20425
  "egypt-post": ["egypt-post-1", "egypt-post-s10"],
20411
20426
  ekart: ["ekart-ecommerce"],
20412
20427
  elta: ["elta-s10"],
20413
- emile: ["emile-1"],
20428
+ emile: ["emile-1", "emile-2"],
20414
20429
  "emirates-post": [],
20415
20430
  "ems-vietnam": [],
20416
20431
  "energia-tk": [],
@@ -75,6 +75,11 @@
75
75
  "id": "emile-1",
76
76
  "pattern": "^EM\\d{12}CA$",
77
77
  "confidence": "low"
78
+ },
79
+ {
80
+ "id": "emile-2",
81
+ "pattern": "^EM\\d{16}CA$",
82
+ "confidence": "low"
78
83
  }
79
84
  ]
80
85
  }
@@ -10,8 +10,8 @@ export const EMILE_MAX_BYTES = 1_000_000;
10
10
  const PROVIDER = 'Emile';
11
11
  export function normalizeEmileNumber(raw) {
12
12
  const number = normalizeTrackingNumber(raw);
13
- if (!/^EM\d{12}CA$/.test(number))
14
- throw new InvalidInputError(PROVIDER, 'Emile requires EM, twelve digits and CA');
13
+ if (!/^EM\d{12}(?:\d{4})?CA$/.test(number))
14
+ throw new InvalidInputError(PROVIDER, 'Emile requires EM, twelve or sixteen digits and CA');
15
15
  return number;
16
16
  }
17
17
  /** Preserve the identity attributes while rejecting malformed XML, entities and excessive nesting. */
@@ -71,6 +71,12 @@
71
71
  "id": "four-px-cainiao-reference",
72
72
  "pattern": "^LP\\d{13}CN$",
73
73
  "confidence": "low"
74
+ },
75
+ {
76
+ "id": "four-px-emile-reference",
77
+ "pattern": "^EM\\d{16}CA$",
78
+ "confidence": "low",
79
+ "preferred": true
74
80
  }
75
81
  ]
76
82
  }
@@ -243,6 +243,22 @@
243
243
  "confidence": "high"
244
244
  },
245
245
  "note": "A lookup on 4PX's tracker archived by the Wayback Machine. 4PX's feed answers the Royal Mail number it handed the parcel over with; Royal Mail delivered it, so detection names Royal Mail."
246
+ },
247
+ {
248
+ "number": "EM0000000000000001CA",
249
+ "role": "shipment",
250
+ "evidence": "synthetic",
251
+ "derivedFrom": "donated_real",
252
+ "shapeConfirmed": "2026-10-18",
253
+ "expect": {
254
+ "carrier": "unknown",
255
+ "confidence": "low",
256
+ "candidates": [
257
+ "four-px",
258
+ "emile"
259
+ ]
260
+ },
261
+ "note": "Made-up number in the shape of the Emile barcodes on parcels 4PX hands to Emile in Canada. Both 4PX's and Emile's trackers find such a parcel, and Emile's history says its waybill was generated for 4PX."
246
262
  }
247
263
  ]
248
264
  }
@@ -5,7 +5,7 @@ export interface FourPxStatus extends ClassifiedStatus {
5
5
  }
6
6
  export declare function fourPxStatus(code: string, description?: string): FourPxStatus | undefined;
7
7
  /**
8
- * What the map says about one scan: a code it maps, the exact wording of a
8
+ * What the map says about one scan: a code it maps, the known wording of a
9
9
  * code that relays a partner's step, or a codeless scan it knows. Other
10
10
  * wording under those codes is left to the shared rules.
11
11
  */
@@ -25,7 +25,10 @@ const CODES = new Map([
25
25
  // These codes relay whatever step a partner reported, from a label to an
26
26
  // arrival in the destination country, so the wording decides the stage.
27
27
  const WORDED = new Set(['FPX_O_IR', 'FPX_O_IRI']);
28
- const WORDING = { 'Waybill generated': 'registered' };
28
+ // By `normalizeStatusWording` wording. A partner's label can name its own
29
+ // waybill: "Waybill generated for …", as Emile words it.
30
+ const WORDING = new Map([['waybill generated', 'registered']]);
31
+ const LABEL_FOR = /^waybill generated for [a-z0-9]+$/;
29
32
  // Scans a partner relays without a code, by `normalizeStatusWording` wording.
30
33
  const UNCODED = new Map([
31
34
  ['your shipment has departed from the transit origin', 'in_transit'],
@@ -40,15 +43,17 @@ export function fourPxStatus(code, description = '') {
40
43
  return { status: languageStageStatus(uncoded), stage: uncoded, source: 'carrier_map' };
41
44
  if (!WORDED.has(code))
42
45
  return undefined;
43
- const exact = WORDING[description];
46
+ const exact = wordedStage(normalizeStatusWording(description));
44
47
  if (exact)
45
48
  return { status: languageStageStatus(exact), stage: exact, source: 'carrier_map' };
46
49
  const worded = classifyWording(description, 'pending');
47
50
  return worded.source === 'none' ? undefined : { status: languageStageStatus(worded.stage), stage: worded.stage, source: worded.source };
48
51
  }
49
- const NORMALIZED_WORDING = new Map(Object.entries(WORDING).map(([wording, stage]) => [normalizeStatusWording(wording), stage]));
52
+ function wordedStage(wording) {
53
+ return WORDING.get(wording) ?? (LABEL_FOR.test(wording) ? 'registered' : undefined);
54
+ }
50
55
  /**
51
- * What the map says about one scan: a code it maps, the exact wording of a
56
+ * What the map says about one scan: a code it maps, the known wording of a
52
57
  * code that relays a partner's step, or a codeless scan it knows. Other
53
58
  * wording under those codes is left to the shared rules.
54
59
  */
@@ -56,7 +61,7 @@ export const statusMap = {
56
61
  stage: (code, wording) => {
57
62
  if (!code)
58
63
  return UNCODED.get(wording);
59
- return CODES.get(code)?.stage ?? (WORDED.has(code) ? NORMALIZED_WORDING.get(wording) : undefined);
64
+ return CODES.get(code)?.stage ?? (WORDED.has(code) ? wordedStage(wording) : undefined);
60
65
  },
61
66
  gaps: [],
62
67
  };
@@ -175,7 +175,8 @@
175
175
  "language": "en",
176
176
  "stage": "registered",
177
177
  "confirmedBy": "live",
178
- "firstSeen": "2026-10-08"
178
+ "firstSeen": "2026-10-08",
179
+ "note": "Also relayed as \"Waybill generated for\" and the partner's waybill number, staged the same."
179
180
  },
180
181
  {
181
182
  "code": "FPX_O_IR",
@@ -3616,6 +3616,11 @@
3616
3616
  {
3617
3617
  "pattern": "^LP\\d{13}CN$",
3618
3618
  "confidence": "low"
3619
+ },
3620
+ {
3621
+ "pattern": "^EM\\d{16}CA$",
3622
+ "confidence": "low",
3623
+ "preferred": true
3619
3624
  }
3620
3625
  ]
3621
3626
  },
@@ -11181,6 +11186,10 @@
11181
11186
  {
11182
11187
  "pattern": "^EM\\d{12}CA$",
11183
11188
  "confidence": "low"
11189
+ },
11190
+ {
11191
+ "pattern": "^EM\\d{16}CA$",
11192
+ "confidence": "low"
11184
11193
  }
11185
11194
  ]
11186
11195
  },
@@ -2459,6 +2459,10 @@ export declare const CARRIER_CATALOG: {
2459
2459
  }, {
2460
2460
  readonly pattern: "^LP\\d{13}CN$";
2461
2461
  readonly confidence: "low";
2462
+ }, {
2463
+ readonly pattern: "^EM\\d{16}CA$";
2464
+ readonly confidence: "low";
2465
+ readonly preferred: true;
2462
2466
  }];
2463
2467
  };
2464
2468
  readonly "blue-dart": {
@@ -7265,6 +7269,9 @@ export declare const CARRIER_CATALOG: {
7265
7269
  readonly detectionRules: readonly [{
7266
7270
  readonly pattern: "^EM\\d{12}CA$";
7267
7271
  readonly confidence: "low";
7272
+ }, {
7273
+ readonly pattern: "^EM\\d{16}CA$";
7274
+ readonly confidence: "low";
7268
7275
  }];
7269
7276
  };
7270
7277
  readonly "emirates-post": {
@@ -3617,6 +3617,11 @@ export const CARRIER_CATALOG = {
3617
3617
  {
3618
3618
  "pattern": "^LP\\d{13}CN$",
3619
3619
  "confidence": "low"
3620
+ },
3621
+ {
3622
+ "pattern": "^EM\\d{16}CA$",
3623
+ "confidence": "low",
3624
+ "preferred": true
3620
3625
  }
3621
3626
  ]
3622
3627
  },
@@ -11182,6 +11187,10 @@ export const CARRIER_CATALOG = {
11182
11187
  {
11183
11188
  "pattern": "^EM\\d{12}CA$",
11184
11189
  "confidence": "low"
11190
+ },
11191
+ {
11192
+ "pattern": "^EM\\d{16}CA$",
11193
+ "confidence": "low"
11185
11194
  }
11186
11195
  ]
11187
11196
  },
@@ -27134,7 +27143,7 @@ export const DETECTION_RULE_IDS = {
27134
27143
  "correios-br": ["correios-br-1"],
27135
27144
  "correos-chile": ["correos-chile-1", "correos-chile-2"],
27136
27145
  "yunexpress": ["yunexpress-1"],
27137
- "four-px": ["four-px-1", "four-px-cainiao-reference"],
27146
+ "four-px": ["four-px-1", "four-px-cainiao-reference", "four-px-emile-reference"],
27138
27147
  "blue-dart": ["blue-dart-1"],
27139
27148
  "delhivery": ["delhivery-1"],
27140
27149
  "nz-post": ["nz-post-1", "nz-post-2", "nz-post-3"],
@@ -27321,7 +27330,7 @@ export const DETECTION_RULE_IDS = {
27321
27330
  "egypt-post": ["egypt-post-1", "egypt-post-s10"],
27322
27331
  "ekart": ["ekart-ecommerce"],
27323
27332
  "elta": ["elta-s10"],
27324
- "emile": ["emile-1"],
27333
+ "emile": ["emile-1", "emile-2"],
27325
27334
  "emirates-post": [],
27326
27335
  "ems-vietnam": [],
27327
27336
  "energia-tk": [],
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Universal Parcel Scraper",
5
- "version": "0.310.0"
5
+ "version": "0.311.0"
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.310.0-main.1813",
3
+ "version": "0.311.0-main.1817",
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",