universal-parcel-scraper 0.3.0-main.298 → 0.3.0-main.302

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 CHANGED
@@ -1,22 +1,26 @@
1
1
  <div align="center">
2
2
 
3
- <img src="docs/assets/logo.svg" width="88" alt="">
3
+ <img src="docs/assets/pip.svg" width="112" alt="Pip, a kraft parcel with a face">
4
4
 
5
5
  # Universal Parcel Scraper
6
6
 
7
7
  **Parcel tracking that asks the carrier directly, from your own machine.**
8
8
 
9
+ The engine behind [Peek](https://github.com/plhery/delivery-tracker), the open-source parcel tracker for iPhone and the web.
10
+
9
11
  [![npm](https://img.shields.io/npm/v/universal-parcel-scraper)](https://www.npmjs.com/package/universal-parcel-scraper)
10
12
  [![CI](https://github.com/plhery/universal-parcel-scraper/actions/workflows/ci.yml/badge.svg)](https://github.com/plhery/universal-parcel-scraper/actions/workflows/ci.yml)
11
13
  [![License: Apache-2.0](https://img.shields.io/badge/core-Apache--2.0-blue.svg)](LICENSE)
12
14
 
13
15
  <!-- GENERATED:summary -->
14
- **105 carriers · 85 active dedicated adapters · 58 countries represented**
16
+ **3,500+ carriers** through **85 dedicated adapters** and **5 universal fallbacks**
17
+
18
+ <sub>105 carriers in the catalog · 58 countries represented</sub>
15
19
  <!-- /GENERATED:summary -->
16
20
 
17
21
  [Try it](#try-it) · [Ways to run it](#ways-to-run-it) · [Coverage](#how-much-can-it-track) · [Carriers](carriers/) · [Add a carrier](CONTRIBUTING.md)
18
22
 
19
- <img src="docs/assets/demo.svg" width="840" alt="The track command printing a parcel's history as JSON, next to a timeline drawn from it">
23
+ <img src="docs/assets/terminal.svg" width="840" alt="A terminal session: the detect command names UPS as the carrier of a tracking number, then the track command prints a parcel's scans with their stages">
20
24
 
21
25
  </div>
22
26
 
@@ -24,10 +28,15 @@ Give it a tracking number. It works out which carrier the number belongs to and
24
28
  history from that carrier's own website. What comes back has one shape, so a UPS parcel and
25
29
  a Poczta Polska parcel look the same to your code.
26
30
 
27
- There is no account to open and no API key. Every carrier publishes tracking in its own way,
28
- and hosted tracking APIs smooth that over for a fee while seeing every number you look up.
29
- Here the same work is open code: one adapter per carrier, each in [its own folder](carriers/)
30
- with a README on how that site is read.
31
+ There is no account to open and no API key. The carriers it knows best each have a dedicated
32
+ adapter in [their own folder](carriers/), with a README on how that site is read. For the
33
+ rest it can ask the universal trackers such as 17TRACK and Ship24, which is where the big
34
+ number above comes from. Those stay off until you switch them on, and each one you enable
35
+ sees the numbers you send it.
36
+
37
+ It started as the tracking engine inside [Peek](https://github.com/plhery/delivery-tracker)
38
+ and was pulled out so it can be used on its own. It runs as a command-line tool and as a Node
39
+ library, and it can serve the same lookups over HTTP.
31
40
 
32
41
  ## Try it
33
42
 
@@ -138,8 +147,8 @@ The image runs `serve` and ships Chromium, for the carriers that only answer a r
138
147
 
139
148
  ## What you can build with it
140
149
 
141
- - **A tracking screen in your own app.** [Delivery Tracker](https://github.com/plhery/delivery-tracker),
142
- an open-source iPhone app and PWA, runs on this package.
150
+ - **A parcel-tracking app.** [Peek](https://github.com/plhery/delivery-tracker) is the
151
+ full-size example: an iPhone and web app built on this package.
143
152
  - **A Home Assistant sensor** for the parcel you are waiting on.
144
153
  [The config is in examples](examples/home-assistant.yaml).
145
154
  - **Order status inside a shop or help desk**, so customers are not sent off to the carrier's
@@ -156,7 +165,7 @@ are yours to do.
156
165
 
157
166
  <picture>
158
167
  <source media="(prefers-color-scheme: dark)" srcset="docs/assets/how-it-works-dark.svg">
159
- <img src="docs/assets/how-it-works-light.svg" width="840" alt="An input is detected offline and tracked by the carrier's dedicated adapter. With no history, the lookup moves to the fallbacks you enabled. Either way the result is one timeline.">
168
+ <img src="docs/assets/how-it-works-light.svg" width="840" alt="An input is detected offline and fetched by the carrier's dedicated adapter, or by a fallback you enabled when that finds no history. Each scan's wording is filed under a stage, and the result is one timeline.">
160
169
  </picture>
161
170
 
162
171
  Each adapter uses plain HTTP wherever the carrier's site allows it. Some sites only answer a
@@ -181,14 +190,35 @@ one you enable receives the tracking number:
181
190
  createTracker({ providers: ['ParcelsApp', 'Ship24', '17TRACK', 'Postal Ninja', 'UPU'] });
182
191
  ```
183
192
 
193
+ ### One stage list
194
+
195
+ Carriers describe the same moment in their own words, or with a bare code. Each carrier
196
+ folder keeps a `statuses.json` with the codes and wordings seen from that carrier and the
197
+ stage each one means. Every entry also says how it was confirmed, by a live reply or the
198
+ carrier's own documentation for instance.
199
+
200
+ <!-- GENERATED:stages -->
201
+ <picture>
202
+ <source media="(prefers-color-scheme: dark)" srcset="docs/assets/stages-dark.svg">
203
+ <img src="docs/assets/stages-light.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">
204
+ </picture>
205
+
206
+ The folders hold 1,671 recorded statuses from 88 carriers.
207
+ <!-- /GENERATED:stages -->
208
+
209
+ A scan nobody has recorded yet goes through a shared classifier that reads English, French,
210
+ German, Italian, Spanish, Portuguese and Polish. Each scan in the result carries a
211
+ `stage_source` saying which of the two decided.
212
+
184
213
  [ARCHITECTURE.md](ARCHITECTURE.md) has the rest.
185
214
 
186
215
  ## How much can it track?
187
216
 
188
- A carrier count says what the catalog knows about. Whether a real parcel comes back with its
189
- history is a different question, so each source was run on its own against the same
190
- **100-carrier reference set**. The top bar counts a carrier when any source below it returned
191
- a history.
217
+ The number at the top of this page is reach: with the fallbacks on, a lookup can go to the
218
+ largest aggregator, and [reach.json](docs/reach.json) records how many carriers each one
219
+ says it follows. Whether a real parcel comes back with its history is a different question,
220
+ so each source was run on its own against the same **100-carrier reference set**. The top
221
+ bar counts a carrier when any source below it returned a history.
192
222
 
193
223
  <!-- GENERATED:coverage -->
194
224
  <picture>
@@ -225,15 +255,15 @@ or a promise about today, because parcels expire and carrier sites change.
225
255
  | Account | None | Sign-up and an API key |
226
256
  | Cost | Your own compute | A plan or a per-shipment price |
227
257
  | Who sees the tracking number | The carrier, plus any fallback you enable | The vendor, then the carrier |
228
- | Carriers | The [catalog](carriers/) in this repository | A much larger catalog |
258
+ | Carriers | Dedicated adapters for the [catalog](carriers/), fallbacks for the rest | One large catalog |
229
259
  | Updates | You poll | Webhooks |
230
260
  | When a carrier changes its site | The adapter breaks until it is fixed here | The vendor deals with it |
231
261
  | Hosting | Yours | Theirs |
232
262
 
233
- If you want the widest catalog and nothing to run, a hosted API is the better choice. This
234
- project is for when the numbers should stay on your side, or when a price per parcel makes
235
- no sense for what you are building. Vendor catalog totals are not comparable with the
236
- reference test above.
263
+ If you want webhooks and nothing to run, a hosted API is the better choice. This project is
264
+ for when the numbers should stay on your side, or when a price per parcel makes no sense for
265
+ what you are building. Vendor catalog totals are not comparable with the reference test
266
+ above.
237
267
 
238
268
  ## Privacy and limits
239
269
 
@@ -172,7 +172,7 @@ export const adapter = (environment) => {
172
172
  executablePath: environment.browserExecutablePath ?? undefined, recorder: environment.recorder,
173
173
  });
174
174
  return {
175
- id: 'dhl-ecommerce',
175
+ id: 'dhl-ecommerce', recordsSteps: true,
176
176
  steps: ['browser'],
177
177
  track: (input, context) => tracker.fetch(input.number, context),
178
178
  };
@@ -303,7 +303,7 @@ export const adapter = (environment) => {
303
303
  recorder: environment.recorder,
304
304
  });
305
305
  return {
306
- id: 'fedex',
306
+ id: 'fedex', recordsSteps: true,
307
307
  // Browser-backed direct tracking; universal recovery belongs to the caller.
308
308
  steps: ['trawl'],
309
309
  track: (input, context) => tracker.fetch(input.number, context),
@@ -353,7 +353,7 @@ export const adapter = (environment) => {
353
353
  recorder: environment.recorder,
354
354
  });
355
355
  return {
356
- id: 'mondial-relay',
356
+ id: 'mondial-relay', recordsSteps: true,
357
357
  // Cloudflare refuses every non-browser client, so there is no direct tier.
358
358
  steps: ['trawl'],
359
359
  track: (input, context) => tracker.fetch(input.number, input.postcode ?? '', context),
@@ -256,7 +256,7 @@ export const adapter = (environment) => {
256
256
  recorder: environment.recorder,
257
257
  });
258
258
  return {
259
- id: 'royal-mail',
259
+ id: 'royal-mail', recordsSteps: true,
260
260
  // Akamai refuses every non-browser client, so there is no direct tier.
261
261
  steps: ['trawl'],
262
262
  track: (input, context) => tracker.fetch(input.number, context),
@@ -257,7 +257,7 @@ export const adapter = (environment) => {
257
257
  recorder: environment.recorder,
258
258
  });
259
259
  return {
260
- id: 'usps',
260
+ id: 'usps', recordsSteps: true,
261
261
  // Akamai refuses every non-browser client, so there is no direct tier.
262
262
  steps: ['trawl'],
263
263
  track: (input, context) => tracker.fetch(input.number, context),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-parcel-scraper",
3
- "version": "0.3.0-main.298",
3
+ "version": "0.3.0-main.302",
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",