universal-parcel-scraper 0.2.0 → 0.3.0-main.298
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 +209 -71
- package/data/carrier.schema.json +6 -4
- package/data/catalog.json +6 -6
- package/dist/app.d.ts +11 -0
- package/dist/app.js +11 -0
- package/dist/browser/scraper.js +1386 -1568
- package/dist/carriers/aliexpress/adapter.d.ts +5 -3
- package/dist/carriers/aliexpress/adapter.js +28 -8
- package/dist/carriers/amazon-shipping/adapter.d.ts +3 -2
- package/dist/carriers/amazon-shipping/adapter.js +15 -10
- package/dist/carriers/amazon-shipping/eligibility.d.ts +2 -1
- package/dist/carriers/amazon-shipping/eligibility.js +2 -2
- package/dist/carriers/aramex/adapter.d.ts +2 -0
- package/dist/carriers/aramex/adapter.js +5 -3
- package/dist/carriers/aramex/parser.js +2 -2
- package/dist/carriers/asendia/adapter.d.ts +8 -0
- package/dist/carriers/asendia/adapter.js +66 -11
- package/dist/carriers/asendia/probe.d.ts +2 -0
- package/dist/carriers/asendia/probe.js +9 -7
- package/dist/carriers/australia-post/adapter.js +2 -2
- package/dist/carriers/austrian-post/adapter.js +2 -2
- package/dist/carriers/blue-dart/parser.js +2 -2
- package/dist/carriers/bpost/parser.js +2 -2
- package/dist/carriers/bring-posten/parser.js +2 -2
- package/dist/carriers/brt/parser.js +2 -2
- package/dist/carriers/c-chez-vous/adapter.d.ts +3 -2
- package/dist/carriers/c-chez-vous/adapter.js +15 -10
- package/dist/carriers/canada-post/adapter.d.ts +1 -0
- package/dist/carriers/canada-post/adapter.js +5 -3
- package/dist/carriers/canada-post/parser.js +2 -2
- package/dist/carriers/canpar/parser.js +2 -2
- package/dist/carriers/ciblex/parser.js +2 -2
- package/dist/carriers/colis-prive/adapter.d.ts +3 -2
- package/dist/carriers/colis-prive/adapter.js +0 -0
- package/dist/carriers/colisweb/adapter.d.ts +3 -2
- package/dist/carriers/colisweb/adapter.js +13 -8
- package/dist/carriers/correios-br/parser.js +2 -2
- package/dist/carriers/correos-chile/parser.js +3 -3
- package/dist/carriers/correos-express/parser.js +2 -2
- package/dist/carriers/correos-spain/adapter.d.ts +4 -2
- package/dist/carriers/correos-spain/adapter.js +16 -8
- package/dist/carriers/ctt/adapter.d.ts +2 -2
- package/dist/carriers/ctt/adapter.js +30 -25
- package/dist/carriers/ctt-express/parser.js +2 -2
- package/dist/carriers/dachser/adapter.d.ts +3 -2
- package/dist/carriers/dachser/adapter.js +34 -16
- package/dist/carriers/delhivery/parser.js +2 -2
- package/dist/carriers/dhl/adapter.d.ts +2 -2
- package/dist/carriers/dhl/adapter.js +50 -22
- package/dist/carriers/dhl-ecommerce/adapter.d.ts +3 -3
- package/dist/carriers/dhl-ecommerce/adapter.js +8 -8
- package/dist/carriers/dpd/adapter.d.ts +3 -3
- package/dist/carriers/dpd/adapter.js +113 -57
- package/dist/carriers/dpd/carrier.json +1 -1
- package/dist/carriers/dpd-fr/adapter.d.ts +2 -2
- package/dist/carriers/dpd-fr/adapter.js +29 -20
- package/dist/carriers/dtdc/parser.js +2 -2
- package/dist/carriers/ecoscooting/parser.js +2 -2
- package/dist/carriers/ems/adapter.js +2 -2
- package/dist/carriers/estafeta/parser.js +2 -2
- package/dist/carriers/evri/adapter.js +2 -2
- package/dist/carriers/fedex/adapter.d.ts +2 -2
- package/dist/carriers/fedex/adapter.js +14 -10
- package/dist/carriers/four-px/adapter.js +2 -2
- package/dist/carriers/geodis/adapter.d.ts +3 -2
- package/dist/carriers/geodis/adapter.js +13 -8
- package/dist/carriers/gls-ch/adapter.d.ts +4 -3
- package/dist/carriers/gls-ch/adapter.js +27 -19
- package/dist/carriers/gls-ch/carrier.json +1 -1
- package/dist/carriers/gls-de/adapter.d.ts +3 -3
- package/dist/carriers/gls-de/adapter.js +14 -9
- package/dist/carriers/gls-de/carrier.json +1 -1
- package/dist/carriers/gls-fr/adapter.d.ts +3 -2
- package/dist/carriers/gls-fr/adapter.js +16 -11
- package/dist/carriers/gofo/parser.js +2 -2
- package/dist/carriers/heppner/adapter.d.ts +4 -2
- package/dist/carriers/heppner/adapter.js +19 -14
- package/dist/carriers/heppner/carrier.json +1 -1
- package/dist/carriers/hermes/adapter.d.ts +3 -2
- package/dist/carriers/hermes/adapter.js +13 -8
- package/dist/carriers/hermes-de/adapter.d.ts +3 -2
- package/dist/carriers/hermes-de/adapter.js +16 -12
- package/dist/carriers/india-post/adapter.d.ts +2 -2
- package/dist/carriers/india-post/adapter.js +42 -21
- package/dist/carriers/inpost/adapter.d.ts +4 -2
- package/dist/carriers/inpost/adapter.js +17 -10
- package/dist/carriers/japan-post/adapter.js +2 -2
- package/dist/carriers/korea-post/adapter.js +2 -2
- package/dist/carriers/la-poste/adapter.d.ts +4 -2
- package/dist/carriers/la-poste/adapter.js +18 -13
- package/dist/carriers/landmark-global/parser.js +2 -2
- package/dist/carriers/mondial-relay/adapter.d.ts +2 -2
- package/dist/carriers/mondial-relay/adapter.js +26 -17
- package/dist/carriers/mondial-relay/carrier.json +1 -1
- package/dist/carriers/mrw/adapter.js +4 -2
- package/dist/carriers/mrw/parser.js +3 -3
- package/dist/carriers/nacex/parser.js +2 -2
- package/dist/carriers/ninja-van/parser.js +2 -2
- package/dist/carriers/nz-post/parser.js +2 -2
- package/dist/carriers/ontrac/parser.js +2 -2
- package/dist/carriers/paack/adapter.d.ts +4 -2
- package/dist/carriers/paack/adapter.js +24 -14
- package/dist/carriers/paack/carrier.json +1 -1
- package/dist/carriers/packeta/adapter.d.ts +4 -2
- package/dist/carriers/packeta/adapter.js +16 -8
- package/dist/carriers/planzer/adapter.d.ts +5 -3
- package/dist/carriers/planzer/adapter.js +35 -12
- package/dist/carriers/planzer/shared.d.ts +4 -1
- package/dist/carriers/planzer/shared.js +20 -6
- package/dist/carriers/poczta-polska/parser.js +2 -2
- package/dist/carriers/pos-malaysia/adapter.d.ts +2 -0
- package/dist/carriers/pos-malaysia/adapter.js +9 -5
- package/dist/carriers/poste-italiane/adapter.d.ts +4 -2
- package/dist/carriers/poste-italiane/adapter.js +16 -8
- package/dist/carriers/posti/adapter.js +2 -2
- package/dist/carriers/postlogistics/adapter.d.ts +6 -4
- package/dist/carriers/postlogistics/adapter.js +49 -17
- package/dist/carriers/postlogistics/status.d.ts +2 -0
- package/dist/carriers/postlogistics/status.js +2 -0
- package/dist/carriers/postnord/parser.js +2 -2
- package/dist/carriers/purolator/parser.js +2 -2
- package/dist/carriers/relais-colis/adapter.js +2 -2
- package/dist/carriers/royal-mail/adapter.d.ts +2 -2
- package/dist/carriers/royal-mail/adapter.js +14 -10
- package/dist/carriers/seur/parser.js +2 -2
- package/dist/carriers/sf-express/parser.js +2 -2
- package/dist/carriers/singapore-post/adapter.js +2 -2
- package/dist/carriers/spring-gds/adapter.d.ts +2 -0
- package/dist/carriers/spring-gds/adapter.js +16 -15
- package/dist/carriers/sunyou/adapter.d.ts +5 -3
- package/dist/carriers/sunyou/adapter.js +16 -9
- package/dist/carriers/swiss-post/adapter.d.ts +4 -4
- package/dist/carriers/swiss-post/adapter.js +33 -15
- package/dist/carriers/swiss-post-cargo/adapter.d.ts +3 -2
- package/dist/carriers/swiss-post-cargo/adapter.js +14 -9
- package/dist/carriers/the-courier-guy/number.js +3 -2
- package/dist/carriers/tipsa/parser.js +3 -3
- package/dist/carriers/tnt/adapter.js +3 -3
- package/dist/carriers/ukrposhta/adapter.js +20 -62
- package/dist/carriers/ukrposhta/parser.js +2 -2
- package/dist/carriers/uniuni/parser.js +3 -3
- package/dist/carriers/ups/adapter.d.ts +2 -2
- package/dist/carriers/ups/adapter.js +40 -32
- package/dist/carriers/usps/adapter.d.ts +2 -2
- package/dist/carriers/usps/adapter.js +14 -10
- package/dist/carriers/yamato/adapter.js +2 -2
- package/dist/carriers/yanwen/adapter.js +2 -2
- package/dist/carriers/yto/parser.js +2 -2
- package/dist/carriers/yunda/parser.js +2 -2
- package/dist/carriers/yunexpress/adapter.js +21 -39
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +49 -19
- package/dist/core/adapter/index.d.ts +18 -1
- package/dist/core/adapter/index.js +28 -4
- package/dist/core/adapter/track.js +21 -7
- package/dist/core/catalog/index.d.ts +1 -15
- package/dist/core/catalog/index.js +3 -106
- package/dist/core/catalog/inputs.d.ts +2 -2
- package/dist/core/catalog/inputs.js +4 -4
- package/dist/core/catalog/parcel.d.ts +53 -0
- package/dist/core/catalog/parcel.js +105 -0
- package/dist/core/catalog/types.d.ts +1 -29
- package/dist/core/catalog/urls.js +1 -0
- package/dist/core/errors/hint.d.ts +7 -0
- package/dist/core/errors/hint.js +11 -1
- package/dist/core/errors/index.d.ts +8 -1
- package/dist/core/errors/index.js +11 -0
- package/dist/core/runner/index.d.ts +23 -1
- package/dist/core/runner/index.js +71 -14
- package/dist/core/transport/boundedFetch.js +24 -19
- package/dist/core/transport/browser.d.ts +1 -0
- package/dist/core/transport/browser.js +76 -99
- package/dist/core/transport/index.d.ts +4 -1
- package/dist/core/transport/index.js +3 -1
- package/dist/core/transport/localBrowser.d.ts +24 -0
- package/dist/core/transport/localBrowser.js +87 -0
- package/dist/core/transport/trawl.d.ts +6 -0
- package/dist/core/transport/trawl.js +30 -9
- package/dist/core/transport/userAgent.d.ts +8 -0
- package/dist/core/transport/userAgent.js +15 -0
- package/dist/data/catalog.json +6 -6
- package/dist/facade/index.d.ts +3 -0
- package/dist/facade/index.js +29 -11
- package/dist/generated/catalog.d.ts +6 -6
- package/dist/generated/catalog.js +6 -6
- package/dist/index.d.ts +0 -4
- package/dist/index.js +0 -4
- package/dist/providers/parcelsapp/adapter.d.ts +1 -1
- package/dist/providers/parcelsapp/adapter.js +13 -10
- package/dist/providers/parcelsapp/http.d.ts +1 -1
- package/dist/providers/parcelsapp/http.js +2 -2
- package/dist/providers/postal-ninja/adapter.d.ts +2 -2
- package/dist/providers/postal-ninja/adapter.js +9 -8
- package/dist/providers/seventeentrack/adapter.d.ts +1 -1
- package/dist/providers/seventeentrack/adapter.js +7 -7
- package/dist/providers/shared/capture.d.ts +2 -0
- package/dist/providers/shared/capture.js +1 -1
- package/dist/providers/shared/result.js +4 -2
- package/dist/providers/ship24/adapter.d.ts +2 -2
- package/dist/providers/ship24/adapter.js +15 -11
- package/dist/providers/ship24/http.d.ts +1 -1
- package/dist/providers/ship24/http.js +4 -3
- package/dist/providers/universal.d.ts +3 -2
- package/dist/providers/universal.js +20 -2
- package/dist/providers/upu/adapter.js +2 -2
- package/dist/scripts/carrier-canary.js +2 -1
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.js +90 -12
- package/dist/server/openapi.json +399 -52
- package/package.json +13 -7
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* credential: never log it, quote it in an issue, or put a real one in a
|
|
12
12
|
* fixture.
|
|
13
13
|
*/
|
|
14
|
-
import type
|
|
14
|
+
import { type AdapterFactory, type TrackingContext } from '../../core/adapter/index.js';
|
|
15
15
|
import type { CarrierResult } from '../../core/result/index.js';
|
|
16
16
|
export { STEP_DETAILS, stepDetails } from './status.js';
|
|
17
17
|
export declare function normalizeCChezVousCredential(raw: string): string;
|
|
@@ -21,11 +21,12 @@ export interface CChezVousTrackerOptions {
|
|
|
21
21
|
timeoutMs?: number;
|
|
22
22
|
/** Test seam; production uses the global fetch. */
|
|
23
23
|
fetcher?: typeof fetch;
|
|
24
|
+
userAgent?: string;
|
|
24
25
|
}
|
|
25
26
|
export declare class CChezVousTracker {
|
|
26
27
|
#private;
|
|
27
28
|
readonly timeoutMs: number;
|
|
28
29
|
constructor(options?: CChezVousTrackerOptions);
|
|
29
|
-
fetch(rawCredential: string): Promise<CarrierResult>;
|
|
30
|
+
fetch(rawCredential: string, context?: TrackingContext): Promise<CarrierResult>;
|
|
30
31
|
}
|
|
31
32
|
export declare const adapter: AdapterFactory;
|
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
* fixture.
|
|
13
13
|
*/
|
|
14
14
|
import { load } from 'cheerio';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { lookupBudget } from '../../core/adapter/index.js';
|
|
16
|
+
import { InvalidInputError, NotFoundError, SchemaError } from '../../core/errors/index.js';
|
|
17
|
+
import { UpstreamHttpError, clean, decodeText, fetchBounded, userAgentOf } from '../../core/transport/index.js';
|
|
17
18
|
import { isRecord } from '../../core/types.js';
|
|
18
19
|
import { UNKNOWN_STEP, UNKNOWN_STEP_DESCRIPTION, parcelStep, stepDetails } from './status.js';
|
|
19
20
|
export { STEP_DETAILS, stepDetails } from './status.js';
|
|
@@ -54,7 +55,7 @@ export function normalizeCChezVousCredential(raw) {
|
|
|
54
55
|
const composite = /^([A-Z0-9]{11})--(\d{5})$/.exec(value);
|
|
55
56
|
if (composite) {
|
|
56
57
|
if (!FRENCH_POSTCODE.test(composite[2])) {
|
|
57
|
-
throw new
|
|
58
|
+
throw new InvalidInputError(PROVIDER, 'C Chez Vous tracking contains an invalid French postcode');
|
|
58
59
|
}
|
|
59
60
|
return `${composite[1]}--${composite[2]}`;
|
|
60
61
|
}
|
|
@@ -63,12 +64,12 @@ export function normalizeCChezVousCredential(raw) {
|
|
|
63
64
|
const compactComposite = /^([A-Z0-9]{11})(\d{5})$/.exec(value);
|
|
64
65
|
if (compactComposite) {
|
|
65
66
|
if (!FRENCH_POSTCODE.test(compactComposite[2])) {
|
|
66
|
-
throw new
|
|
67
|
+
throw new InvalidInputError(PROVIDER, 'C Chez Vous tracking contains an invalid French postcode');
|
|
67
68
|
}
|
|
68
69
|
return `${compactComposite[1]}--${compactComposite[2]}`;
|
|
69
70
|
}
|
|
70
71
|
if (!/^(?=.*\d)[A-Z0-9]{8,15}$/.test(value)) {
|
|
71
|
-
throw new
|
|
72
|
+
throw new InvalidInputError(PROVIDER, 'C Chez Vous tracking requires an 8- to 15-character order number, or an 11-character order followed by -- and a French postcode');
|
|
72
73
|
}
|
|
73
74
|
return value;
|
|
74
75
|
}
|
|
@@ -138,24 +139,28 @@ export function parseCChezVousTrackingHtml(html, rawCredential) {
|
|
|
138
139
|
export class CChezVousTracker {
|
|
139
140
|
timeoutMs;
|
|
140
141
|
#fetcher;
|
|
142
|
+
#userAgent;
|
|
141
143
|
constructor(options = {}) {
|
|
142
144
|
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
143
145
|
if (!Number.isFinite(this.timeoutMs) || this.timeoutMs <= 0) {
|
|
144
146
|
throw new TypeError('C Chez Vous timeout must be positive');
|
|
145
147
|
}
|
|
146
148
|
this.#fetcher = options.fetcher;
|
|
149
|
+
this.#userAgent = userAgentOf(options.userAgent);
|
|
147
150
|
}
|
|
148
|
-
async fetch(rawCredential) {
|
|
151
|
+
async fetch(rawCredential, context = {}) {
|
|
149
152
|
const credential = normalizeCChezVousCredential(rawCredential);
|
|
153
|
+
const budget = lookupBudget(context, this.timeoutMs);
|
|
150
154
|
const { response, bytes } = await fetchBounded(cChezVousTrackingUrl(credential), {
|
|
155
|
+
signal: budget.signal,
|
|
151
156
|
headers: {
|
|
152
157
|
Accept: 'text/html,application/xhtml+xml',
|
|
153
158
|
'Accept-Language': 'fr-FR,fr;q=0.9',
|
|
154
|
-
'User-Agent':
|
|
159
|
+
'User-Agent': this.#userAgent,
|
|
155
160
|
},
|
|
156
161
|
}, {
|
|
157
162
|
provider: 'C Chez Vous tracking',
|
|
158
|
-
timeoutMs: this.timeoutMs,
|
|
163
|
+
timeoutMs: Math.min(this.timeoutMs, budget.remainingMs()),
|
|
159
164
|
maxBytes: MAX_RESPONSE_BYTES,
|
|
160
165
|
redirect: 'manual',
|
|
161
166
|
allowHttpError: true,
|
|
@@ -171,11 +176,11 @@ export class CChezVousTracker {
|
|
|
171
176
|
}
|
|
172
177
|
}
|
|
173
178
|
export const adapter = (environment) => {
|
|
174
|
-
const tracker = new CChezVousTracker({ fetcher: environment.fetcher });
|
|
179
|
+
const tracker = new CChezVousTracker({ fetcher: environment.fetcher, userAgent: environment.userAgent });
|
|
175
180
|
return {
|
|
176
181
|
id: 'c-chez-vous',
|
|
177
182
|
steps: ['direct'],
|
|
178
183
|
// The postcode, when the order needs one, is already part of the stored number.
|
|
179
|
-
track: (input) => tracker.fetch(input.number),
|
|
184
|
+
track: (input, context) => tracker.fetch(input.number, context),
|
|
180
185
|
};
|
|
181
186
|
};
|
|
@@ -2,7 +2,7 @@ import { accepted, recognizeFromLookup } from '../../core/adapter/index.js';
|
|
|
2
2
|
import { BudgetExceededError, SchemaError, TransportError, UpstreamHttpError } from '../../core/errors/index.js';
|
|
3
3
|
import { runSteps } from '../../core/runner/index.js';
|
|
4
4
|
import { NOOP_RECORDER } from '../../core/telemetry/index.js';
|
|
5
|
-
import { fetchBounded, parseJsonBytes } from '../../core/transport/index.js';
|
|
5
|
+
import { fetchBounded, parseJsonBytes, userAgentOf } from '../../core/transport/index.js';
|
|
6
6
|
import { canadaPostLookupKind, normalizeCanadaPostNumber, parseCanadaPostTrackingResponse, resolveCanadaPostPin } from './parser.js';
|
|
7
7
|
export { normalizeCanadaPostNumber, parseCanadaPostTrackingResponse } from './parser.js';
|
|
8
8
|
const API_BASE = 'https://www.canadapost-postescanada.ca/track-reperage/rs/track/json/package';
|
|
@@ -15,11 +15,13 @@ export function canadaPostTrackingUrl(trackingNumber) {
|
|
|
15
15
|
export class CanadaPostTracker {
|
|
16
16
|
timeoutMs;
|
|
17
17
|
#options;
|
|
18
|
+
#userAgent;
|
|
18
19
|
constructor(options = {}) {
|
|
19
20
|
this.#options = typeof options === 'number' ? { timeoutMs: options } : options;
|
|
20
21
|
this.timeoutMs = this.#options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
21
22
|
if (!Number.isFinite(this.timeoutMs) || this.timeoutMs <= 0)
|
|
22
23
|
throw new TypeError('Canada Post timeout must be positive');
|
|
24
|
+
this.#userAgent = userAgentOf(this.#options.userAgent);
|
|
23
25
|
}
|
|
24
26
|
async fetch(rawTrackingNumber, context = {}) {
|
|
25
27
|
const number = normalizeCanadaPostNumber(rawTrackingNumber);
|
|
@@ -40,7 +42,7 @@ export class CanadaPostTracker {
|
|
|
40
42
|
// The public tracking application's interceptor sends empty Basic credentials.
|
|
41
43
|
Authorization: 'Basic Og==',
|
|
42
44
|
Referer: 'https://www.canadapost-postescanada.ca/track-reperage/en/home',
|
|
43
|
-
'User-Agent':
|
|
45
|
+
'User-Agent': this.#userAgent,
|
|
44
46
|
'X-Requested-With': 'XMLHttpRequest',
|
|
45
47
|
} }, { provider: 'canada-post', timeoutMs: Math.max(1, Math.floor(requestBudget)),
|
|
46
48
|
maxBytes: 1_000_000, fetcher: this.#options.fetcher }));
|
|
@@ -72,7 +74,7 @@ export class CanadaPostTracker {
|
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
export const adapter = (environment) => {
|
|
75
|
-
const tracker = new CanadaPostTracker({ fetcher: environment.fetcher, recorder: environment.recorder });
|
|
77
|
+
const tracker = new CanadaPostTracker({ fetcher: environment.fetcher, recorder: environment.recorder, userAgent: environment.userAgent });
|
|
76
78
|
return { id: 'canada-post', recordsSteps: true, steps: ['direct'], track: (input, context) => tracker.fetch(input.number, context),
|
|
77
79
|
recognize: (number, context) => recognizeFromLookup(() => tracker.fetch(number, context), () => accepted(() => normalizeCanadaPostNumber(number))) };
|
|
78
80
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DateTime } from 'luxon';
|
|
2
2
|
import { isValidS10TrackingNumber } from '../../core/detection/s10.js';
|
|
3
|
-
import { IndeterminateError, SchemaError } from '../../core/errors/index.js';
|
|
3
|
+
import { IndeterminateError, InvalidInputError, SchemaError } from '../../core/errors/index.js';
|
|
4
4
|
import { explicitOffsetTime } from '../../core/time/index.js';
|
|
5
5
|
import { clean } from '../../core/transport/index.js';
|
|
6
6
|
import { isRecord } from '../../core/types.js';
|
|
@@ -8,7 +8,7 @@ import { canadaPostPackageStage, canadaPostScanStage, canadaPostStage, statusFor
|
|
|
8
8
|
export function normalizeCanadaPostNumber(raw) {
|
|
9
9
|
const value = raw.toUpperCase().replace(/[\s.-]/g, '');
|
|
10
10
|
if (!/^\d{11,24}$/.test(value) && !(value.endsWith('CA') && isValidS10TrackingNumber(value))) {
|
|
11
|
-
throw new
|
|
11
|
+
throw new InvalidInputError('canada-post', 'Canada Post requires a parcel PIN, numeric reference or valid Canadian postal tracking number');
|
|
12
12
|
}
|
|
13
13
|
return value;
|
|
14
14
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { DateTime } from 'luxon';
|
|
2
2
|
import { normalizeTrackingNumber } from '../../core/detection/index.js';
|
|
3
|
-
import { IndeterminateError, SchemaError } from '../../core/errors/index.js';
|
|
3
|
+
import { IndeterminateError, InvalidInputError, SchemaError } from '../../core/errors/index.js';
|
|
4
4
|
import { clean } from '../../core/transport/index.js';
|
|
5
5
|
import { isRecord } from '../../core/types.js';
|
|
6
6
|
import { canparStatus } from './status.js';
|
|
7
7
|
export function normalizeCanparNumber(raw) {
|
|
8
8
|
const number = normalizeTrackingNumber(raw);
|
|
9
9
|
if (!/^[CDKLSUXZ]\d{21}$/.test(number))
|
|
10
|
-
throw new
|
|
10
|
+
throw new InvalidInputError('Canpar', 'Canpar requires a full parcel barcode');
|
|
11
11
|
return number;
|
|
12
12
|
}
|
|
13
13
|
function clock(raw) {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { load } from 'cheerio';
|
|
2
2
|
import { DateTime } from 'luxon';
|
|
3
|
-
import { IndeterminateError, SchemaError } from '../../core/errors/index.js';
|
|
3
|
+
import { IndeterminateError, InvalidInputError, SchemaError } from '../../core/errors/index.js';
|
|
4
4
|
import { clean } from '../../core/transport/index.js';
|
|
5
5
|
import { calendarDay, zonedTime } from '../../core/time/index.js';
|
|
6
6
|
import { classifyCiblexStatus, comparableText } from './status.js';
|
|
7
7
|
export function normalizeCiblexTrackingNumber(raw) {
|
|
8
8
|
const number = raw.replace(/\s/g, '');
|
|
9
9
|
if (!/^(?:\d{14}|\d{24})$/.test(number))
|
|
10
|
-
throw new
|
|
10
|
+
throw new InvalidInputError('Ciblex', 'Ciblex requires exactly 14 or 24 digits');
|
|
11
11
|
return number;
|
|
12
12
|
}
|
|
13
13
|
export function ciblexTrackingUrl(raw) {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* so it is part of the tracking credential: it is never logged, put in an issue
|
|
12
12
|
* or written into a fixture.
|
|
13
13
|
*/
|
|
14
|
-
import { type AdapterFactory } from '../../core/adapter/index.js';
|
|
14
|
+
import { type AdapterFactory, type TrackingContext } from '../../core/adapter/index.js';
|
|
15
15
|
import { NotFoundError } from '../../core/errors/index.js';
|
|
16
16
|
import type { CarrierResult } from '../../core/result/index.js';
|
|
17
17
|
export { classifyStatus } from './status.js';
|
|
@@ -29,11 +29,12 @@ export interface ColisPriveTrackerOptions {
|
|
|
29
29
|
timeoutMs?: number;
|
|
30
30
|
/** Test seam; production uses the global fetch. */
|
|
31
31
|
fetcher?: typeof fetch;
|
|
32
|
+
userAgent?: string;
|
|
32
33
|
}
|
|
33
34
|
export declare class ColisPriveTracker {
|
|
34
35
|
#private;
|
|
35
36
|
readonly timeoutMs: number;
|
|
36
37
|
constructor(options?: ColisPriveTrackerOptions);
|
|
37
|
-
fetch(rawCredential: string): Promise<CarrierResult>;
|
|
38
|
+
fetch(rawCredential: string, context?: TrackingContext): Promise<CarrierResult>;
|
|
38
39
|
}
|
|
39
40
|
export declare const adapter: AdapterFactory;
|
|
Binary file
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* milestones, the step and the slot's starting day; everything describing a
|
|
9
9
|
* person or a shop is dropped.
|
|
10
10
|
*/
|
|
11
|
-
import type
|
|
11
|
+
import { type AdapterFactory, type TrackingContext } from '../../core/adapter/index.js';
|
|
12
12
|
import type { CarrierResult } from '../../core/result/index.js';
|
|
13
13
|
export { classifyStatus } from './status.js';
|
|
14
14
|
export declare function normalizeColiswebTrackingNumber(raw: string): string;
|
|
@@ -19,11 +19,12 @@ export interface ColiswebTrackerOptions {
|
|
|
19
19
|
timeoutMs?: number;
|
|
20
20
|
/** Test seam; production uses the global fetch. */
|
|
21
21
|
fetcher?: typeof fetch;
|
|
22
|
+
userAgent?: string;
|
|
22
23
|
}
|
|
23
24
|
export declare class ColiswebTracker {
|
|
24
25
|
#private;
|
|
25
26
|
readonly timeoutMs: number;
|
|
26
27
|
constructor(options?: ColiswebTrackerOptions);
|
|
27
|
-
fetch(rawTrackingNumber: string): Promise<CarrierResult>;
|
|
28
|
+
fetch(rawTrackingNumber: string, context?: TrackingContext): Promise<CarrierResult>;
|
|
28
29
|
}
|
|
29
30
|
export declare const adapter: AdapterFactory;
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
* milestones, the step and the slot's starting day; everything describing a
|
|
9
9
|
* person or a shop is dropped.
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { lookupBudget } from '../../core/adapter/index.js';
|
|
12
|
+
import { IndeterminateError, InvalidInputError, NotFoundError, SchemaError } from '../../core/errors/index.js';
|
|
13
|
+
import { UpstreamHttpError, clean, decodeText, fetchBounded, parseJsonBytes, userAgentOf } from '../../core/transport/index.js';
|
|
13
14
|
import { isRecord } from '../../core/types.js';
|
|
14
15
|
import { classifyStatus } from './status.js';
|
|
15
16
|
export { classifyStatus } from './status.js';
|
|
@@ -47,7 +48,7 @@ function saysNotFound(value) {
|
|
|
47
48
|
export function normalizeColiswebTrackingNumber(raw) {
|
|
48
49
|
const value = raw.replace(/\s/g, '');
|
|
49
50
|
if (!/^\d{8,32}$/.test(value)) {
|
|
50
|
-
throw new
|
|
51
|
+
throw new InvalidInputError(PROVIDER, 'Colisweb tracking numbers must contain at least 8 digits');
|
|
51
52
|
}
|
|
52
53
|
return value;
|
|
53
54
|
}
|
|
@@ -114,28 +115,32 @@ export function parseColiswebTrackingResponse(payload, rawTrackingNumber) {
|
|
|
114
115
|
export class ColiswebTracker {
|
|
115
116
|
timeoutMs;
|
|
116
117
|
#fetcher;
|
|
118
|
+
#userAgent;
|
|
117
119
|
constructor(options = {}) {
|
|
118
120
|
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
119
121
|
if (!Number.isFinite(this.timeoutMs) || this.timeoutMs <= 0) {
|
|
120
122
|
throw new TypeError('Colisweb timeout must be positive');
|
|
121
123
|
}
|
|
122
124
|
this.#fetcher = options.fetcher;
|
|
125
|
+
this.#userAgent = userAgentOf(options.userAgent);
|
|
123
126
|
}
|
|
124
|
-
async fetch(rawTrackingNumber) {
|
|
127
|
+
async fetch(rawTrackingNumber, context = {}) {
|
|
125
128
|
const trackingNumber = normalizeColiswebTrackingNumber(rawTrackingNumber);
|
|
129
|
+
const budget = lookupBudget(context, this.timeoutMs);
|
|
126
130
|
const { response, bytes } = await fetchBounded(coliswebTrackingUrl(), {
|
|
127
131
|
method: 'POST',
|
|
132
|
+
signal: budget.signal,
|
|
128
133
|
headers: {
|
|
129
134
|
Accept: 'application/json',
|
|
130
135
|
'Content-Type': 'application/json',
|
|
131
136
|
Origin: 'https://www.colisweb.com',
|
|
132
137
|
Referer: 'https://www.colisweb.com/suivi-livraison',
|
|
133
|
-
'User-Agent':
|
|
138
|
+
'User-Agent': this.#userAgent,
|
|
134
139
|
},
|
|
135
140
|
body: coliswebRequestBody(trackingNumber),
|
|
136
141
|
}, {
|
|
137
142
|
provider: 'Colisweb tracking',
|
|
138
|
-
timeoutMs: this.timeoutMs,
|
|
143
|
+
timeoutMs: Math.min(this.timeoutMs, budget.remainingMs()),
|
|
139
144
|
maxBytes: MAX_RESPONSE_BYTES,
|
|
140
145
|
redirect: 'error',
|
|
141
146
|
allowHttpError: true,
|
|
@@ -157,10 +162,10 @@ export class ColiswebTracker {
|
|
|
157
162
|
}
|
|
158
163
|
}
|
|
159
164
|
export const adapter = (environment) => {
|
|
160
|
-
const tracker = new ColiswebTracker({ fetcher: environment.fetcher });
|
|
165
|
+
const tracker = new ColiswebTracker({ fetcher: environment.fetcher, userAgent: environment.userAgent });
|
|
161
166
|
return {
|
|
162
167
|
id: 'colisweb',
|
|
163
168
|
steps: ['direct'],
|
|
164
|
-
track: (input) => tracker.fetch(input.number),
|
|
169
|
+
track: (input, context) => tracker.fetch(input.number, context),
|
|
165
170
|
};
|
|
166
171
|
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { DateTime, IANAZone } from 'luxon';
|
|
2
2
|
import { isValidS10TrackingNumber } from '../../core/detection/s10.js';
|
|
3
|
-
import { ChallengeError, IndeterminateError, SchemaError } from '../../core/errors/index.js';
|
|
3
|
+
import { ChallengeError, IndeterminateError, InvalidInputError, SchemaError } from '../../core/errors/index.js';
|
|
4
4
|
import { clean } from '../../core/transport/index.js';
|
|
5
5
|
import { isRecord } from '../../core/types.js';
|
|
6
6
|
import { classifyCorreiosStatus } from './status.js';
|
|
7
7
|
export function normalizeCorreiosNumber(raw) {
|
|
8
8
|
const number = raw.toUpperCase().replace(/[\s.-]/g, '');
|
|
9
9
|
if (!/^[A-Z]{2}\d{9}[A-Z]{2}$/.test(number) || !isValidS10TrackingNumber(number)) {
|
|
10
|
-
throw new
|
|
10
|
+
throw new InvalidInputError('Correios', 'Correios requires a valid postal S10 tracking number');
|
|
11
11
|
}
|
|
12
12
|
return number;
|
|
13
13
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isValidS10TrackingNumber } from '../../core/detection/s10.js';
|
|
2
|
-
import { ChallengeError, IndeterminateError, RateLimitedError, SchemaError } from '../../core/errors/index.js';
|
|
2
|
+
import { ChallengeError, IndeterminateError, InvalidInputError, RateLimitedError, SchemaError } from '../../core/errors/index.js';
|
|
3
3
|
import { calendarDay } from '../../core/time/index.js';
|
|
4
4
|
import { clean } from '../../core/transport/index.js';
|
|
5
5
|
import { isRecord } from '../../core/types.js';
|
|
@@ -10,11 +10,11 @@ const RESOURCE = 'cl_cch_seguimiento_portlet_seguimientoresurcecommand';
|
|
|
10
10
|
const ALLOWED_PARAMS = new Set(['p_p_id', 'p_p_lifecycle', 'p_p_state', 'p_p_mode', 'p_p_resource_id', 'p_p_cacheability']);
|
|
11
11
|
export function normalizeCorreosChileNumber(raw) {
|
|
12
12
|
if (raw.length > 48)
|
|
13
|
-
throw new
|
|
13
|
+
throw new InvalidInputError('Correos de Chile', 'Correos de Chile tracking number is too long');
|
|
14
14
|
const number = raw.toUpperCase().replace(/[\s.-]/g, '');
|
|
15
15
|
if (/^\d{13}$/.test(number) || (/^[A-Z]{2}\d{9}CL$/.test(number) && isValidS10TrackingNumber(number)))
|
|
16
16
|
return number;
|
|
17
|
-
throw new
|
|
17
|
+
throw new InvalidInputError('Correos de Chile', 'Correos de Chile requires 13 digits or a valid Chilean postal number');
|
|
18
18
|
}
|
|
19
19
|
export function parseCorreosChileBootstrap(html) {
|
|
20
20
|
if (/Radware (?:Captcha )?Page|We apologize for the inconvenience|Please solve this CAPTCHA/i.test(html)) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { load } from 'cheerio';
|
|
2
2
|
import { DateTime } from 'luxon';
|
|
3
|
-
import { IndeterminateError, NotFoundError, SchemaError } from '../../core/errors/index.js';
|
|
3
|
+
import { IndeterminateError, InvalidInputError, NotFoundError, SchemaError } from '../../core/errors/index.js';
|
|
4
4
|
import { calendarDay } from '../../core/time/index.js';
|
|
5
5
|
import { clean } from '../../core/transport/index.js';
|
|
6
6
|
import { classifyCorreosExpressStatus } from './status.js';
|
|
@@ -10,7 +10,7 @@ const FAILED_ROUND = 'Su envío no ha podido ser entregado';
|
|
|
10
10
|
export function normalizeCorreosExpressNumber(raw) {
|
|
11
11
|
const number = raw.replace(/[\s.-]/g, '');
|
|
12
12
|
if (!/^\d{16}$/.test(number))
|
|
13
|
-
throw new
|
|
13
|
+
throw new InvalidInputError('Correos Express', 'Correos Express requires a 16-digit shipment number');
|
|
14
14
|
return number;
|
|
15
15
|
}
|
|
16
16
|
function scanClock(raw) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AdapterFactory, type TrackingContext } from '../../core/adapter/index.js';
|
|
2
2
|
import type { CarrierResult } from '../../core/result/index.js';
|
|
3
3
|
export declare function normalizeCorreosSpainTrackingNumber(raw: string): string;
|
|
4
4
|
export declare function correosSpainTrackingUrl(rawTrackingNumber: string): string;
|
|
@@ -6,10 +6,12 @@ export declare function parseCorreosSpainTrackingResponse(payload: unknown, trac
|
|
|
6
6
|
export declare class CorreosSpainTracker {
|
|
7
7
|
readonly timeoutMs: number;
|
|
8
8
|
readonly fetcher: typeof fetch | undefined;
|
|
9
|
+
private readonly userAgent;
|
|
9
10
|
constructor(options?: {
|
|
10
11
|
timeoutMs?: number;
|
|
11
12
|
fetcher?: typeof fetch;
|
|
13
|
+
userAgent?: string;
|
|
12
14
|
});
|
|
13
|
-
fetch(rawTrackingNumber: string): Promise<CarrierResult>;
|
|
15
|
+
fetch(rawTrackingNumber: string, context?: TrackingContext): Promise<CarrierResult>;
|
|
14
16
|
}
|
|
15
17
|
export declare const adapter: AdapterFactory;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { lookupBudget } from '../../core/adapter/index.js';
|
|
2
|
+
import { InvalidInputError, NotFoundError, SchemaError } from '../../core/errors/index.js';
|
|
2
3
|
import { zonedTime } from '../../core/time/index.js';
|
|
3
|
-
import { clean, fetchBounded, parseJsonBytes, UpstreamHttpError } from '../../core/transport/index.js';
|
|
4
|
+
import { clean, fetchBounded, parseJsonBytes, UpstreamHttpError, userAgentOf } from '../../core/transport/index.js';
|
|
4
5
|
import { isRecord } from '../../core/types.js';
|
|
5
6
|
import { classifyCorreosSpainStatus } from './status.js';
|
|
6
7
|
// Protocol provenance:
|
|
@@ -16,6 +17,8 @@ import { classifyCorreosSpainStatus } from './status.js';
|
|
|
16
17
|
// attempt → office hold → collected); the map lives in status.ts.
|
|
17
18
|
const TRACKING_ENDPOINT = 'https://localizador.correos.es/canonico/eventos_envio_servicio';
|
|
18
19
|
const DEFAULT_TIMEOUT_MS = 15_000;
|
|
20
|
+
/** `fetchBounded` repeats a request that failed in transit once, after this pause. */
|
|
21
|
+
const TRANSIENT_RETRY_DELAY_MS = 1_000;
|
|
19
22
|
const MAX_RESPONSE_BYTES = 1_000_000;
|
|
20
23
|
const MAX_EVENTS_TO_RETURN = 20;
|
|
21
24
|
function parsedTime(dateValue, timeValue) {
|
|
@@ -33,7 +36,7 @@ export function normalizeCorreosSpainTrackingNumber(raw) {
|
|
|
33
36
|
// PR-prefixed); the codError envelope — not the shape — decides unknown.
|
|
34
37
|
const value = raw.toLocaleUpperCase('en-US').replace(/[\s.-]/g, '');
|
|
35
38
|
if (!/^[A-Z0-9]{4,40}$/.test(value) || !/\d/.test(value)) {
|
|
36
|
-
throw new
|
|
39
|
+
throw new InvalidInputError('Correos', 'Correos tracking requires a tracking code with letters, numbers and a digit');
|
|
37
40
|
}
|
|
38
41
|
return value;
|
|
39
42
|
}
|
|
@@ -151,26 +154,31 @@ export function parseCorreosSpainTrackingResponse(payload, trackingNumber) {
|
|
|
151
154
|
export class CorreosSpainTracker {
|
|
152
155
|
timeoutMs;
|
|
153
156
|
fetcher;
|
|
157
|
+
userAgent;
|
|
154
158
|
constructor(options = {}) {
|
|
155
159
|
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
156
160
|
this.fetcher = options.fetcher;
|
|
161
|
+
this.userAgent = userAgentOf(options.userAgent);
|
|
157
162
|
if (!Number.isFinite(this.timeoutMs) || this.timeoutMs <= 0) {
|
|
158
163
|
throw new TypeError('Correos tracking timeout must be positive');
|
|
159
164
|
}
|
|
160
165
|
}
|
|
161
|
-
async fetch(rawTrackingNumber) {
|
|
166
|
+
async fetch(rawTrackingNumber, context = {}) {
|
|
162
167
|
const trackingNumber = normalizeCorreosSpainTrackingNumber(rawTrackingNumber);
|
|
168
|
+
// The default budget covers the request, the pause and the one transient retry.
|
|
169
|
+
const budget = lookupBudget(context, 2 * this.timeoutMs + TRANSIENT_RETRY_DELAY_MS);
|
|
163
170
|
const url = `${TRACKING_ENDPOINT}/${encodeURIComponent(trackingNumber)}`
|
|
164
171
|
+ '?codAplicacion=60&codCanal=3&codIdioma=ES&indUltEvento=N';
|
|
165
172
|
const { response, bytes } = await fetchBounded(url, {
|
|
173
|
+
signal: budget.signal,
|
|
166
174
|
headers: {
|
|
167
175
|
Accept: 'application/json, text/plain, */*',
|
|
168
176
|
'Accept-Language': 'en-US,en;q=0.9',
|
|
169
|
-
'User-Agent':
|
|
177
|
+
'User-Agent': this.userAgent,
|
|
170
178
|
},
|
|
171
179
|
}, {
|
|
172
180
|
provider: 'Correos tracking',
|
|
173
|
-
timeoutMs: this.timeoutMs,
|
|
181
|
+
timeoutMs: Math.min(this.timeoutMs, budget.remainingMs()),
|
|
174
182
|
maxBytes: MAX_RESPONSE_BYTES,
|
|
175
183
|
retryTransient: true,
|
|
176
184
|
allowHttpError: true,
|
|
@@ -182,10 +190,10 @@ export class CorreosSpainTracker {
|
|
|
182
190
|
}
|
|
183
191
|
}
|
|
184
192
|
export const adapter = (environment) => {
|
|
185
|
-
const tracker = new CorreosSpainTracker({ fetcher: environment.fetcher });
|
|
193
|
+
const tracker = new CorreosSpainTracker({ fetcher: environment.fetcher, userAgent: environment.userAgent });
|
|
186
194
|
return {
|
|
187
195
|
id: 'correos-spain',
|
|
188
196
|
steps: ['direct'],
|
|
189
|
-
track: (input) => tracker.fetch(input.number),
|
|
197
|
+
track: (input, context) => tracker.fetch(input.number, context),
|
|
190
198
|
};
|
|
191
199
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AdapterFactory, type TrackingContext } from '../../core/adapter/index.js';
|
|
2
2
|
import { IndeterminateError, MaintenanceError } from '../../core/errors/index.js';
|
|
3
3
|
import type { CarrierResult } from '../../core/result/index.js';
|
|
4
4
|
/** A CTT maintenance window: the backend is up but refuses to answer lookups. */
|
|
@@ -22,7 +22,7 @@ export declare class CttTracker {
|
|
|
22
22
|
timeoutMs?: number;
|
|
23
23
|
fetcher?: typeof fetch;
|
|
24
24
|
});
|
|
25
|
-
fetch(rawTrackingNumber: string): Promise<CarrierResult>;
|
|
25
|
+
fetch(rawTrackingNumber: string, context?: TrackingContext): Promise<CarrierResult>;
|
|
26
26
|
private isMaintenance;
|
|
27
27
|
private callAction;
|
|
28
28
|
private ensureApiVersion;
|