universal-parcel-scraper 0.330.0-main.1886 → 0.331.0-main.1889
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/README.md +2 -2
- package/data/catalog.json +11 -4
- package/data/coverage-summary.json +1 -1
- package/data/detection-golden.json +10 -6
- package/dist/browser/scraper.js +11 -5
- package/dist/carriers/big-smart/carrier.json +1 -1
- package/dist/carriers/equick/adapter.d.ts +19 -0
- package/dist/carriers/equick/adapter.js +65 -0
- package/dist/carriers/equick/carrier.json +48 -7
- package/dist/carriers/equick/numbers.json +8 -10
- package/dist/carriers/equick/parser.d.ts +16 -0
- package/dist/carriers/equick/parser.js +151 -0
- package/dist/carriers/equick/status.d.ts +11 -0
- package/dist/carriers/equick/status.js +30 -0
- package/dist/carriers/equick/statuses.json +10 -1
- package/dist/carriers/evdemo-lojistik/carrier.json +1 -1
- package/dist/core/catalog/statusMaps.js +2 -1
- package/dist/data/catalog.json +11 -4
- package/dist/generated/catalog.d.ts +9 -4
- package/dist/generated/catalog.js +12 -5
- package/dist/generated/recognition.js +1 -0
- package/dist/generated/registry.js +3 -1
- package/dist/server/openapi.json +1 -1
- 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)
|
|
14
14
|
|
|
15
15
|
<!-- GENERATED:summary -->
|
|
16
|
-
**3,500+ carriers** through **
|
|
16
|
+
**3,500+ carriers** through **369 dedicated adapters** and **5 universal fallbacks**
|
|
17
17
|
|
|
18
18
|
<sub>687 catalog entries · 131 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,
|
|
158
|
+
The carrier folders record 13,019 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
|
@@ -6972,7 +6972,7 @@
|
|
|
6972
6972
|
},
|
|
6973
6973
|
"big-smart": {
|
|
6974
6974
|
"displayName": "Big Smart",
|
|
6975
|
-
"color": "#
|
|
6975
|
+
"color": "#2f2f5e",
|
|
6976
6976
|
"aliases": [
|
|
6977
6977
|
"BigSmart",
|
|
6978
6978
|
"BIG Pack"
|
|
@@ -11783,7 +11783,9 @@
|
|
|
11783
11783
|
"timezone": "Asia/Shanghai",
|
|
11784
11784
|
"tracking": {
|
|
11785
11785
|
"mode": "automatic",
|
|
11786
|
-
"adapter": "
|
|
11786
|
+
"adapter": "equick",
|
|
11787
|
+
"recognitionRank": 853,
|
|
11788
|
+
"localClocks": true
|
|
11787
11789
|
},
|
|
11788
11790
|
"canaryUrl": "https://api.equick.cn/",
|
|
11789
11791
|
"linkRules": [
|
|
@@ -11795,7 +11797,12 @@
|
|
|
11795
11797
|
"fragment": "^/support/supportWay\\?(?:[^#]*&)?nums=([^&,]+)"
|
|
11796
11798
|
}
|
|
11797
11799
|
],
|
|
11798
|
-
"detectionRules": [
|
|
11800
|
+
"detectionRules": [
|
|
11801
|
+
{
|
|
11802
|
+
"pattern": "^EQK[A-Z]{2}\\d{10}YQ$",
|
|
11803
|
+
"confidence": "high"
|
|
11804
|
+
}
|
|
11805
|
+
]
|
|
11799
11806
|
},
|
|
11800
11807
|
"estes": {
|
|
11801
11808
|
"displayName": "Estes",
|
|
@@ -11995,7 +12002,7 @@
|
|
|
11995
12002
|
},
|
|
11996
12003
|
"evdemo-lojistik": {
|
|
11997
12004
|
"displayName": "Evdemo Lojistik",
|
|
11998
|
-
"color": "#
|
|
12005
|
+
"color": "#e3590f",
|
|
11999
12006
|
"aliases": [
|
|
12000
12007
|
"Evdemo",
|
|
12001
12008
|
"Evdemo Kargo"
|
|
@@ -67090,15 +67090,19 @@
|
|
|
67090
67090
|
},
|
|
67091
67091
|
{
|
|
67092
67092
|
"input": "EQKPT8586061210YQ",
|
|
67093
|
-
"carrier": "
|
|
67094
|
-
"confidence": "
|
|
67095
|
-
"candidates": [
|
|
67093
|
+
"carrier": "equick",
|
|
67094
|
+
"confidence": "high",
|
|
67095
|
+
"candidates": [
|
|
67096
|
+
"equick"
|
|
67097
|
+
]
|
|
67096
67098
|
},
|
|
67097
67099
|
{
|
|
67098
67100
|
"input": "EQKPT8613050786YQ",
|
|
67099
|
-
"carrier": "
|
|
67100
|
-
"confidence": "
|
|
67101
|
-
"candidates": [
|
|
67101
|
+
"carrier": "equick",
|
|
67102
|
+
"confidence": "high",
|
|
67103
|
+
"candidates": [
|
|
67104
|
+
"equick"
|
|
67105
|
+
]
|
|
67102
67106
|
},
|
|
67103
67107
|
{
|
|
67104
67108
|
"input": "ER107045826VN",
|
package/dist/browser/scraper.js
CHANGED
|
@@ -5643,7 +5643,7 @@ var Pe = {
|
|
|
5643
5643
|
},
|
|
5644
5644
|
"big-smart": {
|
|
5645
5645
|
displayName: "Big Smart",
|
|
5646
|
-
color: "#
|
|
5646
|
+
color: "#2f2f5e",
|
|
5647
5647
|
aliases: ["BigSmart", "BIG Pack"],
|
|
5648
5648
|
countries: ["MX"],
|
|
5649
5649
|
selectable: !0,
|
|
@@ -9174,14 +9174,19 @@ var Pe = {
|
|
|
9174
9174
|
timezone: "Asia/Shanghai",
|
|
9175
9175
|
tracking: {
|
|
9176
9176
|
mode: "automatic",
|
|
9177
|
-
adapter: "
|
|
9177
|
+
adapter: "equick",
|
|
9178
|
+
recognitionRank: 853,
|
|
9179
|
+
localClocks: !0
|
|
9178
9180
|
},
|
|
9179
9181
|
canaryUrl: "https://api.equick.cn/",
|
|
9180
9182
|
linkRules: [{
|
|
9181
9183
|
domains: ["www.equick.cn", "equick.cn"],
|
|
9182
9184
|
fragment: "^/support/supportWay\\?(?:[^#]*&)?nums=([^&,]+)"
|
|
9183
9185
|
}],
|
|
9184
|
-
detectionRules: [
|
|
9186
|
+
detectionRules: [{
|
|
9187
|
+
pattern: "^EQK[A-Z]{2}\\d{10}YQ$",
|
|
9188
|
+
confidence: "high"
|
|
9189
|
+
}]
|
|
9185
9190
|
},
|
|
9186
9191
|
estes: {
|
|
9187
9192
|
displayName: "Estes",
|
|
@@ -9325,7 +9330,7 @@ var Pe = {
|
|
|
9325
9330
|
},
|
|
9326
9331
|
"evdemo-lojistik": {
|
|
9327
9332
|
displayName: "Evdemo Lojistik",
|
|
9328
|
-
color: "#
|
|
9333
|
+
color: "#e3590f",
|
|
9329
9334
|
aliases: ["Evdemo", "Evdemo Kargo"],
|
|
9330
9335
|
countries: ["TR"],
|
|
9331
9336
|
selectable: !0,
|
|
@@ -21274,7 +21279,7 @@ var Pe = {
|
|
|
21274
21279
|
"envia-colombia": [],
|
|
21275
21280
|
envialia: [],
|
|
21276
21281
|
"epost-global": ["epost-global-1"],
|
|
21277
|
-
equick: [],
|
|
21282
|
+
equick: ["equick-eqk"],
|
|
21278
21283
|
estes: [],
|
|
21279
21284
|
"estes-forwarding": [],
|
|
21280
21285
|
"ethiopian-post": [],
|
|
@@ -26933,6 +26938,7 @@ var pl = {
|
|
|
26933
26938
|
"envia-colombia": 912,
|
|
26934
26939
|
envialia: 260,
|
|
26935
26940
|
"epost-global": 65,
|
|
26941
|
+
equick: 853,
|
|
26936
26942
|
estes: 20,
|
|
26937
26943
|
evri: 605,
|
|
26938
26944
|
"evri-uk": 615,
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
/**
|
|
5
|
+
* The lookup Equick's tracking page makes for the numbers typed in. The page
|
|
6
|
+
* calls the same service on `api.equick.cn:8080` over plain HTTP; its HTTPS
|
|
7
|
+
* host answers the same.
|
|
8
|
+
*/
|
|
9
|
+
export declare const EQUICK_API = "https://api.equick.cn/api/traceQuery";
|
|
10
|
+
export declare class EquickTracker {
|
|
11
|
+
private readonly options;
|
|
12
|
+
constructor(options?: {
|
|
13
|
+
fetcher?: typeof fetch;
|
|
14
|
+
recorder?: StepRecorder;
|
|
15
|
+
userAgent?: string;
|
|
16
|
+
});
|
|
17
|
+
fetch(raw: string, context?: TrackingContext): Promise<CarrierResult>;
|
|
18
|
+
}
|
|
19
|
+
export declare const adapter: AdapterFactory;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { accepted, recognizeFromLookup } from '../../core/adapter/index.js';
|
|
2
|
+
import { ChallengeError, IndeterminateError, 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 { EQUICK_MAX_BYTES, normalizeEquickNumber, parseEquick, PROVIDER } from './parser.js';
|
|
8
|
+
/**
|
|
9
|
+
* The lookup Equick's tracking page makes for the numbers typed in. The page
|
|
10
|
+
* calls the same service on `api.equick.cn:8080` over plain HTTP; its HTTPS
|
|
11
|
+
* host answers the same.
|
|
12
|
+
*/
|
|
13
|
+
export const EQUICK_API = 'https://api.equick.cn/api/traceQuery';
|
|
14
|
+
const REDIRECTS = [301, 302, 303, 307, 308];
|
|
15
|
+
// A missing route is not a missing parcel: an unknown number gets an empty result.
|
|
16
|
+
const GONE = [404, 405, 410];
|
|
17
|
+
// Bot checks a CDN or firewall could put in place of the reply.
|
|
18
|
+
const CHALLENGE = /_cf_chl_opt|cf-turnstile|<title>\s*(?:Just a moment|Attention Required|Access Denied|403 Forbidden)|acw_sc__v2|aliyun_waf|_____tmd_____|captcha|<title>\s*(?:滑动验证|验证码|安全验证)/i;
|
|
19
|
+
function json(body) {
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(body);
|
|
22
|
+
}
|
|
23
|
+
catch (cause) {
|
|
24
|
+
if (CHALLENGE.test(body.slice(0, 64_000)))
|
|
25
|
+
throw new ChallengeError(PROVIDER, 'Equick answered with a browser check', { cause });
|
|
26
|
+
throw new SchemaError(PROVIDER, 'Equick returned a reply that is not JSON', { cause });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class EquickTracker {
|
|
30
|
+
options;
|
|
31
|
+
constructor(options = {}) {
|
|
32
|
+
this.options = options;
|
|
33
|
+
}
|
|
34
|
+
async fetch(raw, context = {}) {
|
|
35
|
+
const number = normalizeEquickNumber(raw);
|
|
36
|
+
const read = async (signal, timeoutMs) => {
|
|
37
|
+
const { response, bytes } = await fetchBounded(EQUICK_API, { method: 'POST', signal, headers: {
|
|
38
|
+
Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': userAgentOf(this.options.userAgent),
|
|
39
|
+
}, body: JSON.stringify({ txtDanHao: number }) }, { provider: PROVIDER, timeoutMs: Math.max(1, Math.floor(timeoutMs)),
|
|
40
|
+
maxBytes: EQUICK_MAX_BYTES, redirect: 'manual', fetcher: this.options.fetcher, allowHttpStatuses: [...REDIRECTS, ...GONE] });
|
|
41
|
+
if (REDIRECTS.includes(response.status))
|
|
42
|
+
throw new TransportError(PROVIDER, 'Equick redirected its tracking lookup');
|
|
43
|
+
if (GONE.includes(response.status))
|
|
44
|
+
throw new TransportError(PROVIDER, 'Equick tracking lookup is unavailable', { status: response.status });
|
|
45
|
+
if (response.status !== 200)
|
|
46
|
+
throw new IndeterminateError(PROVIDER, 'Equick did not answer with its tracking result');
|
|
47
|
+
return parseEquick(json(decodeText(bytes)), number);
|
|
48
|
+
};
|
|
49
|
+
// A read that fails to reach Equick, or hangs, gets one more: the first gets
|
|
50
|
+
// half of the budget, so the retry fits in the rest.
|
|
51
|
+
return runSteps({ carrier: 'equick', budgetMs: context.budgetMs ?? 15_000, signal: context.signal,
|
|
52
|
+
recorder: this.options.recorder ?? NOOP_RECORDER }, [
|
|
53
|
+
{ id: 'direct', run: ({ signal, remainingMs }) => read(signal, firstAttemptMs(remainingMs)) },
|
|
54
|
+
networkRetryStep(({ signal, remainingMs }) => read(signal, remainingMs)),
|
|
55
|
+
]);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export const adapter = (environment) => {
|
|
59
|
+
const tracker = new EquickTracker({ fetcher: environment.fetcher, recorder: environment.recorder, userAgent: environment.userAgent });
|
|
60
|
+
return {
|
|
61
|
+
id: 'equick', recordsSteps: true, steps: ['direct', 'retry'],
|
|
62
|
+
track: (input, context) => tracker.fetch(input.number, context),
|
|
63
|
+
recognize: (number, context) => recognizeFromLookup(() => tracker.fetch(number, context), () => accepted(() => normalizeEquickNumber(number))),
|
|
64
|
+
};
|
|
65
|
+
};
|
|
@@ -23,16 +23,51 @@
|
|
|
23
23
|
"timezone": "Asia/Shanghai",
|
|
24
24
|
"tracking": {
|
|
25
25
|
"mode": "automatic",
|
|
26
|
-
"adapter": "
|
|
27
|
-
"steps": [
|
|
26
|
+
"adapter": "equick",
|
|
27
|
+
"steps": [
|
|
28
|
+
"direct",
|
|
29
|
+
"retry"
|
|
30
|
+
],
|
|
31
|
+
"recognition": {
|
|
32
|
+
"rank": 853
|
|
33
|
+
},
|
|
34
|
+
"localClocks": true
|
|
28
35
|
},
|
|
29
|
-
"capabilities": [
|
|
36
|
+
"capabilities": [
|
|
37
|
+
"history",
|
|
38
|
+
"location",
|
|
39
|
+
"destination_country",
|
|
40
|
+
"delivery_tracking_number"
|
|
41
|
+
],
|
|
30
42
|
"portal": {
|
|
31
43
|
"canaryUrl": "https://api.equick.cn/",
|
|
32
|
-
"shows": [
|
|
33
|
-
|
|
44
|
+
"shows": [
|
|
45
|
+
"status",
|
|
46
|
+
"history",
|
|
47
|
+
"location",
|
|
48
|
+
"destination_country"
|
|
49
|
+
],
|
|
50
|
+
"scraped": [
|
|
51
|
+
"status",
|
|
52
|
+
"history",
|
|
53
|
+
"location",
|
|
54
|
+
"destination_country",
|
|
55
|
+
"delivery_tracking_number"
|
|
56
|
+
],
|
|
34
57
|
"discarded": [],
|
|
35
|
-
"unavailable": [
|
|
58
|
+
"unavailable": [
|
|
59
|
+
"eta",
|
|
60
|
+
"delivered_at",
|
|
61
|
+
"offset_timestamps",
|
|
62
|
+
"weight",
|
|
63
|
+
"service_name",
|
|
64
|
+
"delivery_partner",
|
|
65
|
+
"provider_code",
|
|
66
|
+
"origin_country",
|
|
67
|
+
"sender_name",
|
|
68
|
+
"recipient_name",
|
|
69
|
+
"proof_of_delivery"
|
|
70
|
+
]
|
|
36
71
|
},
|
|
37
72
|
"links": [
|
|
38
73
|
{
|
|
@@ -43,5 +78,11 @@
|
|
|
43
78
|
"fragment": "^/support/supportWay\\?(?:[^#]*&)?nums=([^&,]+)"
|
|
44
79
|
}
|
|
45
80
|
],
|
|
46
|
-
"detection": [
|
|
81
|
+
"detection": [
|
|
82
|
+
{
|
|
83
|
+
"id": "equick-eqk",
|
|
84
|
+
"pattern": "^EQK[A-Z]{2}\\d{10}YQ$",
|
|
85
|
+
"confidence": "high"
|
|
86
|
+
}
|
|
87
|
+
]
|
|
47
88
|
}
|
|
@@ -53,15 +53,14 @@
|
|
|
53
53
|
"dateKind": "capture",
|
|
54
54
|
"access": "full_page"
|
|
55
55
|
},
|
|
56
|
-
"quarantine": true,
|
|
57
56
|
"context": {
|
|
58
|
-
"assessment": "
|
|
57
|
+
"assessment": "confirmed"
|
|
59
58
|
},
|
|
60
59
|
"expect": {
|
|
61
|
-
"carrier": "
|
|
62
|
-
"confidence": "
|
|
60
|
+
"carrier": "equick",
|
|
61
|
+
"confidence": "high"
|
|
63
62
|
},
|
|
64
|
-
"note": "ParcelPanel's Equick China page offers it as the sample number to try
|
|
63
|
+
"note": "ParcelPanel's Equick China page offers it as the sample number to try. Equick's own tracker knows it."
|
|
65
64
|
},
|
|
66
65
|
{
|
|
67
66
|
"number": "EQKPT8586061210YQ",
|
|
@@ -73,15 +72,14 @@
|
|
|
73
72
|
"dateKind": "capture",
|
|
74
73
|
"access": "full_page"
|
|
75
74
|
},
|
|
76
|
-
"quarantine": true,
|
|
77
75
|
"context": {
|
|
78
|
-
"assessment": "
|
|
76
|
+
"assessment": "candidate"
|
|
79
77
|
},
|
|
80
78
|
"expect": {
|
|
81
|
-
"carrier": "
|
|
82
|
-
"confidence": "
|
|
79
|
+
"carrier": "equick",
|
|
80
|
+
"confidence": "high"
|
|
83
81
|
},
|
|
84
|
-
"note": "TrackingMore's Equick China page gives it as a format example
|
|
82
|
+
"note": "TrackingMore's Equick China page gives it as a format example, in the layout of the numbers Equick's own tracker knows."
|
|
85
83
|
}
|
|
86
84
|
]
|
|
87
85
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CarrierResult } from '../../core/result/index.js';
|
|
2
|
+
export declare const PROVIDER = "Equick";
|
|
3
|
+
export declare const EQUICK_MAX_BYTES: number;
|
|
4
|
+
/** An Equick number, in capitals; anything else is not one Equick issues. */
|
|
5
|
+
export declare function normalizeEquickNumber(raw: string): string;
|
|
6
|
+
/** A scan's wording without who signed for it or phone numbers. */
|
|
7
|
+
export declare function equickWording(value: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* The reply of the tracker's `POST /api/traceQuery` for one number:
|
|
10
|
+
* `{"code":1,"msg":"success","data":{…}}`, where `data` keys each number asked,
|
|
11
|
+
* as it was sent, to its scans. A number the tracker does not know has no key,
|
|
12
|
+
* so one asked alone gets `{}`, which the page reports as no result. A `code`
|
|
13
|
+
* other than 1 is a lookup the service did not complete. Every scan must name
|
|
14
|
+
* the whole number asked.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseEquick(payload: unknown, raw: string): CarrierResult;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { normalizeTrackingNumber } from '../../core/detection/index.js';
|
|
2
|
+
import { IndeterminateError, InvalidInputError, NoHistoryError, NotFoundError, SchemaError } from '../../core/errors/index.js';
|
|
3
|
+
import { languageStageStatus } from '../../core/status/index.js';
|
|
4
|
+
import { calendarDay, countryCode } from '../../core/time/index.js';
|
|
5
|
+
import { clean } from '../../core/transport/index.js';
|
|
6
|
+
import { isRecord } from '../../core/types.js';
|
|
7
|
+
import { equickScanStage } from './status.js';
|
|
8
|
+
export const PROVIDER = 'Equick';
|
|
9
|
+
// A long history is a few kilobytes; the tracker answers up to fifty numbers a request.
|
|
10
|
+
export const EQUICK_MAX_BYTES = 512 * 1024;
|
|
11
|
+
// EQK, two letters, ten digits and YQ, as the current tracker's numbers read, or the nine
|
|
12
|
+
// digits of the older tracker's.
|
|
13
|
+
const NUMBER = /^(?:EQK[A-Z]{2}\d{10}YQ|\d{9})$/;
|
|
14
|
+
// The delivering carrier's number.
|
|
15
|
+
const PARTNER_NUMBER = /^(?=.*\d)[A-Z0-9]{4,40}$/;
|
|
16
|
+
// "2029-12-14 18:35:22", the scan's wall clock.
|
|
17
|
+
const CLOCK = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})(?::(\d{2}))?$/;
|
|
18
|
+
// A run of nine or more digits, with spaces, brackets, dots or hyphens between them, as phone
|
|
19
|
+
// numbers are written; a date stays.
|
|
20
|
+
const PHONE = /(?<![A-Z\d])(?!\d{4}-\d{2}-\d{2}(?!\d))\+?\d(?:[\s().-]{0,2}\d){8,}(?![A-Z\d])/gi;
|
|
21
|
+
// Who took a delivered parcel, after the delivery's own words.
|
|
22
|
+
const RECEIVER = /\s*[,;:.\-–]?\s*\b(?:signed(?: for)? by|signatory|received by)\b[\s\S]*$/i;
|
|
23
|
+
const MAX_NUMBERS = 50;
|
|
24
|
+
const MAX_ROWS = 500;
|
|
25
|
+
/** An Equick number, in capitals; anything else is not one Equick issues. */
|
|
26
|
+
export function normalizeEquickNumber(raw) {
|
|
27
|
+
const number = raw.length <= 64 ? normalizeTrackingNumber(raw) : '';
|
|
28
|
+
if (!NUMBER.test(number))
|
|
29
|
+
throw new InvalidInputError(PROVIDER, 'Equick numbers are EQK, two letters, ten digits and YQ, or nine digits');
|
|
30
|
+
return number;
|
|
31
|
+
}
|
|
32
|
+
/** An optional text field; anything but a string is a changed reply. */
|
|
33
|
+
function text(row, key, maxLength = 300) {
|
|
34
|
+
const value = row[key];
|
|
35
|
+
if (value === null || value === undefined)
|
|
36
|
+
return '';
|
|
37
|
+
if (typeof value !== 'string')
|
|
38
|
+
throw new SchemaError(PROVIDER, `Equick returned an invalid ${key}`);
|
|
39
|
+
return clean(value, maxLength);
|
|
40
|
+
}
|
|
41
|
+
/** A scan's wording without who signed for it or phone numbers. */
|
|
42
|
+
export function equickWording(value) {
|
|
43
|
+
return clean(value.replace(RECEIVER, '').replace(PHONE, '').replace(/\s+([,;:.])/g, '$1'))
|
|
44
|
+
.replace(/^[\s,;:\-–]+|[\s,;:\-–]+$/g, '');
|
|
45
|
+
}
|
|
46
|
+
/** A scan's clock as an ISO wall time, to the second; the day and time must exist. */
|
|
47
|
+
function wallClock(value) {
|
|
48
|
+
const match = CLOCK.exec(value);
|
|
49
|
+
const date = match ? calendarDay(Number(match[1]), Number(match[2]), Number(match[3])) : null;
|
|
50
|
+
const [hour, minute, second] = [Number(match?.[4]), Number(match?.[5]), Number(match?.[6] ?? 0)];
|
|
51
|
+
if (!date || hour > 23 || minute > 59 || second > 59)
|
|
52
|
+
throw new SchemaError(PROVIDER, 'Equick returned an invalid scan time');
|
|
53
|
+
return `${date}T${match[4]}:${match[5]}:${match[6] ?? '00'}`;
|
|
54
|
+
}
|
|
55
|
+
/** The scans under the number's key, deduplicated, with the delivering carrier's numbers they carry. */
|
|
56
|
+
function scans(rows, number) {
|
|
57
|
+
const seen = new Set();
|
|
58
|
+
const events = [];
|
|
59
|
+
const partners = new Set();
|
|
60
|
+
let country = '';
|
|
61
|
+
for (const row of rows) {
|
|
62
|
+
if (!isRecord(row) || typeof row.traceLabelNo !== 'string')
|
|
63
|
+
throw new SchemaError(PROVIDER, 'Equick returned an invalid scan');
|
|
64
|
+
// Every scan names the shipment it belongs to.
|
|
65
|
+
if (normalizeTrackingNumber(row.traceLabelNo) !== number)
|
|
66
|
+
throw new IndeterminateError(PROVIDER, 'Equick answered for another shipment');
|
|
67
|
+
const said = text(row, 'traceContent', 2000);
|
|
68
|
+
if (!said)
|
|
69
|
+
throw new SchemaError(PROVIDER, 'Equick returned a scan without its wording');
|
|
70
|
+
const local = wallClock(text(row, 'traceDateTime', 40));
|
|
71
|
+
const description = equickWording(said);
|
|
72
|
+
country ||= text(row, 'traceCountry', 80);
|
|
73
|
+
const partner = text(row, 'destinationWBNo', 200);
|
|
74
|
+
if (partner && normalizeTrackingNumber(partner) !== number)
|
|
75
|
+
partners.add(normalizeTrackingNumber(partner));
|
|
76
|
+
if (!description)
|
|
77
|
+
continue;
|
|
78
|
+
const location = text(row, 'traceLocation', 120);
|
|
79
|
+
const key = JSON.stringify([local, description, location]);
|
|
80
|
+
if (seen.has(key))
|
|
81
|
+
continue;
|
|
82
|
+
seen.add(key);
|
|
83
|
+
const staged = equickScanStage(description);
|
|
84
|
+
events.push({
|
|
85
|
+
local_time: local,
|
|
86
|
+
description,
|
|
87
|
+
...(location ? { location } : {}),
|
|
88
|
+
...(staged ? { stage: staged.stage, stage_source: staged.source } : {}),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return { events, country, partners };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The reply of the tracker's `POST /api/traceQuery` for one number:
|
|
95
|
+
* `{"code":1,"msg":"success","data":{…}}`, where `data` keys each number asked,
|
|
96
|
+
* as it was sent, to its scans. A number the tracker does not know has no key,
|
|
97
|
+
* so one asked alone gets `{}`, which the page reports as no result. A `code`
|
|
98
|
+
* other than 1 is a lookup the service did not complete. Every scan must name
|
|
99
|
+
* the whole number asked.
|
|
100
|
+
*/
|
|
101
|
+
export function parseEquick(payload, raw) {
|
|
102
|
+
const number = normalizeEquickNumber(raw);
|
|
103
|
+
if (!isRecord(payload) || typeof payload.code !== 'number')
|
|
104
|
+
throw new SchemaError(PROVIDER, 'Equick returned an invalid envelope');
|
|
105
|
+
if (payload.code !== 1)
|
|
106
|
+
throw new IndeterminateError(PROVIDER, 'Equick did not complete the lookup');
|
|
107
|
+
const data = payload.data;
|
|
108
|
+
// The service's answer to a request without a number.
|
|
109
|
+
if (data === null)
|
|
110
|
+
throw new IndeterminateError(PROVIDER, 'Equick returned an empty result');
|
|
111
|
+
if (!isRecord(data))
|
|
112
|
+
throw new SchemaError(PROVIDER, 'Equick returned an invalid result');
|
|
113
|
+
const keys = Object.keys(data);
|
|
114
|
+
if (keys.length > MAX_NUMBERS)
|
|
115
|
+
throw new SchemaError(PROVIDER, 'Equick returned too many results');
|
|
116
|
+
if (!keys.length)
|
|
117
|
+
throw new NotFoundError(PROVIDER);
|
|
118
|
+
const mine = keys.filter((key) => normalizeTrackingNumber(key) === number);
|
|
119
|
+
if (!mine.length)
|
|
120
|
+
throw new IndeterminateError(PROVIDER, 'Equick answered for another number');
|
|
121
|
+
if (mine.length > 1)
|
|
122
|
+
throw new IndeterminateError(PROVIDER, 'Equick returned several results for the number');
|
|
123
|
+
const rows = data[mine[0]];
|
|
124
|
+
if (!Array.isArray(rows))
|
|
125
|
+
throw new SchemaError(PROVIDER, 'Equick returned a shipment with invalid scans');
|
|
126
|
+
if (rows.length > MAX_ROWS)
|
|
127
|
+
throw new SchemaError(PROVIDER, 'Equick returned an oversized history');
|
|
128
|
+
const { events, country, partners } = scans(rows, number);
|
|
129
|
+
if (!events.length)
|
|
130
|
+
throw new NoHistoryError(PROVIDER);
|
|
131
|
+
// Newest first, as the tracker lists them by wall clock; an oldest-first reply is turned round.
|
|
132
|
+
// The clocks can be several places', so the order otherwise stands.
|
|
133
|
+
const newestFirst = events[0].local_time < events.at(-1).local_time ? events.reverse() : events;
|
|
134
|
+
const newest = newestFirst[0];
|
|
135
|
+
const scanned = newestFirst.find((event) => event.stage);
|
|
136
|
+
const stage = scanned?.stage;
|
|
137
|
+
const destination = country ? countryCode(country) : null;
|
|
138
|
+
const [partner] = partners;
|
|
139
|
+
return {
|
|
140
|
+
status: stage ? languageStageStatus(stage) : 'unknown',
|
|
141
|
+
...(stage ? { current_stage: stage, current_stage_source: scanned.stage_source } : {}),
|
|
142
|
+
last_status_text: newest.description,
|
|
143
|
+
last_update: null,
|
|
144
|
+
last_update_local: newest.local_time,
|
|
145
|
+
expected_delivery: null,
|
|
146
|
+
...(destination ? { destination_country: destination } : country ? { destination_country_name: country } : {}),
|
|
147
|
+
// The delivering carrier's number, when the scans carry one; the reply does not name the carrier.
|
|
148
|
+
...(partners.size === 1 && PARTNER_NUMBER.test(partner) ? { delivery_tracking_number: partner } : {}),
|
|
149
|
+
events: newestFirst,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ClassifiedWording, type Stage } from '../../core/status/index.js';
|
|
2
|
+
import { type CarrierStatusMap } from '../../core/status/statusMap.js';
|
|
3
|
+
/** The stage Equick's map gives a scan's wording. */
|
|
4
|
+
export declare function equickStage(wording: string): Stage | undefined;
|
|
5
|
+
/** A scan's stage: Equick's map, else the shared wording rules, else none. */
|
|
6
|
+
export declare function equickScanStage(wording: string): ClassifiedWording | null;
|
|
7
|
+
/**
|
|
8
|
+
* Scans come without a code. The tracker's Status column (`In progress`,
|
|
9
|
+
* `Hold`) is not kept: it sets no stage, the wording does.
|
|
10
|
+
*/
|
|
11
|
+
export declare const statusMap: CarrierStatusMap;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { classifyWording } from '../../core/status/index.js';
|
|
2
|
+
import { normalizeStatusWording } from '../../core/status/statusMap.js';
|
|
3
|
+
import statuses from './statuses.json' with { type: 'json' };
|
|
4
|
+
const ENTRIES = statuses.entries;
|
|
5
|
+
/** The scan wordings seen on Equick's trackers, in `normalizeStatusWording` form. */
|
|
6
|
+
const WORDINGS = new Map(ENTRIES.filter((entry) => !entry.code && entry.stage)
|
|
7
|
+
.map((entry) => [normalizeStatusWording(entry.wording), entry.stage]));
|
|
8
|
+
// A depot, hub, operation centre or airport named by its three-letter code, which changes with the route.
|
|
9
|
+
const SITE_SCAN = /^(?:arrived at|departed from) [a-z]{3} (?:depot|hub|operation center|airport)$/;
|
|
10
|
+
/** The stage Equick's map gives a scan's wording. */
|
|
11
|
+
export function equickStage(wording) {
|
|
12
|
+
const key = normalizeStatusWording(wording);
|
|
13
|
+
return WORDINGS.get(key) ?? (SITE_SCAN.test(key) ? 'in_transit' : undefined);
|
|
14
|
+
}
|
|
15
|
+
/** A scan's stage: Equick's map, else the shared wording rules, else none. */
|
|
16
|
+
export function equickScanStage(wording) {
|
|
17
|
+
const mapped = equickStage(wording);
|
|
18
|
+
if (mapped)
|
|
19
|
+
return { stage: mapped, source: 'carrier_map' };
|
|
20
|
+
const worded = classifyWording(wording, 'in_transit');
|
|
21
|
+
return worded.source === 'none' ? null : worded;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Scans come without a code. The tracker's Status column (`In progress`,
|
|
25
|
+
* `Hold`) is not kept: it sets no stage, the wording does.
|
|
26
|
+
*/
|
|
27
|
+
export const statusMap = {
|
|
28
|
+
stage: (code, wording) => (code === null ? equickStage(wording) : undefined),
|
|
29
|
+
gaps: [],
|
|
30
|
+
};
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"carrier": "equick",
|
|
3
3
|
"entries": [
|
|
4
|
+
{"code": "In progress", "wording": "In progress", "language": "en", "confirmedBy": "live", "note": "The tracker's Status column on most scans; it sets no stage, the scan's wording does."},
|
|
5
|
+
{"code": "Hold", "wording": "Hold", "language": "en", "confirmedBy": "live", "note": "Seen in the Status column of a pick-up scan the parcel moved on from, so it sets no stage; the scan's wording does."},
|
|
6
|
+
{"wording": "Shipping Label Created", "stage": "registered", "language": "en", "confirmedBy": "live"},
|
|
4
7
|
{"wording": "Delivered", "stage": "delivered", "language": "en", "confirmedBy": "portal", "note": "Shown in the Status field above the history."},
|
|
5
|
-
{"wording": "picked up from shipper", "stage": "accepted", "language": "en", "confirmedBy": "portal", "note": "Pick-up from the sender in China."},
|
|
8
|
+
{"wording": "picked up from shipper", "stage": "accepted", "language": "en", "confirmedBy": "portal", "note": "Pick-up from the sender in China; the current tracker writes it Picked up from shipper."},
|
|
6
9
|
{"wording": "Accepted by courier", "stage": "accepted", "language": "en", "confirmedBy": "portal"},
|
|
10
|
+
{"wording": "Arrived at SHA Depot", "stage": "in_transit", "language": "en", "confirmedBy": "live", "note": "Shanghai depot; the code changes with the depot."},
|
|
11
|
+
{"wording": "Departed from Original Depot", "stage": "in_transit", "language": "en", "confirmedBy": "live"},
|
|
12
|
+
{"wording": "Arrived at Equick operation center", "stage": "in_transit", "language": "en", "confirmedBy": "live"},
|
|
13
|
+
{"wording": "Departed from Equick operation center", "stage": "in_transit", "language": "en", "confirmedBy": "live"},
|
|
14
|
+
{"wording": "Arrived at original airport", "stage": "in_transit", "language": "en", "confirmedBy": "live", "note": "The departure airport in China."},
|
|
15
|
+
{"wording": "Shipment not yet received or processed", "stage": "in_transit", "language": "en", "confirmedBy": "live", "note": "The destination's delivery carrier has the parcel's data but not the parcel, relayed. Equick took the parcel first, so it does not step back to registered."},
|
|
7
16
|
{"wording": "Arrived at SHA operation center", "stage": "in_transit", "language": "en", "confirmedBy": "portal", "note": "Shanghai operation centre."},
|
|
8
17
|
{"wording": "Arrived at BJS hub", "stage": "in_transit", "language": "en", "confirmedBy": "portal", "note": "Beijing hub."},
|
|
9
18
|
{"wording": "Departed from PVG airport", "stage": "in_transit", "language": "en", "confirmedBy": "portal", "note": "The airport code changes with the route, as in Departed from BJS airport."},
|
|
@@ -103,6 +103,7 @@ import { statusMap as energiaTk } from '../../carriers/energia-tk/status.js';
|
|
|
103
103
|
import { statusMap as enviaColombia } from '../../carriers/envia-colombia/status.js';
|
|
104
104
|
import { statusMap as envialia } from '../../carriers/envialia/status.js';
|
|
105
105
|
import { statusMap as epostGlobal } from '../../carriers/epost-global/status.js';
|
|
106
|
+
import { statusMap as equick } from '../../carriers/equick/status.js';
|
|
106
107
|
import { statusMap as estes } from '../../carriers/estes/status.js';
|
|
107
108
|
import { statusMap as eurodis } from '../../carriers/eurodis/status.js';
|
|
108
109
|
import { statusMap as expressOne } from '../../carriers/express-one/status.js';
|
|
@@ -307,7 +308,7 @@ export const STATUS_MAPS = {
|
|
|
307
308
|
'danske-fragtmaend': danskeFragtmaend, dao, 'day-ross': dayRoss, dellin, delnext, deppon, 'dhl-express': dhlExpress, 'dhl-freight': dhlFreight, dhlink, dpd, 'dpd-at': dpdAt, 'dpd-be': dpdBe,
|
|
308
309
|
'dpd-de': dpdDe, 'dpd-fr': dpdFr, 'dpd-ie': dpdIe, 'dpd-nl': dpdNl, 'dpd-pl': dpdPl, 'dpd-pt': dpdPt, 'dpd-za': dpdZa, drop2shop, dsv, dx, dynalogic, 'early-bird': earlyBird, 'easy-mail': easyMail,
|
|
309
310
|
econt, 'egypt-post': egyptPost, elta, emile, 'ems-vietnam': emsVietnam, 'energia-tk': energiaTk, 'envia-colombia': enviaColombia, envialia,
|
|
310
|
-
'epost-global': epostGlobal, estes, eurodis,
|
|
311
|
+
'epost-global': epostGlobal, equick, estes, eurodis,
|
|
311
312
|
'express-one': expressOne, 'fan-courier': fanCourier, 'fedex-pl': fedexPl, fermopoint, 'fg-delivery': fgDelivery, 'flash-express': flashExpress,
|
|
312
313
|
'flash-express-ph': flashExpressPh,
|
|
313
314
|
'four-px': fourPx, foxpost, fukuyama, gati, gdex,
|
package/dist/data/catalog.json
CHANGED
|
@@ -6972,7 +6972,7 @@
|
|
|
6972
6972
|
},
|
|
6973
6973
|
"big-smart": {
|
|
6974
6974
|
"displayName": "Big Smart",
|
|
6975
|
-
"color": "#
|
|
6975
|
+
"color": "#2f2f5e",
|
|
6976
6976
|
"aliases": [
|
|
6977
6977
|
"BigSmart",
|
|
6978
6978
|
"BIG Pack"
|
|
@@ -11783,7 +11783,9 @@
|
|
|
11783
11783
|
"timezone": "Asia/Shanghai",
|
|
11784
11784
|
"tracking": {
|
|
11785
11785
|
"mode": "automatic",
|
|
11786
|
-
"adapter": "
|
|
11786
|
+
"adapter": "equick",
|
|
11787
|
+
"recognitionRank": 853,
|
|
11788
|
+
"localClocks": true
|
|
11787
11789
|
},
|
|
11788
11790
|
"canaryUrl": "https://api.equick.cn/",
|
|
11789
11791
|
"linkRules": [
|
|
@@ -11795,7 +11797,12 @@
|
|
|
11795
11797
|
"fragment": "^/support/supportWay\\?(?:[^#]*&)?nums=([^&,]+)"
|
|
11796
11798
|
}
|
|
11797
11799
|
],
|
|
11798
|
-
"detectionRules": [
|
|
11800
|
+
"detectionRules": [
|
|
11801
|
+
{
|
|
11802
|
+
"pattern": "^EQK[A-Z]{2}\\d{10}YQ$",
|
|
11803
|
+
"confidence": "high"
|
|
11804
|
+
}
|
|
11805
|
+
]
|
|
11799
11806
|
},
|
|
11800
11807
|
"estes": {
|
|
11801
11808
|
"displayName": "Estes",
|
|
@@ -11995,7 +12002,7 @@
|
|
|
11995
12002
|
},
|
|
11996
12003
|
"evdemo-lojistik": {
|
|
11997
12004
|
"displayName": "Evdemo Lojistik",
|
|
11998
|
-
"color": "#
|
|
12005
|
+
"color": "#e3590f",
|
|
11999
12006
|
"aliases": [
|
|
12000
12007
|
"Evdemo",
|
|
12001
12008
|
"Evdemo Kargo"
|
|
@@ -4631,7 +4631,7 @@ export declare const CARRIER_CATALOG: {
|
|
|
4631
4631
|
};
|
|
4632
4632
|
readonly "big-smart": {
|
|
4633
4633
|
readonly displayName: "Big Smart";
|
|
4634
|
-
readonly color: "#
|
|
4634
|
+
readonly color: "#2f2f5e";
|
|
4635
4635
|
readonly aliases: readonly ["BigSmart", "BIG Pack"];
|
|
4636
4636
|
readonly countries: readonly ["MX"];
|
|
4637
4637
|
readonly selectable: true;
|
|
@@ -7650,14 +7650,19 @@ export declare const CARRIER_CATALOG: {
|
|
|
7650
7650
|
readonly timezone: "Asia/Shanghai";
|
|
7651
7651
|
readonly tracking: {
|
|
7652
7652
|
readonly mode: "automatic";
|
|
7653
|
-
readonly adapter: "
|
|
7653
|
+
readonly adapter: "equick";
|
|
7654
|
+
readonly recognitionRank: 853;
|
|
7655
|
+
readonly localClocks: true;
|
|
7654
7656
|
};
|
|
7655
7657
|
readonly canaryUrl: "https://api.equick.cn/";
|
|
7656
7658
|
readonly linkRules: readonly [{
|
|
7657
7659
|
readonly domains: readonly ["www.equick.cn", "equick.cn"];
|
|
7658
7660
|
readonly fragment: "^/support/supportWay\\?(?:[^#]*&)?nums=([^&,]+)";
|
|
7659
7661
|
}];
|
|
7660
|
-
readonly detectionRules: readonly [
|
|
7662
|
+
readonly detectionRules: readonly [{
|
|
7663
|
+
readonly pattern: "^EQK[A-Z]{2}\\d{10}YQ$";
|
|
7664
|
+
readonly confidence: "high";
|
|
7665
|
+
}];
|
|
7661
7666
|
};
|
|
7662
7667
|
readonly estes: {
|
|
7663
7668
|
readonly displayName: "Estes";
|
|
@@ -7789,7 +7794,7 @@ export declare const CARRIER_CATALOG: {
|
|
|
7789
7794
|
};
|
|
7790
7795
|
readonly "evdemo-lojistik": {
|
|
7791
7796
|
readonly displayName: "Evdemo Lojistik";
|
|
7792
|
-
readonly color: "#
|
|
7797
|
+
readonly color: "#e3590f";
|
|
7793
7798
|
readonly aliases: readonly ["Evdemo", "Evdemo Kargo"];
|
|
7794
7799
|
readonly countries: readonly ["TR"];
|
|
7795
7800
|
readonly selectable: true;
|
|
@@ -6973,7 +6973,7 @@ export const CARRIER_CATALOG = {
|
|
|
6973
6973
|
},
|
|
6974
6974
|
"big-smart": {
|
|
6975
6975
|
"displayName": "Big Smart",
|
|
6976
|
-
"color": "#
|
|
6976
|
+
"color": "#2f2f5e",
|
|
6977
6977
|
"aliases": [
|
|
6978
6978
|
"BigSmart",
|
|
6979
6979
|
"BIG Pack"
|
|
@@ -11784,7 +11784,9 @@ export const CARRIER_CATALOG = {
|
|
|
11784
11784
|
"timezone": "Asia/Shanghai",
|
|
11785
11785
|
"tracking": {
|
|
11786
11786
|
"mode": "automatic",
|
|
11787
|
-
"adapter": "
|
|
11787
|
+
"adapter": "equick",
|
|
11788
|
+
"recognitionRank": 853,
|
|
11789
|
+
"localClocks": true
|
|
11788
11790
|
},
|
|
11789
11791
|
"canaryUrl": "https://api.equick.cn/",
|
|
11790
11792
|
"linkRules": [
|
|
@@ -11796,7 +11798,12 @@ export const CARRIER_CATALOG = {
|
|
|
11796
11798
|
"fragment": "^/support/supportWay\\?(?:[^#]*&)?nums=([^&,]+)"
|
|
11797
11799
|
}
|
|
11798
11800
|
],
|
|
11799
|
-
"detectionRules": [
|
|
11801
|
+
"detectionRules": [
|
|
11802
|
+
{
|
|
11803
|
+
"pattern": "^EQK[A-Z]{2}\\d{10}YQ$",
|
|
11804
|
+
"confidence": "high"
|
|
11805
|
+
}
|
|
11806
|
+
]
|
|
11800
11807
|
},
|
|
11801
11808
|
"estes": {
|
|
11802
11809
|
"displayName": "Estes",
|
|
@@ -11996,7 +12003,7 @@ export const CARRIER_CATALOG = {
|
|
|
11996
12003
|
},
|
|
11997
12004
|
"evdemo-lojistik": {
|
|
11998
12005
|
"displayName": "Evdemo Lojistik",
|
|
11999
|
-
"color": "#
|
|
12006
|
+
"color": "#e3590f",
|
|
12000
12007
|
"aliases": [
|
|
12001
12008
|
"Evdemo",
|
|
12002
12009
|
"Evdemo Kargo"
|
|
@@ -28478,7 +28485,7 @@ export const DETECTION_RULE_IDS = {
|
|
|
28478
28485
|
"envia-colombia": [],
|
|
28479
28486
|
"envialia": [],
|
|
28480
28487
|
"epost-global": ["epost-global-1"],
|
|
28481
|
-
"equick": [],
|
|
28488
|
+
"equick": ["equick-eqk"],
|
|
28482
28489
|
"estes": [],
|
|
28483
28490
|
"estes-forwarding": [],
|
|
28484
28491
|
"ethiopian-post": [],
|
|
@@ -124,6 +124,7 @@ import { adapter as energiaTk } from '../carriers/energia-tk/adapter.js';
|
|
|
124
124
|
import { adapter as enviaColombia } from '../carriers/envia-colombia/adapter.js';
|
|
125
125
|
import { adapter as envialia } from '../carriers/envialia/adapter.js';
|
|
126
126
|
import { adapter as epostGlobal } from '../carriers/epost-global/adapter.js';
|
|
127
|
+
import { adapter as equick } from '../carriers/equick/adapter.js';
|
|
127
128
|
import { adapter as estafeta } from '../carriers/estafeta/adapter.js';
|
|
128
129
|
import { adapter as estes } from '../carriers/estes/adapter.js';
|
|
129
130
|
import { adapter as eurodis } from '../carriers/eurodis/adapter.js';
|
|
@@ -494,6 +495,7 @@ export const REGISTRY = {
|
|
|
494
495
|
"envia-colombia": enviaColombia,
|
|
495
496
|
"envialia": envialia,
|
|
496
497
|
"epost-global": epostGlobal,
|
|
498
|
+
"equick": equick,
|
|
497
499
|
"estafeta": estafeta,
|
|
498
500
|
"estes": estes,
|
|
499
501
|
"eurodis": eurodis,
|
|
@@ -947,7 +949,7 @@ export const REGISTRY = {
|
|
|
947
949
|
"envia-colombia": "envia-colombia",
|
|
948
950
|
"envialia": "envialia",
|
|
949
951
|
"epost-global": "epost-global",
|
|
950
|
-
"equick": "
|
|
952
|
+
"equick": "equick",
|
|
951
953
|
"estafeta": "estafeta",
|
|
952
954
|
"estes": "estes",
|
|
953
955
|
"estes-forwarding": "universal",
|
package/dist/server/openapi.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "universal-parcel-scraper",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.331.0-main.1889",
|
|
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",
|