universal-parcel-scraper 0.331.0-main.1889 → 0.331.0-main.1890

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
@@ -10242,7 +10242,8 @@
10242
10242
  "DHLink",
10243
10243
  "Dhlink",
10244
10244
  "驼飞侠",
10245
- "駝飛俠"
10245
+ "駝飛俠",
10246
+ "XZG"
10246
10247
  ],
10247
10248
  "countries": [
10248
10249
  "CN"
@@ -8033,7 +8033,8 @@ var Pe = {
8033
8033
  "DHLink",
8034
8034
  "Dhlink",
8035
8035
  "驼飞侠",
8036
- "駝飛俠"
8036
+ "駝飛俠",
8037
+ "XZG"
8037
8038
  ],
8038
8039
  countries: ["CN"],
8039
8040
  selectable: !0,
@@ -5,7 +5,8 @@
5
5
  "DHLink",
6
6
  "Dhlink",
7
7
  "驼飞侠",
8
- "駝飛俠"
8
+ "駝飛俠",
9
+ "XZG"
9
10
  ],
10
11
  "region": {
11
12
  "countries": [
@@ -10242,7 +10242,8 @@
10242
10242
  "DHLink",
10243
10243
  "Dhlink",
10244
10244
  "驼飞侠",
10245
- "駝飛俠"
10245
+ "駝飛俠",
10246
+ "XZG"
10246
10247
  ],
10247
10248
  "countries": [
10248
10249
  "CN"
@@ -6662,7 +6662,7 @@ export declare const CARRIER_CATALOG: {
6662
6662
  readonly dhlink: {
6663
6663
  readonly displayName: "DHLink";
6664
6664
  readonly color: "#143167";
6665
- readonly aliases: readonly ["DHLink", "Dhlink", "驼飞侠", "駝飛俠"];
6665
+ readonly aliases: readonly ["DHLink", "Dhlink", "驼飞侠", "駝飛俠", "XZG"];
6666
6666
  readonly countries: readonly ["CN"];
6667
6667
  readonly selectable: true;
6668
6668
  readonly timezone: "Asia/Shanghai";
@@ -10243,7 +10243,8 @@ export const CARRIER_CATALOG = {
10243
10243
  "DHLink",
10244
10244
  "Dhlink",
10245
10245
  "驼飞侠",
10246
- "駝飛俠"
10246
+ "駝飛俠",
10247
+ "XZG"
10247
10248
  ],
10248
10249
  "countries": [
10249
10250
  "CN"
@@ -25,7 +25,9 @@ export declare const ADAPTER_CHECKED_RULES: ReadonlySet<string>;
25
25
  * Evri International's tracker) names the partner whose rule claims it.
26
26
  * Several names that all map to the catalog can be one journey's legs; see
27
27
  * `journeyOwner`. Beside Cainiao, a bare brand names its network that
28
- * delivers at home.
28
+ * delivers at home. A bare brand none of whose networks fits the number names
29
+ * a group, such as "DPD Group" beside BRT, its network in Italy: beside a
30
+ * carrier whose rule fits the number, it leaves that carrier's hint.
29
31
  */
30
32
  export declare function universalCarrierHints(raw: unknown[], trackingNumber?: string): {
31
33
  reported_carriers: string[];
@@ -63,50 +63,68 @@ const NAME_CHECKED_RULES = new Set(['fedex-1']);
63
63
  * Evri International's tracker) names the partner whose rule claims it.
64
64
  * Several names that all map to the catalog can be one journey's legs; see
65
65
  * `journeyOwner`. Beside Cainiao, a bare brand names its network that
66
- * delivers at home.
66
+ * delivers at home. A bare brand none of whose networks fits the number names
67
+ * a group, such as "DPD Group" beside BRT, its network in Italy: beside a
68
+ * carrier whose rule fits the number, it leaves that carrier's hint.
67
69
  */
68
70
  export function universalCarrierHints(raw, trackingNumber) {
69
71
  const names = [...new Set(raw.filter((value) => typeof value === 'string'
70
72
  && value.length <= 80 && /^[\p{L}\p{N} .&'()-]+$/u.test(value)).map((value) => value.trim()))].filter(Boolean).slice(0, 10);
71
73
  const refused = new Set(trackingNumber ? checksumFailures(trackingNumber)
72
74
  .filter(({ rule }) => ADAPTER_CHECKED_RULES.has(rule) || NAME_CHECKED_RULES.has(rule)).map(({ carrier }) => carrier) : []);
75
+ const fitting = trackingNumber ? detectCarrierMatch(trackingNumber).candidates : [];
73
76
  const detected = new Set();
77
+ const inFull = new Set();
74
78
  // Cainiao follows a parcel from abroad under its delivery carrier's number,
75
79
  // so a brand named beside it delivers at home: Evri UK, not Evri
76
80
  // International, which hands parcels to partners abroad.
77
81
  const inbound = names.some((name) => followsPartnerNumbers(carrierIdFromName(name) ?? ''));
78
82
  const leg = inbound ? (network) => !tracksPartnerNumbers(network) : undefined;
79
83
  let unmapped = false;
84
+ let group = false;
80
85
  for (const name of names) {
81
- const named = carrierIdFromName(name) ?? (trackingNumber ? brandCarrierForNumber(name, trackingNumber, leg) : undefined);
86
+ const own = carrierIdFromName(name);
87
+ const named = own ?? (trackingNumber ? brandCarrierForNumber(name, trackingNumber, leg) : undefined);
82
88
  const carrier = named && trackingNumber ? partnerNumberOwner(named, trackingNumber) ?? named : named;
83
- if (!carrier)
89
+ const networks = carrier || !trackingNumber ? [] : brandCarrierIds(name);
90
+ if (networks.length && !networks.some((id) => fitting.includes(id)))
91
+ group = true;
92
+ else if (!carrier)
84
93
  unmapped = true;
85
- else if (!refused.has(carrier))
94
+ else if (!refused.has(carrier)) {
86
95
  detected.add(carrier);
96
+ if (own)
97
+ inFull.add(carrier);
98
+ }
87
99
  }
88
100
  // A name outside the catalog may be the number's owner, so it leaves no hint.
101
+ if (group && ![...detected].some((carrier) => fitting.includes(carrier)))
102
+ unmapped = true;
89
103
  const discovered = unmapped ? undefined : detected.size === 1 ? [...detected][0]
90
- : detected.size > 1 && trackingNumber ? journeyOwner([...detected], trackingNumber) : undefined;
104
+ : detected.size > 1 && trackingNumber ? journeyOwner([...detected], trackingNumber, inFull) : undefined;
91
105
  return { reported_carriers: names, ...(discovered ? { discovered_carrier: discovered } : {}) };
92
106
  }
93
107
  /**
94
108
  * A provider can name an origin and the carrier it hands the parcel to, such
95
109
  * as DHLink and SwiftX. The number is the one carrier's whose rules fit it,
96
- * or that a preferred rule backs among several. When none fits, Cainiao, which
110
+ * or that a preferred rule backs among several, else the one named in full
111
+ * beside networks a bare brand left to the number's shape. When none fits, Cainiao, which
97
112
  * follows a parcel under its delivery carrier's number, leaves the one carrier
98
113
  * named beside it. Otherwise a carrier whose numbers all have a layout of their own
99
114
  * (only high-confidence rules, SwiftX's SWX and eighteen digits) is named for
100
115
  * its own leg, and the one carrier left is the hint.
101
116
  */
102
- function journeyOwner(carriers, trackingNumber) {
117
+ function journeyOwner(carriers, trackingNumber, inFull) {
103
118
  const { candidates, preferred } = detectCarrierMatch(trackingNumber);
104
119
  const fitting = carriers.filter((carrier) => candidates.includes(carrier));
105
120
  if (fitting.length === 1)
106
121
  return fitting[0];
107
122
  if (fitting.length > 1) {
108
123
  const backed = fitting.filter((carrier) => preferred.includes(carrier));
109
- return backed.length === 1 ? backed[0] : undefined;
124
+ if (backed.length === 1)
125
+ return backed[0];
126
+ const named = (backed.length ? backed : fitting).filter((carrier) => inFull.has(carrier));
127
+ return named.length === 1 && named.length < fitting.length ? named[0] : undefined;
110
128
  }
111
129
  const delivering = carriers.filter((carrier) => !followsPartnerNumbers(carrier));
112
130
  if (delivering.length === 1 && delivering.length < carriers.length)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-parcel-scraper",
3
- "version": "0.331.0-main.1889",
3
+ "version": "0.331.0-main.1890",
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",