Compare commits

...

1158 commits
v2.5.0 ... main

Author SHA1 Message Date
Traines
b59d7b3084 fix docs
[skip ci]
2025-04-27 17:13:10 +00:00
Traines
db4c03054a cspell...
Some checks failed
test / lint-and-spellcheck (push) Has been cancelled
test / unit-tests (18.x) (push) Has been cancelled
test / unit-tests (20.x) (push) Has been cancelled
test / unit-tests (22.x) (push) Has been cancelled
test / integration-tests (18.x) (push) Has been cancelled
test / integration-tests (20.x) (push) Has been cancelled
test / integration-tests (22.x) (push) Has been cancelled
test / e2e-tests (18.x) (push) Has been cancelled
2025-04-11 21:05:18 +00:00
Traines
eac21d188b 6.8.1 2025-04-11 20:59:29 +00:00
Traines
ad09f8b1be dticket support 2025-04-11 20:59:06 +00:00
Traines
c4d0a55d41 docs
Some checks failed
test / lint-and-spellcheck (push) Has been cancelled
test / unit-tests (18.x) (push) Has been cancelled
test / unit-tests (20.x) (push) Has been cancelled
test / unit-tests (22.x) (push) Has been cancelled
test / integration-tests (18.x) (push) Has been cancelled
test / integration-tests (20.x) (push) Has been cancelled
test / integration-tests (22.x) (push) Has been cancelled
test / e2e-tests (18.x) (push) Has been cancelled
2025-03-22 00:56:43 +00:00
Traines
29aab87cdf add dbbahnhof 2025-03-22 00:39:43 +00:00
Traines
883eb8c8de refactor 2025-03-21 21:13:20 +00:00
Traines
b20cf1060a add dbris, moreStops param 2025-03-21 20:49:38 +00:00
Traines
b887c674d4 fix param parsing for refreshJourney
Some checks failed
test / lint-and-spellcheck (push) Has been cancelled
test / unit-tests (18.x) (push) Has been cancelled
test / unit-tests (20.x) (push) Has been cancelled
test / unit-tests (22.x) (push) Has been cancelled
test / integration-tests (18.x) (push) Has been cancelled
test / integration-tests (20.x) (push) Has been cancelled
test / integration-tests (22.x) (push) Has been cancelled
test / e2e-tests (18.x) (push) Has been cancelled
2025-03-20 10:58:32 +00:00
Traines
b3e0e764e2 update db-hafas-stations
Some checks failed
test / lint-and-spellcheck (push) Has been cancelled
test / unit-tests (18.x) (push) Has been cancelled
test / unit-tests (20.x) (push) Has been cancelled
test / unit-tests (22.x) (push) Has been cancelled
test / integration-tests (18.x) (push) Has been cancelled
test / integration-tests (20.x) (push) Has been cancelled
test / integration-tests (22.x) (push) Has been cancelled
test / e2e-tests (18.x) (push) Has been cancelled
2025-03-19 00:39:01 +00:00
Traines
2ea47f7792 disable some more live e2e tests 2025-03-19 00:38:48 +00:00
Traines
6c2081c14e fix spelling and tests...
Some checks failed
test / lint-and-spellcheck (push) Has been cancelled
test / unit-tests (18.x) (push) Has been cancelled
test / unit-tests (20.x) (push) Has been cancelled
test / unit-tests (22.x) (push) Has been cancelled
test / integration-tests (18.x) (push) Has been cancelled
test / integration-tests (20.x) (push) Has been cancelled
test / integration-tests (22.x) (push) Has been cancelled
test / e2e-tests (18.x) (push) Has been cancelled
2025-03-15 23:25:48 +00:00
Traines
f741a13670 docs 2025-03-15 23:15:40 +00:00
Traines
bcaad526c7 disable blocked endpoints tests for now 2025-03-15 22:54:12 +00:00
Traines
162b946bac support for bestprice, notOnlyFastRoutes, serviceDays, fix param default handling 2025-03-15 22:44:08 +00:00
Traines
14b80dbf33 update deps
[skip ci]
2025-03-14 17:28:14 +00:00
Traines
1927f98906 fix station enrichment 2025-03-14 17:19:48 +00:00
Traines
0ef3935a35 update db-hafas-stations, bump version 2025-03-14 16:57:38 +00:00
Traines
b04a671b50 improve duration explanation 2025-03-14 16:57:02 +00:00
Traines
9975a6c9ac more reliable setup of proxy agent
Some checks failed
test / lint-and-spellcheck (push) Has been cancelled
test / unit-tests (18.x) (push) Has been cancelled
test / unit-tests (20.x) (push) Has been cancelled
test / unit-tests (22.x) (push) Has been cancelled
test / integration-tests (18.x) (push) Has been cancelled
test / integration-tests (20.x) (push) Has been cancelled
test / integration-tests (22.x) (push) Has been cancelled
test / e2e-tests (18.x) (push) Has been cancelled
2025-03-08 23:12:36 +00:00
Traines
960371e2ec v6.6.1
Some checks failed
test / lint-and-spellcheck (push) Has been cancelled
test / unit-tests (18.x) (push) Has been cancelled
test / unit-tests (20.x) (push) Has been cancelled
test / unit-tests (22.x) (push) Has been cancelled
test / integration-tests (18.x) (push) Has been cancelled
test / integration-tests (20.x) (push) Has been cancelled
test / integration-tests (22.x) (push) Has been cancelled
test / e2e-tests (18.x) (push) Has been cancelled
2025-03-06 20:22:05 +00:00
Traines
88acdd1620 enrichStations fix 2025-03-06 20:18:00 +00:00
dabund24
25cbb288ca
Fix dbnav time zone bug (#25)
* fix dbnav time zone bug

* test fix of dbnav time zone bug

* exclude `test/parse/dbnav-journey.js` from spell check
2025-03-06 21:13:08 +01:00
Kristjan ESPERANTO
a6e84be2df Add spell check to CI
Some checks are pending
test / lint-and-spellcheck (push) Waiting to run
test / unit-tests (18.x) (push) Waiting to run
test / unit-tests (20.x) (push) Waiting to run
test / unit-tests (22.x) (push) Waiting to run
test / integration-tests (18.x) (push) Waiting to run
test / integration-tests (20.x) (push) Waiting to run
test / integration-tests (22.x) (push) Waiting to run
test / e2e-tests (18.x) (push) Blocked by required conditions
2025-03-06 16:13:56 +01:00
Kristjan ESPERANTO
de63bf0a37 Fix typos found with cspell 2025-03-06 16:13:56 +01:00
Kristjan ESPERANTO
040a8f44e4 Add cspell 2025-03-06 16:13:56 +01:00
Traines
6b67a77823 v6.6.0
Some checks failed
test / lint (push) Has been cancelled
test / unit-tests (18.x) (push) Has been cancelled
test / unit-tests (20.x) (push) Has been cancelled
test / unit-tests (22.x) (push) Has been cancelled
test / integration-tests (18.x) (push) Has been cancelled
test / integration-tests (20.x) (push) Has been cancelled
test / integration-tests (22.x) (push) Has been cancelled
test / e2e-tests (18.x) (push) Has been cancelled
2025-03-02 13:39:35 +00:00
Kristjan ESPERANTO
debb45a929
Update dependencies (#21) 2025-03-02 14:32:29 +01:00
Kristjan ESPERANTO
53b385a865
Replace lodash by modern JavaScript functions (#20)
Some checks are pending
test / lint (push) Waiting to run
test / unit-tests (18.x) (push) Waiting to run
test / unit-tests (20.x) (push) Waiting to run
test / unit-tests (22.x) (push) Waiting to run
test / integration-tests (18.x) (push) Waiting to run
test / integration-tests (20.x) (push) Waiting to run
test / integration-tests (22.x) (push) Waiting to run
test / e2e-tests (18.x) (push) Blocked by required conditions
* Replace lodash by built-in functions

* .flatMap -> .flat
2025-03-01 17:30:58 +01:00
Traines
185870db3d cleanup
Some checks failed
test / lint (push) Has been cancelled
test / unit-tests (18.x) (push) Has been cancelled
test / unit-tests (20.x) (push) Has been cancelled
test / unit-tests (22.x) (push) Has been cancelled
test / integration-tests (18.x) (push) Has been cancelled
test / integration-tests (20.x) (push) Has been cancelled
test / integration-tests (22.x) (push) Has been cancelled
test / e2e-tests (18.x) (push) Has been cancelled
2025-02-25 12:56:29 +00:00
Traines
16829f839c add back HTTP_PROXY support 2025-02-25 12:52:50 +00:00
Traines
9fe4972d2b fix includeRelatedStations 2025-02-25 12:23:26 +00:00
McToel
1aeb246622
Browser compatibility (#17)
* Removed Proxy and local address code

* replaced node crypto with web crypto

* Replaced require with static imports

* removed commented out imports

* import db-hafas-stations on demand

* trying to handle undefined envs

* Less optimistic variable handling

* cleanup

* Small browser docs addition

* Linting

* No async in new Promise

* Bumped eslint to v9 and ecmaScript to 2025

* removed duplicated eslint config

* Bumped minimal node version to node 18

* Added node 24

* using math.random instead of webcrypto and reintroduced randomizeUserAgent

* Oh no node 24 is actually not released yet

* removed temp debug file
2025-02-25 13:21:26 +01:00
Kristjan ESPERANTO
6d1d0c626f Upgrade ESLint and fix linting issues
Some checks failed
test / lint (push) Has been cancelled
test / unit-tests (16.x) (push) Has been cancelled
test / unit-tests (18.x) (push) Has been cancelled
test / unit-tests (20.x) (push) Has been cancelled
test / unit-tests (22.x) (push) Has been cancelled
test / integration-tests (16.x) (push) Has been cancelled
test / integration-tests (18.x) (push) Has been cancelled
test / integration-tests (20.x) (push) Has been cancelled
test / integration-tests (22.x) (push) Has been cancelled
test / e2e-tests (18.x) (push) Has been cancelled
2025-02-17 21:41:20 +01:00
Kristjan ESPERANTO
afa99b0742
Review test workflow (#16)
Some checks are pending
test / lint (push) Waiting to run
test / unit-tests (16.x) (push) Waiting to run
test / unit-tests (18.x) (push) Waiting to run
test / unit-tests (20.x) (push) Waiting to run
test / unit-tests (22.x) (push) Waiting to run
test / integration-tests (16.x) (push) Waiting to run
test / integration-tests (18.x) (push) Waiting to run
test / integration-tests (20.x) (push) Waiting to run
test / integration-tests (22.x) (push) Waiting to run
test / e2e-tests (18.x) (push) Blocked by required conditions
* Run linting only once

* Update actions/cache to v4

* Run e2e-tests with the same matrix as the others

* Change cache keys to avoid cache collisions

* Run e2e-tests only once
Since they go against the live DB APIs #16
2025-02-17 19:09:14 +01:00
Kristjan ESPERANTO
229dbac93e
Update copyright information (#15)
Some checks failed
test / unit-tests (16.x) (push) Has been cancelled
test / unit-tests (18.x) (push) Has been cancelled
test / unit-tests (20.x) (push) Has been cancelled
test / unit-tests (22.x) (push) Has been cancelled
test / integration-tests (16.x) (push) Has been cancelled
test / integration-tests (18.x) (push) Has been cancelled
test / integration-tests (20.x) (push) Has been cancelled
test / integration-tests (22.x) (push) Has been cancelled
test / e2e-tests (16.x) (push) Has been cancelled
2025-02-14 22:33:50 +01:00
Traines
7a1e513fa2 6.5.0
Some checks are pending
test / unit-tests (16.x) (push) Waiting to run
test / unit-tests (18.x) (push) Waiting to run
test / unit-tests (20.x) (push) Waiting to run
test / unit-tests (22.x) (push) Waiting to run
test / integration-tests (16.x) (push) Waiting to run
test / integration-tests (18.x) (push) Waiting to run
test / integration-tests (20.x) (push) Waiting to run
test / integration-tests (22.x) (push) Waiting to run
test / e2e-tests (16.x) (push) Blocked by required conditions
2025-02-13 23:34:39 +00:00
Traines
f1302b0a7b docs 2025-02-13 23:33:45 +00:00
Traines
177a3cab3f migrate and update loyaltyCard parsing from db-rest 2025-02-13 23:32:01 +00:00
Traines
71d1a4f1a9 refactor enrichStations, only load on first request 2025-02-13 22:16:22 +00:00
Traines
6ff406ea79 artificially filter for includeRelatedStations and direction 2025-02-13 21:53:49 +00:00
Traines
2a23e1ad9b make dbweb selectable in docker img 2025-02-13 19:41:46 +00:00
Traines
9314e59053 6.4.0
Some checks failed
test / unit-tests (16.x) (push) Has been cancelled
test / unit-tests (18.x) (push) Has been cancelled
test / unit-tests (20.x) (push) Has been cancelled
test / unit-tests (22.x) (push) Has been cancelled
test / integration-tests (16.x) (push) Has been cancelled
test / integration-tests (18.x) (push) Has been cancelled
test / integration-tests (20.x) (push) Has been cancelled
test / integration-tests (22.x) (push) Has been cancelled
test / e2e-tests (16.x) (push) Has been cancelled
2025-02-11 21:20:33 +00:00
Traines
69c098744a update docs 2025-02-11 21:16:23 +00:00
dabund24
c671e995cb
bahn.de boards (#12)
* parse bahn.de boards

* add optional chaining in line.js

* unit tests for bahn.de boards

* fix product check in line.js for bahn.de boards

* add integration tests for bahn.de boards

* allow letting hafas decide the amount of vias

* split dbweb and dbregioguide profiles; add db profile

* commit location-filter.js (forgot that in the last commit)

* simplify how db profile works

* remove `ezGleis` from coalesce for scheduled platform

* un-break parsing of remarks

* determine fahrtNr by removing all non-digits

* employ enrichStations for board stop property

* prevent timeouts in dbweb e2e test from calling `end()` twice

* use promises in dbweb e2e tests when waiting for enrichStations to work

* replace vias option with stopovers option for dbweb profile; enrich stations when only name is known

* change dbweb-departures test covering enrichStation feature for stop and stopovers

* remove check for not existing option

* move verkehrsmittel.name in front of verkehrsmittel.langText when parsing name in line.js
2025-02-09 00:46:21 +01:00
Traines
1e7977a8bb linting... 2025-01-20 20:32:38 +00:00
Traines
ff559c83dd version bump, docs 2025-01-20 20:30:58 +00:00
Traines
76d6121f88 trim returned HAFAS journey ids (for better compat with hafas-client/raw HAFAS API) 2025-01-20 20:06:29 +00:00
Traines
206e709e6a adapt openapi.yaml
[skip ci]
2025-01-15 02:19:10 +00:00
Traines
7d10f409ef fix links
[skip ci]
2025-01-15 02:07:13 +00:00
Traines
179ada6f08 openapi spec
[skip ci]
2025-01-15 02:04:20 +00:00
Traines
4c8c503e48 version bump
[skip ci]
2025-01-14 22:36:03 +00:00
Traines
3c7227635a docs fixes
[skip ci]
2025-01-14 22:35:19 +00:00
Traines
22c839847f updat fixture for db poly endpoint 2025-01-14 22:24:53 +00:00
Traines
1b0858a253 update docs 2025-01-14 22:16:09 +00:00
Traines
a59a3d78dc add back hafas-client docs 2025-01-14 21:15:30 +00:00
Traines
911a6d371e db: support for polylines 2025-01-14 21:12:23 +00:00
Traines
2b55f7148f support db regio-guide trip id/endpoint 2025-01-14 21:07:23 +00:00
Traines
715541f060 refactor 2025-01-14 18:13:58 +00:00
Traines
70f4cdb2b0 linting 2025-01-11 23:38:00 +00:00
Traines
bb692f4bc9 use proper correlation id 2025-01-11 23:37:07 +00:00
Traines
977da80885 cleanup 2025-01-11 21:14:50 +00:00
Traines
01b95e74f4 add back cli 2025-01-11 20:55:46 +00:00
Traines
911ac17510 add priority where available as int (dbnav) 2025-01-11 19:08:52 +00:00
Traines
32792507ba pretty-print fixtures 2025-01-11 19:08:29 +00:00
Traines
60656b0119 db: create fake walking leg for intra-station transfer 2025-01-11 18:39:32 +00:00
Traines
232893f2dc dumps 2025-01-11 18:15:13 +00:00
Traines
41feb41b5a version bump 2025-01-10 18:59:32 +00:00
Traines
63bc542b1c improve line details (fahrtNr, name, id), add tests 2025-01-10 18:55:14 +00:00
Traines
a624e62172 disable enrichStations for tests 2025-01-10 18:52:16 +00:00
McToel
942972d5f0
Use risZuglaufId to get fahrtNr (#8) 2025-01-10 19:21:27 +01:00
Traines
8d07b24604 make dbnav default for docker image, require setting of user agent 2025-01-09 12:32:12 +00:00
Traines
126077582b parse admincode, operator where available 2025-01-09 12:26:42 +00:00
Traines
615c36650e bump version 2025-01-09 00:12:43 +00:00
Traines
bc676fd0b6 more tests, docs 2025-01-09 00:07:17 +00:00
Traines
98670d5e08 stop() 2025-01-08 23:24:40 +00:00
Traines
0e68a375e1 fix dockerfile 2025-01-08 23:24:40 +00:00
dabund24
632a29d2aa
Allow value -1 for transfers option in journeys() (#6)
* allow value -1 for transfers option in journeys() for db and dbnav profiles

* add unit test for implicitly unconstrained transfers

* implement `formatTransfers()`, use it `formatJourneysReq()` functions and re-add corresponding unit test
2025-01-09 00:22:43 +01:00
Traines
8026689ee8 update readme 2025-01-08 18:35:13 +00:00
Traines
d992961421 fix package config
[skip ci ]
2025-01-08 18:02:57 +00:00
Traines
31df18f4be ci...
[skip ci]
2025-01-08 17:54:07 +00:00
Traines
94e130f0d2 ci...
[skip ci]
2025-01-08 17:47:11 +00:00
Traines
9e69594a36 ci... 2025-01-08 17:35:13 +00:00
Traines
db12ea036d publish to npmjs
[skip ci]
2025-01-08 17:25:34 +00:00
Traines
de78b40da4 ci... 2025-01-03 13:07:05 +00:00
Traines
b431fe65b7 support multiple travellers 2025-01-03 12:46:37 +00:00
Traines
661024cedb version bump 2025-01-03 11:42:56 +00:00
Traines
db168b7a35 docs 2025-01-03 11:39:55 +00:00
Traines
d2a39b33c7 more dumps 2025-01-03 11:01:49 +00:00
Traines
87a705e966 dbnav journeys, trips, fixes 2025-01-03 10:57:24 +00:00
Traines
3d998de41c dbnav boards, fixes 2025-01-02 14:00:45 +00:00
Traines
6538f814aa fix regression... 2024-12-21 23:16:57 +00:00
Traines
debc1ee150 dbnav profile: locations, nearby 2024-12-21 23:04:05 +00:00
Traines
ad6c356552 more dumps 2024-12-21 22:39:37 +00:00
Traines
771ab128b3 more refactoring 2024-12-21 16:30:11 +00:00
Traines
9f5e1fa6bd refactoring journeysReq 2024-12-21 16:15:10 +00:00
Traines
ec723b3414 refactoring 2024-12-21 15:26:49 +00:00
Traines
bc56d41fbe ci... 2024-12-18 02:18:13 +00:00
Traines
d24a341def ci, docs 2024-12-18 02:02:05 +00:00
Traines
59bd56e824 docker image latest tag 2024-12-18 01:48:39 +00:00
Traines
73b4d40e02 trip by id support 2024-12-18 01:16:57 +00:00
Traines
e14a909ebf linting 2024-12-18 00:40:37 +00:00
Traines
2a49495959 don't validate products (race cond) 2024-12-18 00:34:56 +00:00
Traines
318644958a cleanup 2024-12-18 00:21:10 +00:00
Traines
4a932f0329 fix csp header 2024-12-18 00:10:59 +00:00
Traines
80195404bb enrich stations with db-hafas-stations 2024-12-18 00:10:49 +00:00
Traines
073d33e12f ci release 2024-12-17 23:06:20 +00:00
Traines
5c5c1acd44 don't set undefined price fields 2024-12-17 20:43:54 +00:00
Traines
e05b31e19c fix laterThan/earlierThan 2024-12-17 20:26:48 +00:00
Traines
0e2d0e32ab fix ci 2024-12-17 20:26:12 +00:00
Traines
e4a99d4be3 artificially limit number of results, fixes #2 2024-12-17 19:54:14 +00:00
Traines
ed8683e8c2 fix int tests and invalid fields 2024-12-17 19:41:00 +00:00
Traines
df81b5600d fix workflow 2024-12-17 16:07:39 +00:00
Traines
0aedad5192 build workflow 2024-12-17 16:04:41 +00:00
Traines
43ba0fe0be fix docker build 2024-12-17 15:39:56 +00:00
Traines
73d9c88ffb fix bad rename 2024-12-17 14:56:51 +00:00
Traines
6e0f3d66b9 drawbacks dbnav api 2024-12-16 21:35:23 +00:00
Traines
e87acc3e24 dbnav boards wip 2024-12-16 21:33:10 +00:00
Traines
175b166864 docs, dumps 2024-12-16 20:22:36 +00:00
Traines
30d84352ae remove hafas-client dep 2024-12-16 12:02:47 +00:00
Traines
5bb4e66c9a boards: correctly handle missing rt info 2024-12-12 12:10:09 +00:00
Traines
e18ac3f8d3 docs 2024-12-11 23:57:49 +00:00
Traines
760a1bdb54 refreshJourney with tickets, loyaltyCard/firstClass rest support, accept-lang 2024-12-11 23:51:58 +00:00
Traines
f379fba930 add Dockerfile 2024-12-10 22:50:15 +00:00
Traines
c6bb1b468a fixes for journeyID and fahrtNr 2024-12-10 22:49:11 +00:00
Traines
491348bd3b docs 2024-12-10 17:57:56 +00:00
Traines
c663a35711 switch to regio-guide ris for boards 2024-12-10 17:51:20 +00:00
Traines
f8a79834b3 linting 2024-12-08 21:42:57 +00:00
Traines
65aae69481 fixes 2024-12-07 23:59:04 +00:00
Traines
a2de274a90 fix readme 2024-12-07 23:56:34 +00:00
Traines
f5008fc747 update readme 2024-12-07 23:48:17 +00:00
Traines
0e328aa681 tests 2024-12-07 23:48:08 +00:00
Traines
80e633dcb7 arrival/departure, refactoring 2024-12-07 22:46:04 +00:00
Traines
2f45f66793 /locations, /locations/nearby, fixes 2024-12-07 18:29:16 +00:00
Traines
2e094c2b78 initial db-vendo with /journeys (wip) 2024-12-07 16:17:16 +00:00
Jannis R
e9211e8105
ÖBB E2E/integration tests: update mocked when, update fixtures 2024-09-26 00:42:35 +02:00
Jannis R
31c4f17b10
ÖBB: change ver to 1.45 🐛
fixes #233
2024-09-26 00:41:29 +02:00
Jannis R
08db80f165
changelog 📝; 6.3.2 2024-09-25 23:31:32 +02:00
Jannis R
e411a4b60e
SNCB: remove superfluous code & certificate 💚 2024-09-25 22:08:26 +02:00
Jannis R
b45449a20e
CI: don't lint more than once 💚 2024-09-25 21:56:15 +02:00
Jannis R
1d23bef765
CI: run tests with Node v22, too 💚 2024-09-25 21:55:44 +02:00
Jannis R
52f0dd19bb
SNCB E2E/integration tests: un-skip tests 2024-09-25 21:53:00 +02:00
Jannis R
96f97f245e
SNCB: remove hard-coded SSL CA certificate chain 🐛 2024-09-25 21:49:31 +02:00
Jannis R
d2b490a4ff
KVB: remove hard-coded SSL CA certificate chain 🐛 2024-09-25 21:49:04 +02:00
Jannis R
329c89c4d4
KVB: fix bitmask for Regionalverkehr product 🐛 2024-09-25 21:48:24 +02:00
Jannis R
3c8bb905f3
BVG E2E/integration tests: update mocked when, update fixtures
closes #323
2024-09-25 21:48:23 +02:00
Jannis R
d001fcc1a4
BVG: update HAFAS client details again 🐛 2024-09-25 21:48:23 +02:00
Tim von Werne
8377202866
BVG: update auth aid in order to fix "invalid client version" error 🐛
fixes #324
fixes https://github.com/public-transport/bvg-hafas/issues/2
fixes https://github.com/derhuerst/bvg-rest/issues/22

Co-Authored-By: Jannis R <mail@jannisr.de>
2024-09-25 21:48:20 +02:00
Jannis R
6da22a0a12
changelog 📝, add @1Maxnet1 as contributor; 6.3.1 2024-07-16 12:10:53 +02:00
Jannis R
97268d7a8a
DB: remove stop() v1.16 workaround
Also, `LocGeoPos`/nearby() doesn't seem to break with `getStops: false` anymore.
2024-07-16 12:10:43 +02:00
Jannis R
1a0b595a71
object-scan@19, tap@19 2024-07-15 19:23:31 +02:00
Max Buchholz
6e74b9ab60 Fix typo in journeys.md 2024-04-22 15:00:52 +02:00
Jannis R
65096a85b6
changelog 📝, add @PaulSut as contributor; 6.3.0 2024-03-20 17:00:07 +01:00
Jannis R
7f78dc9458
add todos & comments 2024-03-12 12:26:46 +01:00
Paul Sutter
d3bc9d351d
DB E2E tests: adjust assertValidTickets 2024-03-12 01:19:01 +01:00
Paul Sutter
191b9abb6d
DB: add parseLoyaltyCard utility function
Co-Authored-By: Jannis R <mail@jannisr.de>
2024-03-12 01:18:59 +01:00
Paul Sutter
c4966aeca7
DB: optionally parse ticket URLs
Co-Authored-By: Jannis R <mail@jannisr.de>
2024-03-12 01:18:56 +01:00
Paul Sutter
784d273adf
DB E2E tickets test: add fixtures
Co-Authored-By: Jannis R <mail@jannisr.de>
2024-03-12 01:18:54 +01:00
Paul Sutter
9365c00aaf
DB: add end-to-end test for tickets
Co-Authored-By: Jannis R <mail@jannisr.de>
2024-03-12 01:18:52 +01:00
Paul Sutter
248adb5f72
DB refreshJourney(): optionally request ticket infos
Co-Authored-By: Jannis R <mail@jannisr.de>
2024-03-12 01:18:50 +01:00
Paul Sutter
fd90abdeca
DB journeys()/refreshJourney(): parse tickets from reponse
Co-Authored-By: Jannis R <mail@jannisr.de>
2024-03-12 01:18:29 +01:00
Jannis R
c826100bc8
E2E/integration tests: sort fixtures 2024-03-12 01:18:21 +01:00
Jannis R
336a9ba115
E2E/integration tests: configure Polly.js HTTP adapter correctly, minor tweaks
remotely related: https://github.com/nock/nock/issues/2461

Also silence a warning about the browser being offline.
2024-02-25 22:06:41 +01:00
Jannis R
9eeafd0ae8
E2E/integration tests: make sure tap teardown runs
may be related: https://github.com/tapjs/tapjs/issues/1005
2024-02-25 22:04:14 +01:00
Jannis R
613609782d
changelog 📝; 6.2.2 2024-02-25 22:00:02 +01:00
Jannis R
90b1140401
radar(): relax bounding box checks 🐛
to allow crossing the antimeridian & poles

fixes https://github.com/derhuerst/hafas-monitor-trips/issues/12
2024-02-25 21:36:23 +01:00
Kristjan ESPERANTO
66d9fb5194
apply linting rules
follow-up of 228c7253
2024-02-10 16:50:12 +01:00
Kristjan ESPERANTO
228c72531b
linting: add rules based on @stylistic/eslint-plugin
Co-Authored-By: Jannis R <mail@jannisr.de>
2024-02-10 16:49:38 +01:00
Jannis R
26c56f8dc6
fix date of next-day DEVI leg in an overnight journey 🐛
follow-up of a2870f6a
follow-up of 6e6285c7
fixes #301
2024-01-28 20:47:18 +01:00
Jannis R
c85f083db5
overnight journey with next-day leg: add a working test case
follow-up of a2870f6a
related: #301
2024-01-28 20:47:18 +01:00
Soeren Wegener
8a17401693
reproduce #301: leg of an overnight journey completely within the next day
Co-Authored-By: Jannis R <mail@jannisr.de>
2024-01-28 20:47:18 +01:00
Jannis R
eec06ba81a
changelog 📝; 6.2.1 2024-01-18 15:34:23 +01:00
Jannis R
a157d0b15f
put todos 2024-01-18 15:27:35 +01:00
Jannis R
5660f602a7
readme: link to Travel-Status-DE-HAFAS 📝 2024-01-18 15:27:29 +01:00
Kristjan ESPERANTO
8520eb3d1c Fix mode for 'ec-ic'
This threw an error in the intigration test.
2024-01-09 12:04:06 +01:00
Kristjan ESPERANTO
160039df10 Update actions 2023-12-10 22:07:02 +01:00
Jannis R
f29ced5b2d
handle "PROBLEMS" HAFAS error code 2023-12-07 00:55:35 +01:00
Jannis R
b12d235bae
contributing.md: link to testing docs 📝 2023-12-07 00:54:56 +01:00
Jannis R
5287ced44c
readme: minor tweaks 📝; put todos 2023-12-07 00:54:29 +01:00
Jannis R
9a3a1d3b0c
changelog 📝; 6.2.0 2023-11-27 16:32:35 +01:00
Daniel Bund
244e88dec0
add attribute additional to additional stopovers 2023-11-27 16:25:54 +01:00
Jannis R
ecc8fccc54
tap@18 2023-09-27 19:58:49 +03:00
Jannis R
02c781b180
cross-fetch@4, p-retry@6 2023-09-22 08:53:19 +02:00
Jannis R
449d2261bd
changelog 📝; 6.1.1 2023-09-03 17:09:05 +02:00
Jannis R
0bc6ba3650
DB journeys(): pass along opt.age if defined 2023-09-03 13:53:38 +02:00
Jannis R
a8401f36e1
DB: add test for profile.transformJourneysQuery() 2023-09-03 13:53:27 +02:00
Jannis R
45610fc951
IVB: update SSL CA certificate chain 🐛 2023-07-31 20:58:01 +02:00
Jannis R
581a47510d
profiles' examples: fixes, minor tweaks 🐛📝
- hafas.station() -> hafas.stop() 🐛
- put stop IDs into variables
- .then/.catch -> async/await
- consistent order of methods
- minor reformatting for readability
2023-07-28 21:35:59 +02:00
Jannis R
19cdde0655
document testing setup 📝
[ci skip]
2023-07-25 17:39:04 +02:00
Jannis R
8ff945c075
changelog 📝; 6.1.0 2023-07-25 16:10:10 +02:00
Jannis R
793cc9eee5
request: with $HTTP(S)_PROXY, keep connections alive for 10s 2023-07-25 16:09:43 +02:00
Lambert Theisen
5ce0129c36
DB: add routingModes option 📝
closes #295
fixes #287

Co-Authored-By: Jannis R <mail@jannisr.de>
2023-07-25 15:51:24 +02:00
Jannis R
92bbc63590
DB integration tests: update mocked when & fixtures 2023-07-25 15:51:24 +02:00
Jannis R
f9c24a4a84
https-proxy-agent@7 2023-07-07 19:33:06 +02:00
Jannis R
4cb7062302
changelog 📝; 6.0.5 2023-05-15 21:21:38 +02:00
Jannis R
24ad6117b0
CI: run with Node v20 too 💚 2023-05-15 12:59:07 +02:00
Jannis R
b8f0ab0fd6
DB: put todos 2023-05-15 12:58:40 +02:00
Jannis R
4116b53e9b
parseHint: put todos 2023-05-15 12:58:32 +02:00
Traines
9a1ef7c586 apply leg-wide remarks if opt.stopovers is false 2023-05-15 12:49:03 +02:00
Jannis R
dcc01d1413
update tools/transport-apis Git submodule 2023-04-25 00:41:18 +02:00
Jannis R
1e3cbc09a1
tools/endpoint-hci-version: mri -> util.parseArgs 2023-04-25 00:41:18 +02:00
Jannis R
f45842d7a3
tools/debug-cli: mri -> util.parseArgs 2023-04-25 00:41:18 +02:00
Jannis R
0e023136b8
fix tools/endpoint-hci-version 🐛 2023-04-25 00:41:17 +02:00
Jannis R
02dc6aef12
fix CI markup 💚 2023-04-04 14:12:32 +02:00
Jannis R
d6307aa24b
changelog 📝; minor tweak; 6.0.4 2023-04-04 14:01:24 +02:00
Jannis R
ab3f3636ff
CI: run integration tests in parallel to unit tests 💚 2023-04-04 14:00:36 +02:00
Jannis R
14c9805ad8
journeys(): let earlierRef/laterRef fall back to null 🐛 2023-04-04 11:40:03 +02:00
Jannis R
8faf8ba507
DB: use ver 1.16 for stop() requests 🐛, update integration test fixture
fixes #288
2023-04-04 11:33:24 +02:00
Jannis R
9d35d83c97
changelog 📝; 6.0.3 2023-03-14 21:04:14 +01:00
Jannis R
e7602e6c84
createClient(): throw if userAgent is one of the documented ones 💥📝
related: #286
fixes #286
2023-03-14 21:01:11 +01:00
Jannis R
5910d62535
docs: make user agent instructions more specific & actionable 📝
related: #286
2023-03-14 20:58:17 +01:00
Jannis R
0f3d6ec858
changelog: add missing 6.0.2 section 📝
follow-up of 8ba1adeb
2023-03-14 20:45:15 +01:00
Jannis R
673eb4d6c7
CI: cache npm's cache across jobs & runs 💚 2023-02-10 17:05:01 +01:00
Jannis R
8ba1adeb39
readme: remove badge 📝; changelog 📝; 6.0.2 2023-02-10 11:48:12 +01:00
Jannis R
2639448911
SNCB/NMBS: document profile as broken 📝, skip E2E/integration tests
related: https://github.com/public-transport/hafas-client/issues/284
2023-02-10 11:42:05 +01:00
Jannis R
c2a71b08e8
request: import Buffer 🐛
related: #281
2023-01-06 14:07:30 +01:00
Jannis R
9f85a9af54
changelog 📝; 6.0.1 2022-12-11 22:44:30 +01:00
Jannis R
557fc66078
luxon@3 2022-12-11 22:40:24 +01:00
Jannis R
547dd4b2a9
parseDateTime, format{Date,Time}: share Luxon IANAZones 2022-12-03 14:05:30 +01:00
Kristjan SCHMIDT
fc1afe0625
lines() docs: fix typo 📝
part of #278
2022-11-23 12:46:47 +01:00
Kristjan ESPERANTO
3493ad1086 Update actions version 2022-11-22 23:19:27 +01:00
Kristjan ESPERANTO
d8805d9ea3
docs: fix profile imports in code examples 📝
closes #278
2022-11-22 21:09:06 +01:00
Kristjan ESPERANTO
3791ec25e2 Fix version 2022-11-22 14:41:41 +01:00
Jannis R
8278ff9c62
changelog 📝; 6.0.0 2022-11-19 15:01:07 +01:00
Jannis R
4c8aeeb70c
integration tests: don't record fixtures in parallel 2022-11-19 02:33:07 +01:00
Jannis R
0d965c585d
integration tests: update mocked when, adapt to latest schedules, re-add fixtures 2022-11-19 02:33:07 +01:00
Jannis R
198d50e260
integration tests: circumvent broken CE gzip handling 2022-11-19 02:33:05 +01:00
Jannis R
63013d8306
skip leg cycle & alternatives integration tests 2022-11-18 19:29:44 +01:00
Jannis R
573f4ce6d7
integration tests: ignore request order when matching mocks 2022-11-18 19:29:44 +01:00
Jannis R
d43d3bafe3
fix Nah.SH nearby() E2E/integration test 2022-11-18 19:29:44 +01:00
Jannis R
16671b6dc5
SNCB: re-enable reachableFrom 2022-11-18 19:29:44 +01:00
Jannis R
7b914ae939
skip & un-skip some E2E/integration tests 2022-11-18 19:29:44 +01:00
Jannis R
0349ebac20
remove HVV profile 💥
closes #262
closes #261
2022-11-18 19:29:44 +01:00
Jannis R
1e8b5982a2
remove SBB profile 💥
closes #246
2022-11-18 19:29:44 +01:00
Jannis R
c2a228a73a
integration test mocking: replayer -> Polly.js 2022-11-18 19:29:44 +01:00
Jannis R
dd52411f5a
remove integration test fixtures 2022-11-18 19:20:03 +01:00
Jannis R
c736ff6427
minor docs fixes 📝 2022-11-18 19:20:03 +01:00
Jannis R
d80330ba5e
add "migrating to hafas-client@6" guide 📝 2022-11-18 19:20:03 +01:00
Jannis R
3c17678d9d
DB: use REALTIME routing mode 2022-11-18 19:20:03 +01:00
Jannis R
e46514c5f9
DB: rename regionalExp product to regionalExpress 💥 2022-11-18 19:20:03 +01:00
Jannis R
339d64e901
convert to ESM 💥📝 2022-11-18 19:20:03 +01:00
Jannis R
28f1316a51
eslint@8, tap@16 2022-11-18 19:20:03 +01:00
Jannis R
c6085eff26
luxon@2, p-retry@5, p-throttle@5 2022-11-18 19:20:03 +01:00
Jannis R
cef6dcaf0f
request: pass whole req body into transformReqBody 🐛 2022-11-18 19:20:03 +01:00
Jannis R
ef9e3765ee
parseLine: don't trim adminCode 💥 2022-11-18 19:20:03 +01:00
Jannis R
b740539081
parseTrip: remove trip.reachable 💥 2022-11-18 19:20:03 +01:00
Jannis R
30cb1f3d28
trip: remove lineName parameter, update integration test fixtures 💥📝 2022-11-18 19:20:03 +01:00
Jannis R
c53316668d
integration tests: update mocked when & fixtures 2022-11-18 19:20:03 +01:00
Jannis R
db442bb578
serverInfo: fix realtimeDataUpdatedAt parsing 🐛 2022-11-18 19:20:02 +01:00
Jannis R
44c8e37e5c
lines: realtimeDataFrom -> realtimeDataUpdatedAt 💥📝 2022-11-18 19:20:02 +01:00
Jannis R
b1c2eb9b93
parseWarning: handle missing common.himMsgEventL[].{f,t}Time 🐛 2022-11-18 19:20:02 +01:00
Jannis R
bb70081ceb
remarks: realtimeDataFrom -> realtimeDataUpdatedAt 💥📝 2022-11-18 19:20:02 +01:00
Jannis R
2fcaa2304b
reachableFrom: realtimeDataFrom -> realtimeDataUpdatedAt 💥📝 2022-11-17 15:25:01 +01:00
Jannis R
0cc50a918a
radar: realtimeDataFrom -> realtimeDataUpdatedAt 💥📝 2022-11-17 15:25:01 +01:00
Jannis R
a6411707e1
DB E2E test: cleanup 2022-11-17 15:25:01 +01:00
Jannis R
a0a4064bf0
trip/tripsByName: realtimeDataFrom -> separate realtimeDataUpdatedAt field 💥📝 2022-11-17 15:25:00 +01:00
Jannis R
3cbbc3c4da
refreshJourney: return journey as field 💥📝 2022-11-17 15:17:02 +01:00
Jannis R
751ae21d18
journeys/refreshJourney/journeysFromTrip: realtimeDataFrom -> realtimeDataUpdatedAt 💥📝 2022-11-17 15:17:02 +01:00
Jannis R
c4470ca962
arrivals/departures: return obj with realtimeDataUpdatedAt & results 💥📝 2022-11-17 15:17:02 +01:00
Jannis R
1000e48dfd
handle METHOD_NA/NO_MATCH/PARAMETER errors 2022-11-17 15:17:02 +01:00
Jannis R
9b263bb379
rework error handling 💥📝 2022-11-17 15:17:02 +01:00
Jannis R
0275b65c7a
fetch-ponyfill & pinkie-promise -> cross-fetch 💥
cross-fetch requires `globalThis.Promise` to be present.
2022-11-17 15:17:02 +01:00
Jannis R
7765f9d7a1
lib/request: use async/await, simplify error handling 2022-11-17 15:17:02 +01:00
Jannis R
b030eec1f5
use more async/await 💥 2022-11-17 15:17:02 +01:00
Jannis R
40957d3515
reachableFrom: don't retry 💥 2022-11-17 15:17:02 +01:00
Jannis R
f5962c4b7f
VBB E2E/integration tests: update mocked when & fixtures 2022-11-17 15:17:02 +01:00
Jannis R
70ae1b48bc
VBB/BVG E2E/integration tests: refactor shared test utils 2022-11-17 15:17:02 +01:00
Jannis R
7b0374695a
VBB: remove vbb-parse-line 💥 2022-11-17 15:17:01 +01:00
Jannis R
673d6f8279
VBB: remove vbb-parse-ticket, adapt to new response format 💥 2022-11-17 15:17:01 +01:00
Jannis R
d2bc134645
VBB: don't shorten stop/station names 💥 2022-11-17 15:17:01 +01:00
Jannis R
5ecf03f349
VBB: don't convert 7/9 <-> 12 digit IDs 💥 2022-11-17 15:17:01 +01:00
Jannis R
df4124e31d
BVG: don't shorten names 💥 2022-11-17 15:17:01 +01:00
Jannis R
5797105939
BVG: remove vbb-stations 💥 2022-11-17 15:17:01 +01:00
Jannis R
1f6115955d
BVG: don't convert IDs 💥 2022-11-17 15:17:01 +01:00
Jannis R
1ae1362916
BVG: remove vbb-parse-line 💥 2022-11-17 15:17:01 +01:00
Jannis R
a81e550f2a
departures{GetPasslist,StbFltrEquiv}: default to false 💥 2022-11-17 15:17:01 +01:00
Jannis R
492fdeb2ef
add profile.randomizeUserAgent flag 📝 2022-11-17 15:17:01 +01:00
Jannis R
e0cdd55908
parseWarning: {from,to}Loc -> {from,to}Location 💥 2022-11-17 15:17:01 +01:00
Jannis R
90308411fc
docs: .then/.catch -> await 📝
[ci skip]
2022-11-17 15:17:01 +01:00
Jannis R
d5969bc0c4
Node 16+ 💥💚 2022-11-17 15:17:01 +01:00
Jannis R
2baf2f6f04
changelog 📝; 5.26.2 2022-11-16 15:32:49 +01:00
Jannis R
a60083f8d1
parse trip.scheduledDays 2022-11-16 15:23:25 +01:00
Jannis R
b6900a3ddb
parse journey.scheduleDays using fpB & fpE 🐛
fixes #277

Thanks @bergmannjg!
2022-11-16 15:22:18 +01:00
Jannis R
61fc2293fb
E2E/integration tests: tweak assertions 2022-11-09 18:25:04 +01:00
Jannis R
5ff8527b60
tweak & restructure docs 📝, explicit defaults 2022-11-09 18:23:56 +01:00
Jannis R
c88179777d
put todos 2022-10-24 17:29:23 +02:00
Jannis R
f530a30fe0
mention related libs 📝 2022-10-24 14:12:00 +02:00
Jannis R
2319d317d0
changelog 📝; 5.26.1 2022-10-15 14:12:02 +02:00
Jannis R
66d78767ff
readme: mention typings & related libs 📝 2022-10-15 14:07:12 +02:00
Jannis R
0f7382e3b8
parse{Arrival,Departure}: properly parse .origin & .destination 🐛
fixes #273

Co-Authored-By: Jürgen Bergmann <bergmannj@posteo.de>
2022-10-15 14:02:11 +02:00
Jannis R
f20146137e
CI: run with Node 10-18 💚 2022-10-07 14:12:22 +02:00
Jannis R
7ccffa5e51
profile.log{Request,Response}: pass in random request ID 📝 2022-10-07 01:31:12 +02:00
Jannis R
4189ce437b
changelog 📝; 5.26.0 2022-10-06 19:23:58 +02:00
Jannis R
829c9ca461
add profile.log{Request,Response}() hooks 📝 2022-10-06 14:34:38 +02:00
Jannis R
0dc230837a
changelog 📝; 5.25.0
[ci skip]
2022-07-30 13:38:19 +02:00
Jannis R
95af0a0127
parse{Arrival,Departure}: expose prognosisType
fixes #266
2022-07-22 01:07:09 +02:00
Pieterjan Van Saet
7c68f962c1
parse{Stopover,JourneyLeg, Trip}: expose {arrival,departure}PrognosisType
see #266

Co-authored-by: Jannis R <mail@jannisr.de>
2022-07-22 01:06:35 +02:00
Jannis R
0a63698100
parse CHKI legs with checkin: true
fixes #267
2022-07-21 21:37:01 +02:00
Jannis R
9f2dcecf19
readme: link to db-tickets 📝
closes #268

[ci skip]
2022-07-19 22:25:26 +02:00
Jannis R
7929a986d5
changelog 📝; 5.24.1
[ci skip]
2022-06-23 12:54:56 +02:00
Jannis R
2ed2f38195
E2E/integration tests: DRY & tweak assertions 2022-06-18 18:33:26 +02:00
Jannis R
bdf933f806
INSA E2E/integration tests: adapt to latest data, update mocked when & fixtures 2022-06-18 18:33:26 +02:00
Jannis R
38cc9e9af8
E2E/integration tests: validate remarks 2022-06-18 18:33:26 +02:00
Jannis R
dda36c2da0
tests: enable linter, fix code style 2022-06-18 18:33:26 +02:00
Jannis R
3c7d8f79b2
DB: fix journeysFromTrip E2E/integration test 🐛 2022-06-18 18:33:26 +02:00
Jannis R
08be943906
BVG: re-skip BerlKönig test 2022-06-18 18:33:26 +02:00
Jannis R
4aa5f1de85
CFL, Irish Rail: transformReqBody -> defaultLanguage 2022-06-18 18:33:26 +02:00
Jannis R
492cb7dfbc
KVB: provide CA certificate chain via Agent 🐛 2022-06-18 18:33:13 +02:00
Jannis R
27bf631ae5
SVV integration tests: add missing fixture 2022-04-30 00:12:56 +02:00
Jannis R
27d4479e1a
changelog 📝; add @roehrt as contributor; 5.24
[ci skip]
2022-04-26 22:16:15 +02:00
Jannis R
7e1f7ed4ee
BVG/VBB: parse stop DHIDs 2022-04-26 22:08:23 +02:00
Jannis R
f8ca2d5d17
BVG: only expand 9* stop IDs to 12 digits 🐛
follow-up of ff2b6778
2022-04-26 22:08:23 +02:00
Jannis R
119d291d10
DB integration tests: update mocked when to 2022-07-12 2022-04-26 22:07:41 +02:00
roehrt
1236cf63a0
DB: support age group by age API 2022-04-26 12:13:52 +02:00
roehrt
7a3fd4fca5
DB: update to the lowest working version 2022-04-26 12:13:41 +02:00
roehrt
f3c2ee6f5a
DB: support age-based tariffs
The supported age groups are now:
- 'B' (baby, infant)
- 'K' (kind, child)
- 'Y' (young)
- 'E' (Erwachsener, adult)
- 'S' (Senior)
2022-04-26 12:13:41 +02:00
Jannis R
1ab526d900
integration tests: define mocked when per profile
https://github.com/public-transport/hafas-client/pull/264#issuecomment-1107462890
2022-04-23 14:42:55 +02:00
Florian Hüter
68ecd7c5e9 Update readme.md
Fix URL of "Betriebsstellen & disturbances in the German rail network"
2022-03-28 13:46:12 +02:00
Jannis R
947c5d364a
tools: highest-endpoint-version -> endpoint-hci-version 2022-02-22 20:27:08 +01:00
Jannis R
2edcd49e99
serverInfo: add opt.versionInfo 📝
Thanks to @alexander-albers!

see also https://github.com/alexander-albers/tripkit/issues/69#issuecomment-1048105228
2022-02-22 20:27:05 +01:00
Jannis R
cbc7f63dcc
changelog 📝; add @bddq as contributor; 5.23.0
[ci skip]
2022-02-22 18:05:59 +01:00
Benoit Deldicque
57084262a2
add departure.destination & arrival.origin 📝
closes #260
fixes #259

Co-Authored-By: Jannis R <mail@jannisr.de>
2022-02-21 11:43:27 +01:00
Jannis R
4b8f7c8198
changelog 📝; 5.22.2
[ci skip]
2022-01-13 14:09:30 +01:00
Jannis R
4cd0e9d98f
minor tweaks 📝 2022-01-13 14:08:43 +01:00
Jannis R
e3a022972c
request: tweak user-agent randomisation
see also https://github.com/deg0nz/MMM-PublicTransportBerlin/pull/67
2022-01-13 14:08:28 +01:00
Jannis R
2ec079adfc
TPG integration test 2021-12-29 15:56:25 +01:00
Jannis R
fa9a8d9f7d
integration tests: update fixtures 2021-12-29 15:50:58 +01:00
Jannis R
e69d069d43
fix & un-skip ingration tests, update mocked when 2021-12-29 15:50:57 +01:00
Jannis R
f6b144f012
update transport-apis; BVG: update endpoint & aid
The old endpoint currently redirects to the new one.
2021-12-29 15:20:04 +01:00
Jannis R
e79a371dde
add todos 2021-12-29 15:20:03 +01:00
Jannis R
674e4a5fe6
changelog 📝; 5.22.1
[ci skip]
2021-12-28 20:34:55 +01:00
Jannis R
9c10a1765f
fix request debug-logging 🐛 2021-12-09 18:58:35 +01:00
Jannis R
2fd06941b5
use HTTP keep-alive
1000 locations() requests against DB endpoint, before:
  min     max   sum   mean  stddev
215ms  4351ms  329s  329ms   341ms

after:
  min     max   sum   mean  stddev
160ms   579ms  194s  194ms    37ms
2021-12-09 18:54:46 +01:00
Jannis R
8645661cbc
changelog 📝; 5.22.0
[ci skip]
2021-12-08 14:22:43 +01:00
Jannis R
95d2c61fbd
add todos; readme: link to kpublictransport 📝 2021-12-08 14:12:23 +01:00
Jannis R
f6733d937a
ÖBB: enable lines() 2021-12-02 13:57:03 +01:00
Jannis R
ed86ad0b56
add KVB profile 📝
fixes #250
2021-11-27 23:46:27 +01:00
Jannis R
39950122a6
funding metadata: add Liberapay
[ci skip]
2021-11-21 14:53:20 +01:00
Jannis R
579fdbde61
changelog 📝; 5.21.1
[ci skip]
2021-11-18 18:32:31 +01:00
Jannis R
ca6f75501c
add todos; add @MTRNord as contributor 2021-11-18 18:29:25 +01:00
Jannis R
f41b8ac464
BVG: update API endpoint, add new integration test fixtures
related: https://github.com/schildbach/public-transport-enabler/issues/418 & https://github.com/alexander-albers/tripkit/issues/48

This reverts 3f75e07.
2021-11-08 14:18:47 +01:00
Jannis R
601164de21
changelog 📝; 5.21.0
[ci skip]
2021-11-01 22:31:19 +01:00
Marcel
4492b3a376
request.js: Use correct HttpsAgent option for localAddress 2021-11-01 17:40:09 +01:00
Kristjan Esperanto
c270eed998 nationalExp -> nationalExpress
Probably overlooked at commit 567cc98409.
2021-10-30 17:32:30 +02:00
Jannis R
6941e7a4ad
BVG: parse high occupancies 2021-10-29 13:03:58 +02:00
Jannis R
69ddf5fb8d
BVG: parse occupancy 2021-10-28 12:42:55 +02:00
Jannis R
a8d4d328b8
BVG: minor changes 2021-10-28 12:42:55 +02:00
Jannis R
3453cbe159
parseArrOrDep: expose stbStop.{rem,msg}L as remarks[] as well 2021-10-28 12:42:55 +02:00
Jannis R
97b6a76e75
parseTrip: expose realtimeDataUpdatedAt 2021-10-28 00:25:58 +02:00
Jannis R
2f5c8f4619
changelog 📝; 5.20.2
[ci skip]
2021-10-26 15:05:07 +02:00
Jannis R
8d4f8a8357
E2E/integration tests: update fixtures 2021-10-26 15:00:10 +02:00
Jannis R
1f6e6810da
DB: update ext 2021-10-26 15:00:09 +02:00
Jannis R
3f75e075a3
BVG: update API endpoint 2021-10-26 15:00:09 +02:00
Jannis R
39d3807c82
minor tweaks 📝
- package.json: add contributor "Kristjan Esperanto"
- readme: remove table of contents
- VRN: remove superfluous formatRefreshJourneyReq()
- NVV: fix profile name
- CFL: document "Fun" product
2021-10-26 15:00:09 +02:00
Jannis R
a7cb71c870
add todos & comments 2021-10-26 15:00:08 +02:00
Jannis R
dd5e436892
fix departures()/arrivals() without opt.direction 🐛 2021-10-26 14:59:23 +02:00
Jannis R
84c7582a33
journeys(): fix empty viaLocL[] 🐛
fixes #247
2021-10-26 14:08:06 +02:00
Jannis R
5104fa0fa8
changelog 📝; 5.20.1
[ci skip]
2021-10-24 23:14:23 +02:00
Jannis R
f0d33564f2
parseTrip: handle missing stopL[] (on-demand trips) 🐛 2021-10-24 22:52:52 +02:00
Jannis R
39ca7ede57
tripsByName: support some journey filters 2021-10-24 22:52:46 +02:00
Jannis R
fd6a349b64
tripsByName: more options, add to debug CLI, skipped E2E test 📝 2021-10-22 00:04:37 +02:00
Jannis R
959e894d42
E2E/integration tests: un-skip tests, update mocked when, update fixtures 2021-10-22 00:04:29 +02:00
Jannis R
46fb44d0de
SNCB: update CA chain 🐛 2021-10-22 00:00:10 +02:00
Jannis R
22a7f16ec9
remove SBB integration/E2E test
The endpoint seems to be shut off, see #245.
2021-10-20 16:02:36 +02:00
Jannis R
102c4bf2a5
BVG/VBB: fix nearby() integration/E2E test 2021-10-20 16:02:36 +02:00
Jannis R
0148a5bcbc
run network-bound tests in parallel 2021-10-20 16:02:34 +02:00
Jannis R
b616330523
changelog 📝; 5.20.0 2021-10-18 17:18:39 +02:00
Jannis R
c1ee557cf8
parseArrOrDep: export currentTripLocation 📝 2021-10-12 17:53:28 +02:00
Jannis R
6507d5a786
VBB departures() test: update fixtures 2021-10-12 17:46:52 +02:00
Jannis R
b10c1ce644
Rejseplanen trip() test: update fixtures 2021-10-12 17:40:30 +02:00
Jannis R
0a096a13d7
parseJourneyLeg/parseTrip: expose currentLocation 📝 2021-10-12 17:37:34 +02:00
Jannis R
464650c366
changelog 📝; 5.19.1
[ci skip]
2021-09-21 14:37:07 +02:00
Jannis R
ca75c4407d
adapt VBB profile to server changes 2021-09-21 14:32:16 +02:00
Jannis R
042668ff56
add DART profile 📝 2021-09-13 14:19:08 +02:00
Jannis R
182a0797e7
changelog 📝; 5.19.0
[ci skip]
2021-08-24 17:37:07 +02:00
Jannis R
421282608f
E2E/integration tests: update fixtures 2021-08-24 00:53:24 +02:00
Jannis R
0114f587b2
adapt E2E tests to latest data 2021-08-24 00:53:23 +02:00
Yureka
c3bdcc880f expose prodCtx.catOut as line.productName
Closes #242
2021-08-21 00:08:47 +02:00
Jannis R
e871c80900
link to FPTF v2 draft spec 📝
fixes #243
2021-08-18 16:00:16 +02:00
Yureka
dd52c4ade2 adapt fixtures for new price format 2021-08-18 12:56:05 +02:00
Yureka
6de2dc7bf3 fix db price parsing 2021-08-18 12:56:05 +02:00
Yureka
c10f31811a Expose realtimeDataFrom for refreshJourney
Fixes #239
2021-08-17 20:26:47 +02:00
Jannis R
216102763d
first/last walking leg: dTZOffset/aTZOffset of 0 🐛
fixes #237

Thanks @yu-re-ka!
2021-08-17 16:50:21 +02:00
Jannis R
62454d5d94
changelog 📝; 5.18.0
[ci skip]
2021-08-05 20:19:36 +02:00
Jannis R
56bd16b562
add Land Salzburg profile 📝
part of #207
closes #207
2021-08-05 20:11:01 +02:00
Jannis R
db2cbfdc45
add VOR profile 📝
part of #207
2021-08-05 20:10:42 +02:00
Jannis R
649a7ec060
add OÖVV profile 📝
part of #207
2021-08-05 20:10:32 +02:00
Jannis R
0ae13b09af
add STV profile 📝
part of #207
2021-08-05 20:10:22 +02:00
Jannis R
f20466c21c
add IVB profile 📝
part of #207
2021-08-05 20:10:10 +02:00
Jannis R
e293223c08
add VVV profile 📝
part of #207
2021-08-05 20:09:58 +02:00
Jannis R
4a7422fe56 DB: skip journeysFromTrip E2E/integration test 2021-08-04 15:21:00 +02:00
Jannis R
0995696c65 journeysFromTrip: docs 📝 2021-08-04 15:21:00 +02:00
Jannis R
aab7babbc2 DB: test for journeysFromTrip 2021-08-04 15:21:00 +02:00
Jannis R
ce82817631 DB: add journeysFromTrip() 2021-08-04 15:21:00 +02:00
Jannis R
b717642293
changelog 📝; 5.17.0
[ci skip]
2021-07-28 22:54:59 +02:00
Jannis R
33dab455ce
add TPG profile 📝
closes #208
2021-07-28 22:45:43 +02:00
Jannis R
24c2cc6ea4
add BLS profile 📝
part of #208
2021-07-26 17:45:09 +02:00
Jannis R
cec4f4dcaf
p-throttle@4 2021-06-28 23:34:53 +02:00
Jannis R
874ac69b1b
make retry test less flaky 💚 2021-05-20 16:56:41 +01:00
Jannis R
f1a19450fe
tape + tap-spec -> tap 2021-05-20 16:49:21 +01:00
Jannis R
40ec157869
BVG/VBB integration/E2E tests: don' try to identify stations 2021-05-20 16:42:11 +01:00
Jannis R
3412a66f6a
DB integration/E2E tests: don' try to identify stations 2021-05-20 16:38:40 +01:00
Jannis R
48af075f6f
changelog 📝; 5.16.0 2021-05-01 11:05:43 +02:00
Jannis R
4aae0cbcb9 E2E/integration tests: update mocked when, update fixtures 2021-05-01 10:58:45 +02:00
Jannis R
83dfc4456c E2E/integration tests: fix/un-skip some tests 2021-05-01 10:58:45 +02:00
Jannis R
3d50a212b5 remove E2E/integration opt.includeRelatedStations tests 2021-05-01 10:58:45 +02:00
Jannis R
62843f79d4 update profile examples 📝
[ci skip]
2021-05-01 10:58:45 +02:00
Jannis R
96b4d55f56 re-upgrade profiles, adapt feature flags, adapt tests 2021-05-01 10:58:45 +02:00
Jannis R
251e7925c9 pull more profile base data from transport-apis 2021-05-01 10:58:45 +02:00
Jannis R
4557e336b2 update "writing a profile" guide 📝
[ci skip]
2021-05-01 10:58:45 +02:00
Jannis R
16e0038fa9 lib/request: use profile.defaultLanguage 2021-05-01 10:58:45 +02:00
Jannis R
5beec2e15c pull-profile-base-data.sh: omit missing fields 2021-05-01 10:58:45 +02:00
Jannis R
7cb6210847 lib/request: validate response content-type 🐛 2021-05-01 10:58:45 +02:00
Jannis R
99142acf8b
E2E/integration tests: update mocked when, update fixtures 2021-04-15 11:32:01 +02:00
Kristjan Esperanto
e9701648ee Add Rejseplanen to list 2021-03-29 02:52:19 +02:00
Jannis R
44f1206daf
changelog 📝, 5.15.2 2021-03-26 23:38:37 +01:00
Jannis R
3ab6d46b5a
ÖBB integration tests: adapt integration test fixtures 2021-03-26 23:38:37 +01:00
Jannis R
dbac565dbe
ÖBB: fix profile by using https: 🐛
fixes #225
2021-03-26 23:38:26 +01:00
Kristjan
d9de0e004a Mark profile name as code 2021-03-26 01:10:28 +01:00
Kristjan
b6ad9ba0bc Remove 'source code' column and rename 'profile id' to 'profil name' 2021-03-26 01:10:28 +01:00
Kristjan
15be4a0b58 Introduce a 'profile id' column
This is helpful to choose the right profile. The folder name corresponds to the 'profile id' that I have to specify when I create a client. I haven't seen such an overview yet.

I'm not sure if 'profile id' is the appropriate term.
2021-03-26 01:10:28 +01:00
Tobias Roehr
6f56f15284 Enable usage of 1st class BahnCards and fix typo 2021-03-25 13:05:10 +01:00
Kristjan
9bfd4566ae Fix links and add missing cell 2021-03-25 12:01:54 +01:00
Kristjan
68d8bf9fca Correction of links 2021-03-21 16:42:58 +01:00
Jannis R
ebe7c59524
lib/request: fix DEBUG env var switch 🐛 2021-02-17 18:33:18 +01:00
Jannis R
ae66568c03
E2E/integration tests: update mocked when, update fixtures 2021-02-13 00:34:01 +01:00
Jannis R
9f82d3305c
readme: minor tweaks 📝; changelog 📝; 5.15.1
[ci skip]
2021-02-13 00:00:53 +01:00
Jannis R
c6fb966177
adapt E2E tests to updated ÖBB profile
see 7025d3bc
2021-02-12 23:51:04 +01:00
Jannis R
7025d3bc01
ÖBB: change ver to 1.33 🐛, enable remarks(), update client info
fixes #213
2021-02-12 23:47:10 +01:00
Jannis R
92f1831c72
departures()/arrivals(): document opt.products 📝
closes #212

[ci skip]
2021-02-10 21:29:23 +01:00
Jannis R
78bbf9b66c
VKG, VVT departures(): disable getPasslist & stbFltrEquiv 🐛 2021-02-07 22:22:15 +01:00
Jannis R
cb8d92befb
configure iface address used via LOCAL_ADDRESS env var 2021-02-07 22:17:02 +01:00
Jannis R
2afe4154f8 Travis CI -> GitHub Actions 💚 2021-01-28 15:17:09 +01:00
Jannis R
8ba60dcf92
improve readme.md & p/readme.md 📝
- more list of profiles to p/readme.md
- explain related libs better
- tweak readme.md section for better readability

[ci skip]
2021-01-28 14:22:29 +01:00
Jannis R
d86b359cb7
add todos; readme: fix link, changelog 📝; 5.15.0 2021-01-26 22:28:13 +01:00
Jannis R
0690724d1e
add VKG profile 2021-01-26 22:26:36 +01:00
Jannis R
2853fb0408
add VVT profile 2021-01-26 22:26:36 +01:00
Jannis R
f47343df8f
add BART profile 2021-01-26 22:26:36 +01:00
Jannis R
2ae6a9a4ea
add AVV profile 2021-01-26 22:26:36 +01:00
Jannis R
d69d2530ef
add remarksGetPolyline profile flag 2021-01-26 22:26:35 +01:00
Jannis R
7106d24a70
add VOS profile 2021-01-26 22:26:35 +01:00
Jannis R
458d6a77af
refetchJourney/reachableFrom/remarks: make opt.polylines explicit 2021-01-26 22:15:35 +01:00
Jannis R
fe63644827
parseWarning: use fromLocations[0] 2021-01-26 22:15:32 +01:00
Jannis R
472646057f
tests: long stack traces! 2021-01-26 22:08:23 +01:00
Jannis R
c260e34f20
DB: parse gridL[].itemL[].remL[] 🐛 2021-01-26 21:15:19 +01:00
Jannis R
0f284e09b8
parseCommon: resolve **.msgL[] before **.locX 2021-01-26 21:15:19 +01:00
Jannis R
6c4785b05b
DB: use JSON base profile 2021-01-26 21:15:19 +01:00
Jannis R
51af991e38
lib/request: add profile.(auth|client|ext|ver) to request 2021-01-26 17:26:26 +01:00
Jannis R
4ee062a19d
lib/request: allow string profile.salt 2021-01-26 17:26:26 +01:00
Jannis R
3df3a7b73d
tools: add transport-apis submodule & pull-profile-base-data.sh 2021-01-26 17:26:25 +01:00
Jannis R
ba27f54952
changelog 📝, 5.14.0
[ci skip]
2021-01-19 15:21:33 +01:00
Jannis R
4efff792ef
parseJourney: use j.recon.ctx as refreshToken too 🐛
see also d017e62
see also #164
2021-01-19 15:14:39 +01:00
Jannis R
174ed80749
remarks(): support missing res.msgL[] 🐛 2021-01-19 15:14:39 +01:00
Jannis R
4950b1e4f9
tools/highest-endpoint-version: start with current profile ver
[ci skip]
2021-01-19 15:14:39 +01:00
Jannis R
02af67e26c integration tests: update mocks, add mobil-nrw mocks 2021-01-19 12:38:43 +01:00
Jannis R
3b142813e2 E2E/integration tests: update mocked when 2021-01-19 12:38:43 +01:00
Jannis R
d017e62740 mobil.nrw refreshJourneys(): use outReconL[] instead of ctxRecon 🐛 2021-01-19 12:38:43 +01:00
Jannis R
3407ad6b5b mobil.nrw: E2E/integration tests 2021-01-19 12:38:43 +01:00
Jannis R
ad6cfd2288 add mobil.nrw profile 2021-01-19 12:38:43 +01:00
Jannis R
86bf3b46f0
docs: remove "migrating to 4" guide, fix profile examples, minor tweaks 📝 2021-01-10 20:53:37 +01:00
Jannis R
33ea6242bd
changelog 📝, 5.13.0
[ci skip]
2020-12-27 02:19:47 +01:00
Jannis R
ad6f76975b E2E/integration tests: update mocked when, update fixtures 2020-12-27 02:00:44 +01:00
Jannis R
744590ca43 HVV & CMTA: adapt E2E tests to latest data 💚 2020-12-27 02:00:44 +01:00
Jannis R
78a0f0fa54 mobiliteit.lu: E2E/integration tests 2020-12-27 02:00:44 +01:00
Jannis R
54b7d2845b mobiliteit.lu: fix national-train product bitmasks 🐛 2020-12-27 02:00:44 +01:00
Jannis R
850ec9484a mobiliteit.lu: fix endpoint, upgrade to version 1.25 2020-12-27 02:00:44 +01:00
Jannis R
6815c9eb3c SBB integration tests: check in mocks 2020-12-26 21:54:04 +01:00
Jannis R
bbf024dd3a SBB: add E2E/integration tests 2020-12-26 21:54:04 +01:00
Jannis R
2d3c0d6a94 E2E/integration validation logic: handle missing leg.alternatives[].when 2020-12-26 21:54:04 +01:00
Jannis R
17e08acfbb parseJourneyLeg parseAlternative: handle missing stopL[] 🐛, add tests 2020-12-26 21:54:04 +01:00
Norwin Roosen
7444e08819 add SBB profile
closes #198
2020-12-26 21:54:04 +01:00
Jannis R
18f8c81b59
changelog 📝, 5.12.0
[ci skip]
2020-12-09 13:12:54 +01:00
Jannis R
1a0d97dd28
HVV: disable lines() 🐛 2020-11-28 11:40:51 +01:00
Jannis R
e6bc8c6f86 departures/arrivals: add line option 2020-11-28 11:25:43 +01:00
Jannis R
53e10f73b7 profile flag for lines() 2020-11-28 11:25:43 +01:00
Jannis R
9d8260bf5f add lines() 2020-11-28 11:25:43 +01:00
Jannis R
7685d5afeb parseTrip: handle missing date 🐛 2020-11-28 11:25:43 +01:00
Jannis R
40ca838258 parseWarning: parse more fields
closes #178
2020-11-28 11:25:43 +01:00
Jannis R
731d9b8b81 profile flag for remarks() 2020-11-28 11:25:43 +01:00
Jannis R
ed48971fb1 add remarks() 2020-11-28 11:25:43 +01:00
Jannis R
3e6d6d9917 add serverInfo(), E2E tests
see also #145
2020-11-28 11:25:43 +01:00
Jannis R
eed345e3fc
changelog 📝, 5.11.0
[ci skip]
2020-11-26 23:31:21 +01:00
Jannis R
99e8bb313c VRN integration tests: add mocks 2020-11-26 23:29:21 +01:00
Jannis R
c0152d9605 VRN: add E2E/integration tests 2020-11-26 23:29:21 +01:00
Jannis R
259fcd7ad5 add VRN profile 2020-11-26 23:29:21 +01:00
Jannis R
0e46be7237
changelog 📝, 5.10.1
[ci skip]
2020-11-15 14:46:42 +01:00
Jannis R
66ff661767
parseJourneyLeg applyRemarks: handle legs without stopovers 🐛 2020-11-15 14:43:47 +01:00
Jannis R
48ef7b5a5d
minor fixes 2020-11-15 14:18:25 +01:00
Jannis R
6d4f29a3f9
nearby: support opt.products 2020-11-15 14:18:24 +01:00
Jannis R
47dfddfeb4
fetch-ponyfill@7 2020-11-15 13:39:53 +01:00
Jannis R
0ce6a41a85
changelog 📝, 5.10.0
[ci skip]
2020-11-01 18:59:53 +01:00
Jannis R
013ab2d3ce add mobiliteit.lu profile 2020-10-31 17:00:52 +01:00
Jannis R
92fb29d687 parseTrip: handle stopL[] items without idx 🐛 2020-10-06 22:22:30 +02:00
Jannis R
11ca3b171a add tripsByName() method, docs 📝
docs
2020-10-06 22:22:30 +02:00
Jannis R
33d7d30acf
changelog 📝, 5.9.0
[ci skip]
2020-09-24 10:36:49 +02:00
Jannis R
8ed218f4d6 add Irish Rail profile 2020-09-23 10:36:17 +02:00
Jannis R
de86391dcd
support HTTP proxies 2020-09-21 13:18:31 +02:00
Jannis R
fddf25a429
RMV integration tests: add missing mocks 2020-09-15 11:57:33 +02:00
Jannis R
4b72c61c58
changelog 📝, @Adwirawien as contributor, 5.8.0
[ci skip]
2020-09-15 11:43:38 +02:00
Jannis R
c17bd5a541 integration tests: update mocks, add Rejseplanen mocks 2020-09-15 11:36:24 +02:00
Jannis R
68aaad1071 S-Bahn Munich: switch to 1.21 protocol 2020-09-15 11:36:24 +02:00
Jannis R
e6f25a6471 adapt E2E/integration tests to endpoint changes
- skip PKP tests (#184)
- Nah.sh, ÖBB, SVV: adapt tests to endpoint changes
- Nah.sh, RSAG, VBN: skip tests due to endpoint changes
- remove dead code

[ci skip]
2020-09-15 11:36:24 +02:00
Jannis R
b2a3ce4d66 E2E/integration tests: fix stopover & leg validation 🐛 2020-09-15 11:36:24 +02:00
Jannis R
c9f8cc680e E2E/integration tests: update mocked when 2020-09-15 11:36:24 +02:00
Jannis R
2d139c8235 improve E2E/integration test output 2020-09-15 11:36:24 +02:00
Jannis R
25fb25c18d parseLeg: use remarks without fIdx/tIdx 🐛 2020-09-15 11:36:24 +02:00
Jannis R
82de7409e8 Rejseplanen: add tests 2020-09-15 11:36:24 +02:00
Jannis R
4d0605737f Rejseplanen profile 2020-09-15 11:36:24 +02:00
Jannis R
a621fd6df4
minor tweaks 2020-09-10 23:57:03 +02:00
Jannis R
43bd9cf65b
integration tests: add new RMV fixtures 2020-09-09 21:06:23 +02:00
Hanns Adrian Böhme
9848dfa762
Update bitmasks 2020-09-09 21:06:20 +02:00
Jannis R
2a5a385515
changelog 📝, 5.7.1
[ci skip]
2020-09-09 15:26:10 +02:00
Jannis R
da01544b42
add test: VSN with platform objects
test for 5cddd40
2020-08-01 18:26:37 +02:00
Leo Maroni
2612494970
fix platform parsing with some profiles 🐛
closes #187
2020-08-01 18:26:30 +02:00
Jannis R
40df65f462
minor tweaks, changelog 📝, 5.7.0
[ci skip]
2020-08-01 13:14:16 +02:00
Jannis R
4fc4c3b873
fix H9360 error message 🐛 2020-08-01 13:08:53 +02:00
Jannis R
097557c833 check in ZVV integration test fixtures 2020-07-31 12:14:22 +02:00
Jannis R
3f4c05d821 ZVV: E2E/integration tests 2020-07-31 12:14:22 +02:00
Jannis R
b2b1b75f04 add ZVV profile 2020-07-31 12:14:22 +02:00
Jannis R
e18fa7ccae
changelog 📝, 5.6.3
[ci skip]
2020-07-26 21:26:33 +02:00
Jannis R
20d00ca3f0
add test: DB journeys() with polyline 2020-07-26 13:38:01 +02:00
Jannis R
f9bfd6918a
parseJourneyLeg: parse jny.poly 🐛
fixes #186
2020-07-26 13:37:54 +02:00
Jannis R
a4dd763a46
E2E fixtures 2020-07-20 16:52:54 +02:00
Jannis R
dd88cea045
journeys E2E/integration tests: expect >=n results 2020-07-20 16:43:17 +02:00
Jannis R
2c04e2f728
journeys: async fn -> .then, don't check profile.journeysNumF 🐛 2020-07-20 16:42:51 +02:00
Jannis R
71db75df93
journeys: expose realtime data timestamp 2020-07-19 23:26:55 +02:00
Jannis R
51f4a66bd8
journeys: remove collection of results
Reverts 7fd574f.
See also https://github.com/public-transport/hafas-client/pull/23#issuecomment-370246163 .
2020-07-19 22:58:13 +02:00
Jannis R
5c05375650
let Git treat E2E test fixtures as binary data
This excludes the files from search and prevents unreadable diffs.

[ci skip]
2020-07-19 21:14:56 +02:00
Jannis R
c8928fb28d check in integration test fixtures 2020-06-15 15:39:09 +02:00
Jannis R
6f65d82edf document integration test workflow 📝
[ci skip]
2020-06-15 15:39:09 +02:00
Jannis R
3109a92b19 improve E2E tests assertion output 2020-06-15 15:39:09 +02:00
Jannis R
6b275171b1 parseMovement: skip invalid stopL[] items 🐛 2020-06-15 15:39:09 +02:00
Jannis R
5fd2c27a06 adapt E2E test to latest data 💚
also:
- skip RMV reachableFrom() E2E test 💚
2020-06-15 15:39:09 +02:00
Jannis R
d2314e0d40 journeys: don't send outDate/outTime & ctxScr 2020-06-15 15:39:09 +02:00
Jannis R
fea27d3a4a tests: make requests deterministic 💚 2020-06-15 15:39:09 +02:00
Jannis R
0c3acaba46 integration testing using replayer 2020-06-15 15:39:09 +02:00
Jannis R
51b3ca3c20 tape@5, remove tape-promise 2020-06-15 15:39:09 +02:00
Jannis R
3461573f31
changelog 📝, 5.6.2
[ci skip]
2020-06-13 00:11:01 +02:00
Jannis R
de896b1e96
parseCommon: respect opt.polyline 🐛
closes #181
2020-06-11 16:12:48 +02:00
Jannis R
fc2e214bb7
add ÖBB trip() test 2020-06-11 16:12:18 +02:00
Jannis R
dce42bfa31
move trip parsing into parse/trip 2020-06-11 15:34:20 +02:00
Jannis R
7c0be5ed74
tweak readme, changelog 📝, 5.6.1
[ci skip]
2020-06-10 15:08:47 +02:00
Jannis R
a8a9303e6f
nearby: return at most opt.results results 2020-06-10 15:00:49 +02:00
Jannis R
ee94c651dd
ÖBB: improve onCall product name 2020-06-10 14:59:20 +02:00
Julius Tens
57fc610a5f add tests for arrival parsing (db) 2020-06-09 18:02:33 +02:00
Julius Tens
3ca4a0c2b2 add provenance field on arrivals 2020-06-09 18:02:33 +02:00
Jannis R
542aa8caef parse DEVI journey legs 2020-05-31 12:38:07 +02:00
Jannis R
156de8e1c5
changelog 📝, 5.6.0
[ci skip]
2020-05-21 18:03:09 +02:00
Jannis R
322004bdcd
DB: stop.facilities.raw as non-enumerable property 2020-05-21 17:55:01 +02:00
Jannis R
240df85bf6
parseLocation: parse parent station 2020-05-21 17:51:25 +02:00
Jannis R
0251e314cc
DB parseLocation() test: expect sub-stops, facilities, foreign IDs 2020-05-21 17:51:25 +02:00
Jannis R
9e75f42346
DB: parse Reisezentrum opening hours & station facilities 2020-05-21 17:51:25 +02:00
Jannis R
d92eb154c2
parseLocation: give type: station to stops with stopLocL[] 2020-05-21 17:51:25 +02:00
Jannis R
1abafb5bd4
parseLocation: prevent endless recursive loops 2020-05-21 17:51:25 +02:00
Jannis R
76e310218a
parseLocation: parse entrances & sub-stops lists 2020-05-21 17:51:25 +02:00
Jannis R
07c77f8cf9
add subStops & entrances options 2020-05-21 17:51:25 +02:00
Jannis R
d98910a651
parseCommon: parse hints before locations 2020-05-21 17:51:25 +02:00
Jannis R
8fd72ca6f5
changelog 📝, 5.5.1
[ci skip]
2020-05-21 17:46:02 +02:00
Jannis R
b302ba75d2
minor readme/documentation tweaks 📝
- stop(): add `remarks: true` default
- journeys(): more intuitive options order
- readme: fix build status badge
2020-05-21 17:36:31 +02:00
Jannis R
e02a20b1de
readme: update links 📝
[ci skip]
2020-04-18 17:15:50 +02:00
Jannis R
3c888a0ea0
refreshJourney: actually throw the error 🐛, add code 2020-04-18 17:14:40 +02:00
Jannis R
87e5649f89
improve E2E test reliability 💚 2020-04-10 17:20:09 +02:00
Jannis R
0287899d1d
changelog 📝, 5.5.0
[ci skip]
2020-04-09 14:38:46 +02:00
Jannis R
0699d4d22e departures/arrivals: let results default to null
https://github.com/public-transport/hafas-client/pull/171#discussion_r397402352
2020-04-09 14:33:58 +02:00
Jannis R
9c4189a874 add E2E tests for SVV 2020-04-09 14:33:58 +02:00
Jannis R
fa3146d706 add SVV profile 2020-04-09 14:33:58 +02:00
Lukas Siemon
1b0133190f
object-scan@13 (improved performance)
closes #173
2020-04-09 01:00:45 +02:00
Jannis R
e032ec1acd
"invalid response" error: add isHafasError flag
So that consuming code can tell that this error is caused by an
invalid/unexpected response from HAFAS.
2020-04-01 19:03:38 +02:00
Jannis R
33d77868a4
changelog 📝, 5.4.0
[ci skip]
2020-03-29 13:57:35 +02:00
Jannis R
ae74bb420d departures/arrivals: add results option 2020-03-21 13:13:03 +01:00
Jannis Redmann
70c02199b2
Merge pull request #169 from public-transport/sncb-nmbs
add SNCB/NMBS profile
2020-03-19 13:06:41 +01:00
Jannis R
7d3107e6a7
SNCB: normalize S-train line names 2020-03-19 13:05:11 +01:00
Jannis R
17031f3e11
add SNCB/NMBS E2E tests 2020-03-19 13:05:11 +01:00
Jannis R
01b3693271
add SNCB/NMBS profile 2020-03-19 13:05:10 +01:00
Jannis R
ce76c1f983
changelog 📝, 5.3.1
[ci skip]
2020-03-18 22:16:49 +01:00
Jannis R
78487d9163
journeys: default earlierRef & laterRef to null 🐛
`JSON.stringify` exludes entries with `undefined`.
2020-03-18 21:45:36 +01:00
Jannis R
916ac3067d
PKP: trim "-" from stop names 2020-03-18 21:45:36 +01:00
Jannis R
0dceb414af
parseJourneyLeg: parse isRchbl correctly 🐛 2020-03-18 21:45:36 +01:00
Jannis R
2cb6a0c32b
parseIcon, parseHint, parseLocation: handle more edge cases 🐛 2020-03-18 21:45:36 +01:00
Jannis R
36a8b388f2
add todos
also remove dead code
2020-03-18 21:45:30 +01:00
Jannis R
cda96b6698
improve docs 📝
[ci skip]
2020-03-18 21:34:43 +01:00
Julius Tens
e0b15f1e1c add link to pkp-hafas 2020-03-12 20:23:38 +01:00
Jannis R
a93909046e
INSA: ver 1.21 -> 1.18 🐛
1b03b2eb broke it.

see also #95
2020-03-12 19:48:35 +01:00
Jannis R
0499163df3
changelog 📝, 5.3.0
[ci skip]
2020-03-12 19:05:35 +01:00
Jannis R
86ddf2c290 add VMT profile 2020-03-12 19:01:52 +01:00
Jannis R
522248b908 add RSAG E2E tests 2020-03-12 19:01:03 +01:00
Jannis R
84637b2e96 add RSAG profile 2020-03-12 19:01:03 +01:00
Jannis R
0ea2c01abe add RMV E2E tests 2020-03-12 19:00:02 +01:00
Jannis R
3a9e548bcf add RMV profile 2020-03-12 19:00:02 +01:00
Jannis R
8540f5f610 add VBN E2E tests 2020-03-12 18:59:17 +01:00
Jannis R
682f9f948d add VBN profile 2020-03-12 18:59:17 +01:00
Julius Tens
c2b15fab50 add PKP e2e tests 2020-03-12 18:58:29 +01:00
Julius Tens
d5116c2399 add PKP profile 2020-03-12 18:58:29 +01:00
Jannis R
299b5ac8ae INVG E2E tests 2020-03-12 18:57:07 +01:00
Jannis R
1c790e1cd6 add INVG profile 2020-03-12 18:57:07 +01:00
Jannis R
b61c2584b2
highest-endpoint-version helper tool
[ci skip]
2020-03-09 19:15:18 +01:00
Jannis R
225a7c15c1
changelog 📝, 5.2.0
[ci skip]
2020-03-08 23:47:04 +01:00
Jannis R
8c7f164fa3 parseLine: expose adminCode
The admin code is often helpful to distinguish lines that can't
be distinguished by their `operator.id`. See also #10.
2020-03-08 23:44:40 +01:00
Jannis R
3ea9380218 parseLocation: parse fare zone, transit authority & more foreign stop IDs
closes #131
see also #5, #90
2020-03-08 23:04:04 +01:00
Jannis R
2a241375db parseLocation: parse foreign stop IDs from I hints
`rRefL` seems to be used by older HAFAS endpoints, e.g. `ver: 1.11`.

see also #5, #90, #131
2020-03-08 23:04:04 +01:00
Jannis R
b9d5c85a54 tests: DB stop(), INSA stop() 2020-03-08 23:04:04 +01:00
Jannis R
ff2b677812
VBB: only expand 9* stop IDs to 12 digits 🐛
This broke stop IDs like 8080560 (Halle Dessauer Brücke) before.
2020-03-07 00:59:09 +01:00
Jannis R
1b03b2eb0f
INSA: v1.21, enable reachableFrom() 2020-03-07 00:39:11 +01:00
Jannis R
b653d4659b
GitHub funding markup, changelog 📝, 5.1.2
[ci skip]
2020-03-02 21:32:27 +01:00
Julius Tens
9874292a73 split travis script for cleaner CI output
Co-Authored-By: Jannis Redmann <mail@jannisr.de>
2020-02-27 17:10:03 +01:00
Julius Tens
df010fc24c enable no-irregular-whitespace and no-mixed-spaces-and-tabs rules, fix non-compliant whitespace 2020-02-27 17:10:03 +01:00
Julius Tens
c072a70c57 soothe the linter: remove unused variables 2020-02-27 17:10:03 +01:00
Julius Tens
bc30309056 bugfixes: fix undefined variables 🐛 2020-02-27 17:10:03 +01:00
Julius Tens
db94a62649 add basic linter setup 2020-02-27 17:10:03 +01:00
Jannis R
e5abe3d98a
DB: fix journey leg loadFactor parsing 🐛 2020-02-25 08:22:49 +01:00
Jannis R
fd3bc17d08
link to GitHub Sponsors, changelog 📝, 5.1.1
[ci skip]
2020-02-22 19:16:56 +00:00
Lukas Siemon
8cb7d807f2
improve findInTree performance
by passing a list of paths to find in the tree up front

#154

closes #152
2020-02-22 19:13:56 +00:00
Jannis R
940519b15b
make readme more helpful 📝
[ci skip]
2020-02-17 02:46:56 +00:00
Jannis R
9522e9296d
object-scan@11 2020-02-15 19:24:30 +00:00
Jannis R
d2bca32c77
changelog 📝, 5.1.0
[ci skip]
2020-02-08 18:14:21 +01:00
Simeon Keske
65c79fed5d
add n0emis as a contributor 2020-02-08 18:06:07 +01:00
Simeon Keske
738354d202
VSN: add E2E tests 2020-02-08 18:05:59 +01:00
Simeon Keske
1c67350b48
move refreshJourneyReq-formatter to own function 2020-02-08 18:05:42 +01:00
Simeon Keske
542a9eea02
add VSN profile 2020-02-08 18:05:41 +01:00
Jannis R
c1beb28b85
Error -> TypeError 2020-02-04 18:47:25 +01:00
Jannis R
dfff999406
request: add response ID to error objects 2020-02-04 18:42:11 +01:00
Jannis R
4837c2309e
changelog 📝, 5.0.4
[ci skip]
2020-02-03 20:18:18 +01:00
Jannis R
ea4912aae4
debug CLI: accept JS objects 2020-02-03 20:15:47 +01:00
Jannis R
9b0e55c6ad
VBB: accept station IDs with unknown length 🐛 2020-01-31 19:54:18 +01:00
Jannis R
db9287f7fd
@mapbox/polyline -> google-polyline 2020-01-31 18:07:16 +01:00
Jannis R
f771e9fb5d
changelog 📝, 5.0.3
[ci skip]
2020-01-29 02:53:02 +01:00
Jannis R
5622f98e62
vbb-translate-ids@4 🐛
fixes derhuerst/vbb-rest#38 for hafas-client@5
2020-01-29 02:51:41 +01:00
Lukas Siemon
cf69ff4bc8 amend: converted spaced to tabs 2020-01-26 21:37:41 +01:00
Lukas Siemon
8c6a8d858e chore: improved performance 2020-01-26 21:37:41 +01:00
Jannis R
e9699f98ba
minor fix, changelog 📝, 5.0.2 2020-01-15 18:17:49 +01:00
Jannis R
e049aa3d04
parseWarning: fix parseMsgEvent 🐛 2020-01-15 18:17:06 +01:00
Jannis R
616da57550
remove AppVeyor 💚, changelog 📝, 5.0.1
[ci skip]
2020-01-15 00:06:32 +01:00
Jannis R
51b1e68ddd
throttle & retry: use default profile 🐛 2020-01-14 23:56:48 +01:00
Jannis R
42b2a8a7bf
changelog 📝, 5.0.0
[ci skip]
2020-01-05 18:31:06 +01:00
Jannis R
e2567efcc2
DB Busradar NRW: adapt profile to ctx
see also fb7a565, 252ce5b, 9fc6664 & 2cfee22
2020-01-05 18:30:39 +01:00
Jannis R
2f8f82f736
require Node 10+ 💥 2020-01-05 18:10:10 +01:00
Jannis R
4d11f34e1d
adapt "writing a profile" guide to ctx-based parse fns 📝
[ci skip]
2020-01-05 18:10:10 +01:00
Jannis R
39a626784b
request formatters via profile 2020-01-05 18:10:10 +01:00
Jannis R
773035c05d
call formatProductsFilter via profile, use products from ctx.profile 💥 2020-01-05 18:10:10 +01:00
Jannis R
850cd9ce85
tests for formatProductsFilter 2020-01-05 18:10:10 +01:00
Jannis R
6d5c6081ce
request() via profile 💥 2020-01-05 18:10:09 +01:00
Jannis R
4652c1694e
fix test/throttle 💚 2020-01-05 18:10:09 +01:00
Jannis R
2cfee22287
tests: adapt to ctx-based parse fns 2020-01-05 18:10:09 +01:00
Jannis R
9fc6664302
adapt profiles to ctx-based parse fns 2020-01-05 18:10:09 +01:00
Jannis R
7b7293efea
lib/request: use transformed req body 🐛 2020-01-05 18:10:09 +01:00
Jannis R
252ce5b515
lib/request, index: use ctx object 💥 2020-01-05 18:10:09 +01:00
Jannis R
fb7a5653e3
parseProductsBitmask via profile, pass ctx into parse fns 💥 2020-01-05 18:10:09 +01:00
Jannis R
29d7bd4299
parseJourney: fix scheduledDays year 🐛 2020-01-05 18:10:09 +01:00
Jannis R
20a1592eaf
CI: allow E2E tests to fail 💚 2020-01-05 18:10:09 +01:00
Jannis R
cc74f6a85b
tests for parse/* 2020-01-05 18:10:09 +01:00
Jannis R
5ea22f7a59
parseHint: parse code & text properly 🐛 2020-01-05 18:10:09 +01:00
Jannis R
9a6bc2df0d
parseWarning: parseDateTime -> profile.parseDateTime 🐛 2020-01-05 18:10:09 +01:00
Jannis R
8b2a5a82f2
parseIcon: use txt & txtS as text fallback 2020-01-05 18:10:09 +01:00
Jannis R
6c5409fbce
extract parseIcon from parseCommon 2020-01-05 18:10:09 +01:00
Jannis R
9318007455
move profile E2E tests to test/e2e 2020-01-05 18:10:08 +01:00
Jannis R
0165320808
improve docs readability 📝 2020-01-05 17:55:56 +01:00
Jannis R
ef7bd42d15
adapt docs to c2dc874 📝 2020-01-05 17:55:49 +01:00
Jannis R
99d1531dbb
adapt tests to c2dc874 2020-01-05 17:55:37 +01:00
Jannis R
c2dc8742b6
parseWhen, parsePlatform: let when & platform fall back to plan data
This commit adapts parseWhen & parsePlatform to the latest FPTF v2 draft.

see public-transport/friendly-public-transport-format#63
2020-01-05 17:55:37 +01:00
Jannis R
2d1d482ddf
adapt tests to 938a6f2 2020-01-05 17:55:27 +01:00
Jannis R
938a6f22b9
add planned*Platform, scheduled* -> planned/prognosed* 💥 2020-01-05 17:55:27 +01:00
Jannis R
2b9280e6c3
adapt tests to 29a2cf3 2020-01-05 17:55:16 +01:00
Jannis R
29a2cf36e9
add planned(Arrival|Departure|When), scheduled* -> planned*/prognosed* 💥
when not cancelled:
{when, delay} -> {when, plannedWhen, delay}
{arrival, arrivalDelay} -> {arrival, plannedArrival, arrivalDelay}
{departure, departureDelay} -> {departure, plannedDeparture, departureDelay}

when cancelled:
{when: null, delay: null, scheduledWhen} -> {when: null, plannedWhen, prognosedWhen, delay}
{arrival: null, arrivalDelay: null, scheduledArrival, formerArrivalDelay} -> {arrival: null, plannedArrival, arrivalDelay, prognosedArrival}
{departure: null, departureDelay: null, scheduledDeparture, formerDepartureDelay} -> {departure: null, plannedDeparture, departureDelay, prognosedDeparture}
2020-01-05 17:52:17 +01:00
Jannis R
4162328fd4
createClient(): request parameter -> opt parameter 💥 2020-01-05 17:52:17 +01:00
Jannis R
655c425ecf
fix DB E2E tests 2020-01-05 17:52:17 +01:00
Jannis R
4ba4cefab6
improve readme readability 📝 2020-01-05 17:52:17 +01:00
Jannis R
9605ff3bf5
"migration to 5" guide, remove "migrating to 3" guide 📝 2020-01-05 17:51:28 +01:00
Jannis R
70cf3b21dc
upgrade deps & dev deps
- vbb-parse-line@1
- vbb-stations@7
- db-stations@3
- validate-fptf@3
- vbb-stations-autocomplete@4
2020-01-05 17:51:27 +01:00
Jannis R
d724846e91
rename findIdxRefs -> findInTree, remove resolveIdxRefs abstraction 2020-01-05 17:51:27 +01:00
Jannis R
f02fe301c7
parse: refactor applyRemarks 2020-01-05 17:51:27 +01:00
Jannis R
018fc84bf5
parseCommon: parse polylines 2020-01-05 17:51:27 +01:00
Jannis R
6af8f6d5ec
parseCommon: resolve hint & warning references 2020-01-05 17:51:27 +01:00
Jannis R
62cc53ffcf
parseCommon: resolve location references 2020-01-05 17:51:27 +01:00
Jannis R
758deaf2d5
parseCommon: resolve line references 2020-01-05 17:51:27 +01:00
Jannis R
0cc17ee780
parseCommon: resolve icon references 2020-01-05 17:51:27 +01:00
Jannis R
3eae7ab169
parseCommon: resolve operator references 2020-01-05 17:51:27 +01:00
Jannis R
4270125bf7
parse: minor changes 2020-01-05 17:51:27 +01:00
Jannis R
bff7384f06
basic parser tests 2020-01-05 17:51:27 +01:00
Jannis R
9a89cd0dc8
profile-based whitelist for walkingSpeed 2020-01-05 17:50:56 +01:00
Jannis R
0c145d352b
BVG, VBB: tests for walkingSpeed option 2020-01-05 17:50:56 +01:00
Jannis R
9c47a3908c
journeys: document walkingSpeed 📝 2020-01-05 17:50:56 +01:00
philipp lange
f8210c5515
journeys: add walkingSpeed option 2020-01-05 17:50:56 +01:00
Jannis R
33c1dc3c7e
BVG tests: drop opt.stopovers with departures(), skip test 💚 2020-01-05 17:50:56 +01:00
Jannis R
352fa2e564
parse more warning fields 2020-01-05 17:50:55 +01:00
Jannis R
35e44d4c92
pass all data into parseHint/parseWarning 💥 2020-01-05 17:50:55 +01:00
Jannis R
b8496be1a3
DB journeys: make default price null 💥
closes #91
2020-01-05 17:50:55 +01:00
Jannis R
1afe4caf41
BVG: test for BerlKönig 2020-01-05 17:50:55 +01:00
Jannis R
a40006f5ca
BVG: support BerlKönig, docs 📝 2020-01-05 17:50:55 +01:00
Jannis R
baff692b70
journeys: don't request nr of results by default 💥 2020-01-05 17:50:55 +01:00
Jannis R
272bf64e5e
BVG: use 1.21 protocol 2020-01-05 17:50:27 +01:00
Jannis R
793457a7a8
parse icons 💥 2020-01-05 17:50:27 +01:00
Jannis R
93814983da
add profile.parseCommon 2020-01-05 17:50:27 +01:00
Jannis R
4f9c3435d6
changelog 📝, 4.8.0
[ci skip]
2019-12-29 22:58:25 +01:00
Jannis R
16116358df
basic tests for DB Busradar NRW 2019-12-29 22:45:46 +01:00
Jannis R
ed0c606db1
add journeysOutFrwd profile flag 2019-12-29 22:18:22 +01:00
Kevin Arutyunyan
00b184df36
Add readme for DB Busradar NRW profile and add entry in profile overview 2019-12-29 22:18:22 +01:00
Kevin Arutyunyan
46eadcfde6
Update some product comments and disable unused/unknown ones 2019-12-29 22:18:22 +01:00
Kevin Arutyunyan
b7a6dbc504
Use HTTPS for DB Busradar NRW endpoint 2019-12-29 22:18:22 +01:00
Kevin Arutyunyan
56dee669a0
Add DB Busradar NRW profile (WIP) 2019-12-29 22:18:22 +01:00
Jannis R
c7a2813039
changelog 📝, 4.7.0
[ci skip]
2019-12-26 23:11:12 +01:00
Jannis R
747f335e32
move authentication docs to mgate.exe page 📝
[ci skip]
2019-12-25 20:00:38 +01:00
Jannis R
c883d969e2
general documentation for mgate.exe endpoints 📝
[ci skip]
2019-12-25 20:00:37 +01:00
Jannis R
9b9cca3823
changelog: tag links, dates 📝 2019-12-12 18:20:31 +01:00
Felix Geyer
fceaf86186 parse 'Q' hints 2019-11-25 12:43:29 +01:00
Jannis R
2fdff4df5d
changelog 📝, 4.6.2
[ci skip]
2019-11-18 18:37:04 +01:00
Jannis R
105c18b30d
DB profile: always use rtMode: HYBRID 2019-11-18 18:35:01 +01:00
Jannis R
df943252b6
changelog 📝, 4.6.1 2019-10-28 17:47:21 +01:00
Jannis R
1cc453b778
parseArrOrDep, parseLocation: bugfixes 🐛 2019-10-28 17:43:27 +01:00
Jannis R
9ce72930b1
put more todos 2019-10-28 17:42:33 +01:00
Jannis R
43b4a6e6d9
handle H_UNKNOWN error
see also schildbach/public-transport-enabler#0f6862f
2019-10-28 17:35:57 +01:00
Jannis R
2993cc0e87
put more todos
[ci skip]
2019-08-30 16:27:34 +02:00
Jannis R
3c7c1c3d4e
changelog 📝, 4.6.0
[ci skip]
2019-08-16 18:21:47 +02:00
Jannis R
19c3ee614c
NVV tests 2019-08-16 18:20:15 +02:00
Jannis R
73ca349ee5
add NVV profile 2019-08-16 18:20:15 +02:00
Jannis R
ae4e592b00
changelog 📝, 4.5.2
[ci skip]
2019-08-16 18:18:43 +02:00
Jannis R
0bcc9016cd move debug-cli into tools dir 2019-08-16 17:57:22 +02:00
Jannis R
c6de12a707 debug CLI: parse args properly 2019-08-16 17:57:22 +02:00
Jannis R
036d0cdca8 add debug CLI 2019-08-16 17:57:22 +02:00
Jannis R
2e88e964bb client ID: install-unique -> process-unique 2019-08-16 17:57:04 +02:00
Jannis R
f783ef0793
changelog 📝, 4.5.1
[ci skip]
2019-07-20 13:08:28 +02:00
Jannis R
77afb9f9a3
DB: enable radar() 2019-07-20 13:07:16 +02:00
Jannis R
3aaa1496f5
parseWarning: handle missing summary/text 🐛 2019-07-20 13:07:14 +02:00
Jannis R
f5121f1bf6
changelog 📝, minor changes, 4.5.0
[ci skip]
2019-07-08 21:12:39 +02:00
Jannis R
b57c212bb5 errors: add HTTP status codes 2019-07-08 21:06:43 +02:00
Jannis R
b144dd5358 parse & expose error codes 2019-07-08 21:06:43 +02:00
Jannis R
ccfeaecef9
changelog 📝, 4.4.0
[ci skip]
2019-06-30 13:23:31 +02:00
Jannis R
e46d6cd588
parseLocation: expose stop.isMeta 2019-06-30 13:21:25 +02:00
Jannis R
e5dafa0d48
changelog 📝, 4.3.0
[ci skip]
2019-06-25 20:35:43 +02:00
Jannis R
a2b71e2ab6
changelog 📝, 4.2.2
[ci skip]
2019-06-25 10:51:34 +02:00
Jannis R
0ce5669899
fix bitmask handling 🐛 2019-06-24 18:37:39 +02:00
Jannis R
d0f7ca1b6c
follow HTTP redirects, accept br encoding 2019-06-24 18:26:11 +02:00
Jannis R
1e0182f8f6
parseLint: use addName, add todos 2019-06-21 18:43:10 +02:00
Jannis R
707fd292d7
p-retry@4, p-throttle@3 2019-06-09 11:49:02 +02:00
Julius Tens
3eacc443e1
changelog 📝, 4.2.1 2019-06-08 12:58:32 +02:00
Julius Tens
9078d2d25a fix reachable for walking legs 2019-06-08 12:56:24 +02:00
Jannis R
f04b5416e4
changelog 📝, 4.2.0
[ci skip]
2019-06-07 11:34:30 +02:00
Julius Tens
6da1e80ef2 add leg.reachable 2019-06-05 11:59:23 +02:00
Jannis R
965e1f9986
changelog 📝, 4.1.1
[ci skip]
2019-05-29 14:22:33 +02:00
Julius Tens
875ea18b4c parse scheduled/actual platform information on legs
fixes #116
2019-05-29 14:19:23 +02:00
Christopher Zentgraf
f92e9336c0 DB departures/arrivals: parse load factor
See https://www.bahn.de/p/view/service/buchung/auslastungsinformation.shtml for reference.
2019-05-28 11:16:51 +02:00
Jannis R
4f8bc17015
changelog 📝, 4.1.0
[ci skip]
2019-05-27 20:28:21 +02:00
Jannis R
dca6c15ded HVV: tests 2019-05-27 20:17:23 +02:00
Jannis R
57c71865ba HVV examples 📝 2019-05-27 20:17:23 +02:00
Jannis R
3ab099b8e7 HVV profile 2019-05-27 20:17:23 +02:00
Jannis R
b3d75b567d
fix parseWarning 🐛 2019-05-27 16:33:01 +02:00
Jannis R
820f2abe86
parseWarning: parse products 2019-05-27 16:08:09 +02:00
Jannis R
59de9b8862 CFL: adapt tests to latest data 💚 2019-05-20 20:06:24 +02:00
Jannis R
d5f9675c2a CFL tests: ignore missing direction 2019-05-20 20:06:24 +02:00
Jannis R
75432fcf4c CFL: tests 2019-05-20 20:06:24 +02:00
Jannis R
3e01303e43 CFL profile 2019-05-20 20:06:24 +02:00
Jannis R
26069806e0 remove 0 milliseconds from docs & tests 2019-04-29 18:23:40 +01:00
Jannis R
831bcaf4c9 ISO date+time: suppress milliseconds if 0 2019-04-29 18:23:40 +01:00
Jannis R
ed97522908
link to db-netz-hafas, changelog 📝, 4.0.3
[ci skip]
2019-04-01 19:24:37 +02:00
Jannis R
6aa57d4616
handle missing dirTxt 🐛 2019-04-01 19:22:10 +02:00
Jannis R
ab00a9360f
changelog 📝, 4.0.2 2019-03-27 18:58:56 +01:00
Jannis R
133cee9988
parseWarning: expose id 🐛 2019-03-27 18:58:34 +01:00
Jannis R
b88090dd30
br2nl -> @derhuerst/br2nl 2019-03-27 18:31:56 +01:00
Jannis R
9503ef1cda
changelog 📝, 4.0.1 2019-03-19 12:58:37 +01:00
Jannis R
5d49fd0a20 parseDateTime: fix tzOffset + daysOffset 🐛
closes #106
2019-03-19 12:56:49 +01:00
Jannis R
8bfc4aee0f test for parseDateTime 2019-03-19 12:56:49 +01:00
Jannis R
29aea9a5ef
journeys: fix opt.results === null 🐛 2019-03-01 11:37:25 +01:00
Jannis R
16f98b943e
changelog & "migration to 4" guide 📝, 4.0.0
[ci skip]
2019-02-28 17:02:18 +01:00
Jannis R
3b0740d310
adapt tests to 7e39a2f 2019-02-28 16:45:40 +01:00
Jannis R
7e39a2f333
formerScheduled… -> scheduled… 💥 2019-02-28 16:45:40 +01:00
Jannis R
16461733e4
Error -> TypeError 💥 2019-02-28 16:45:40 +01:00
Jannis R
fbde6a171b
createClientWithRetry -> withRetrying 💥 2019-02-28 16:45:40 +01:00
Jannis R
748f8ce6b0
createThrottledClient -> withThrottling 💥 2019-02-28 16:45:40 +01:00
Jannis R
c04e041338
make tests more robust 💚 2019-02-28 16:45:40 +01:00
Jannis R
eab850e058
adapt docs & tests to eb3ffba 📝 2019-02-28 16:45:31 +01:00
Jannis R
eb3ffba4fc
make POIs objects with poi: true 💥
fixes #42
2019-02-28 16:45:31 +01:00
Jannis R
4a79b91680
parseLocation: L param as fallback ID 2019-02-28 16:45:31 +01:00
Jannis R
9c449958c4
remove (arrival|departure).trip, movement.trip 💥 2019-02-28 16:45:31 +01:00
Jannis R
fcc2a23fc1
ÖBB journeys: fix opt.results 🐛 2019-02-28 16:45:31 +01:00
Jannis R
8566bcc85f
journeys tests: expect 4 results
The default nr of results returned by HAFAS seems to be `3`, so we pick
a different one to assert that the `results` option actually works.
2019-02-28 16:45:31 +01:00
Jannis R
ea17443bd8
tweak "writing a profile" guide 📝
[ci skip]
2019-02-28 16:45:31 +01:00
Jannis R
567cc98409
DB, INSA, Nah.SH, ÖBB: nationalExp -> nationalExpress 💥 2019-02-28 16:45:31 +01:00
Jannis R
c1bb9a6a5c
adapt docs & tests to 0e1fcb0 📝 2019-02-28 16:45:18 +01:00
Jannis R
0e1fcb0c99
leg.mode: 'walking' -> leg.walking: true 💥 2019-02-28 16:45:18 +01:00
Jannis R
a972dad7b8
departures/arrivals, locations, nearby, stop: opt.stationLines -> linesOfStops 💥 📝 2019-02-28 16:45:18 +01:00
Jannis R
8f9b22e296
locations, nearby: opt.stations -> opt.stops 💥 📝 2019-02-28 16:45:18 +01:00
Jannis R
d7e439b948
NODE_DEBUG -> DEBUG 💥 2019-02-28 16:45:18 +01:00
Jannis R
61e7d14531
journeys: let opt.transfers default to -1 💥 📝 2019-02-28 16:45:18 +01:00
Jannis R
a1c40ad084
adapt tests to fcc53b5 2019-02-28 16:45:09 +01:00
Jannis R
b2b2d11dfe
adapt docs to fcc53b5 📝
[ci skip]
2019-02-28 16:44:59 +01:00
Milan
fcc53b5d2a
journeys: return object with journeys, earlierRef, laterRef 💥
Previously, an array with additional attributes `earlierRef` and `laterRef` was returned.
When JSON-stringified, the attributes were missing.
2019-02-28 16:44:59 +01:00
Jannis R
cb535cdabe
remove line.class & line.productCode from docs 📝
adapting to 8dd4ef5
2019-02-28 16:44:59 +01:00
Jannis R
a1ffad3071
parseLine: remove line.class & line.productCode 💥 2019-02-28 16:44:59 +01:00
Jannis R
3bc2eff530
locations: default opt.results to 5 💥 📝 2019-02-28 16:44:58 +01:00
Jannis R
88c78c243f
adapt tests to 96ff59d 2019-02-28 16:44:46 +01:00
Jannis R
0fa9610b30
tests: trip validator 2019-02-28 16:44:46 +01:00
Jannis R
0daa1c5fef
adapt docs & examples to 96ff59d 📝 2019-02-28 16:44:36 +01:00
Jannis R
96ff59dc43
leg.id -> leg.tripId 💥 2019-02-28 16:44:36 +01:00
Jannis R
2e12206c0b
adapt tests to bad0af8 2019-02-28 16:44:22 +01:00
Jannis R
8b87868fba
adapt docs & examples to bad0af8 📝 2019-02-28 16:44:10 +01:00
Jannis R
bad0af8e25
rename station(id) -> stop(id) 💥 2019-02-28 16:44:10 +01:00
Jannis R
bbff1f4c63
movement.nextStops -> movement.nextStopovers 💥 2019-02-28 16:44:10 +01:00
Jannis R
59584a3402
tests: co/yield -> async/await 2019-02-28 16:44:10 +01:00
Jannis R
bf3c4c58a1
require Node >=8.3.0 💥 💚 2019-02-28 16:44:09 +01:00
Jannis R
ca1105f139
parseDateTime: parse timezone offset if given 💥 2019-02-28 16:44:09 +01:00
Jannis R
a9fd9ff814
parseDateTime: return ISO str/timestamp 💥 2019-02-28 16:44:09 +01:00
Jannis R
b99ceb21fb
adapt tests to 1e13cf1 2019-02-28 16:43:57 +01:00
Jannis R
1e13cf15ae
parseLocation: strip leading zeros from IDs 💥 2019-02-28 16:30:18 +01:00
Jannis R
73261e99b4
changelog 📝, permalinks to 3 branch 📝, 3.10.1
[ci skip]
2019-02-28 16:24:09 +01:00
Jannis R
46e772967a
remove console.error call 🐛
[ci skip]
2019-02-28 16:23:54 +01:00
Jannis R
dafc96ad11
update CMTA credentials 2019-02-15 15:12:28 +01:00
Jannis R
1eeb0d7bd7
make tests more reliable 💚 2019-02-15 15:11:43 +01:00
Jannis R
f6a7be0652
changelog 📝, 3.10.0 2019-02-13 14:08:30 +01:00
Jannis R
1e16a10f3d DB: optionally use line.nameS 2019-02-13 14:05:06 +01:00
Julius Tens
dd98c6deb4 db: tests for additional line names 2019-02-13 14:05:06 +01:00
Julius Tens
d797333a70 db: parse additional line names 2019-02-13 14:05:06 +01:00
Jannis R
1e8bdda6df
changelog 📝, 3.9.1 2019-02-08 14:17:04 +01:00
Jannis R
a145feab4a
extend default retry opts 🐛 2019-02-08 14:16:43 +01:00
Jannis R
cfda4caf26
changelog 📝, 3.9.0
[ci skip]
2019-02-08 13:42:37 +01:00
Jannis R
9b1bbb92a7
test for retry 2019-02-08 13:42:37 +01:00
Jannis R
e051884ccc
docs for retry & throttle 📝
[ci skip]
2019-02-08 13:17:05 +01:00
Jannis R
b0f786c42a
optional retry support 2019-02-08 13:13:54 +01:00
Jannis R
3f58d84de5
handle stop objects as input 🐛, 3.8.1 2019-02-06 22:27:56 +01:00
Jannis R
b84db19efb
DB, BVG: skip leg cycle/alternatives tests, fix Nah.SH test 💚 2019-01-09 14:26:22 +08:00
Jannis R
985eadc8d8
more related libs, tiny docs fixes 📝
[ci skip]
2019-01-07 16:23:40 +08:00
Jannis R
ecc26ef313
changelog 📝, 3.8.0 2018-12-31 18:26:07 +01:00
Jannis R
f0bd8ba61d
Saarfahrplan: filter empty radar() stopovers 2018-12-31 16:32:41 +01:00
Jannis R
e50c1694d8
Saarfahrplan: disable getPasslist & stbFilterEquiv 2018-12-31 16:32:41 +01:00
Julius Tens
508eaa629b
Saarfahrplan: tests 2018-12-31 16:32:41 +01:00
Jannis R
1b941dea16
Saarfahrplan profile 2018-12-31 16:32:27 +01:00
Jannis R
5d0096c596
departures: profile flag for getPasslist & stbFilterEquiv 2018-12-30 18:42:05 +01:00
Jannis R
b55c2c1579
validateMovement: min/max longitude/latitude config 2018-12-30 18:42:05 +01:00
Jannis R
b9282435a5
changelog 📝, 3.7.0
[ci skip]
2018-12-28 22:46:23 +01:00
Jannis R
f097022b9a
tests for departure.nextStopovers/arrival.previousStopovers 2018-12-28 22:14:35 +01:00
Jannis R
aa0f0118db
parse Y hints 2018-12-28 22:14:35 +01:00
Jannis R
e867dac2ab
arrivals/departures: opt.stopovers for previous/next stopovers, docs 📝 2018-12-28 22:14:35 +01:00
Jannis R
c70a851249
changelog 📝, 3.6.3 2018-12-28 22:14:28 +01:00
Jannis R
cb2d2981a3
stops/stations: default .id of null 2018-12-28 22:13:29 +01:00
Jannis R
a68614bfaf
changelog 📝, 3.6.2
[ci skip]
2018-12-16 17:23:20 +01:00
Jannis R
48424cf10f
p-throttle as normal dependency 🐛 2018-12-16 17:06:49 +01:00
Jannis R
5beff47dea
radar: fix polylines option 🐛
Had to set the default value to `true` to stay backwards-compatible.
2018-12-13 19:30:55 +01:00
Jannis R
215fce004b
DB readme: document loyaltyCard option 📝
[ci skip]
2018-12-12 16:36:36 +01:00
Jannis R
51bd438681
changelog 📝, 3.6.1
[ci skip]
2018-12-10 14:41:21 +01:00
Jannis R
d11b60bbd1
minor changes in readme, profile examples
[ci skip]
2018-12-10 14:38:21 +01:00
Jannis R
e1f1d0d258
ÖBB: fix radar() 🐛, fix radar() test 💚 2018-12-07 16:29:34 +01:00
Jannis R
ae2007c9e2
fix ÖBB 🐛 2018-12-06 11:38:46 +01:00
Jannis R
bcbc366497
ÖBB radar(): don't filter out stops 🐛 2018-12-06 11:35:48 +01:00
Jannis R
b809281d0e
fix error parsing 🐛 2018-12-06 11:31:38 +01:00
Jannis R
e7efcb5405
S-Bahn Munich: switch to 1.18 protocol 2018-12-06 11:31:28 +01:00
Jannis R
054b3f3eec
changelog 📝, 3.6.0
[ci skip]
2018-12-03 11:49:58 +01:00
Jannis R
b208a3dda4
tests: fix messages 2018-12-03 11:48:31 +01:00
Jannis R
d9126d531a leg.alternatives: DB smoke test 2018-12-03 11:43:14 +01:00
Jannis R
9f1a0a0f8a leg.alternatives: BVG smoke test 2018-12-03 11:43:14 +01:00
Jannis R
f88358e02a tests for leg.cycle & leg.alternatives 2018-12-03 11:43:14 +01:00
Jannis R
8fac5fc0e0 leg.alternatives: parse direction & delay 2018-12-03 11:43:14 +01:00
Jannis R
4b56f6608c parseJourney: parse freqency 2018-12-03 11:43:14 +01:00
Jannis R
17b8f1485f parseJourneyLeg: parse freq.numC 2018-12-03 11:43:14 +01:00
Jannis R
1ebb958b4a
link to observe-hafas-client & hafas-client-health-check 📝 2018-11-21 17:31:02 +01:00
Jannis R
94673c266d
CI: Node LTS 💚, cache npm 2018-11-21 17:29:37 +01:00
Jannis R
05409c4f10
earlier/later journeys tests: add when 💚 2018-11-20 18:38:48 +01:00
Jannis R
0ce28fc783
test earlier/later journeys test 💚 2018-11-20 18:29:20 +01:00
Jannis R
ef40e827ae
fix tests 💚 2018-11-13 20:34:12 +01:00
Jannis R
d8bc5d2bd8
changelog 📝, 3.5.0 2018-11-13 19:40:44 +01:00
Jannis R
9d96902794
readableFrom: make maxDuration optional
[ci skip]
2018-11-01 19:39:04 +01:00
Jannis R
02e0e513ef
parse scheduled days of a journey 2018-10-25 18:57:31 +02:00
Jannis R
0e8ed62f23
changelog 📝, 3.4.3
[ci skip]
2018-10-24 22:13:44 +02:00
Jannis R
9936466ce0
p-throttle@2, tape-promise@4 2018-10-15 20:13:06 +02:00
Jannis R
4f15cbd049
minor changes 2018-10-15 20:10:50 +02:00
Jannis R
1a4c09ab4e
test that the profile is exposed 2018-10-15 20:10:50 +02:00
Jannis R
95839372b5
trip: remove when option, it gets ignored anyways 2018-10-15 20:10:50 +02:00
Julius Tens
0b29f805f4 add link to bvg-hafas 2018-10-01 20:07:33 +02:00
Jannis R
c6b7aa74dd
VBB supports numF again 2018-09-25 20:19:06 +02:00
Jannis R
129caa704f
changelog 📝, 3.4.2
[ci skip]
2018-09-24 15:40:30 +02:00
Jannis R
2a6b0dc507
speed up date+time formatting 2018-09-24 15:40:00 +02:00
Jannis R
ed3ecd7b4d
changelog 📝, 3.4.1
[ci skip]
2018-09-22 19:25:06 +02:00
Jannis R
09895ce3fb
link to FPTF 1.2.0 📝
[ci skip]
2018-09-22 19:25:01 +02:00
Jannis R
582c9dee20
speed up date+time parsing 2018-09-22 19:22:27 +02:00
Jannis R
af29210c07
changelog 📝, minor changes, 3.4.0
[ci skip]
2018-09-20 19:06:15 +02:00
Jannis R
e2493b5228
fix tests 💚 2018-09-20 19:06:15 +02:00
Jannis R
3e3bf1e2bc
p/sbahn-munich -> p/sbahn-muenchen 2018-09-18 19:56:03 +02:00
Jannis R
4b07142d49 tests for S-Bahn Munich 2018-09-18 19:51:07 +02:00
Jannis R
b7b5843d46 S-Bahn Munich profile 2018-09-18 19:51:07 +02:00
Jannis R
eddacd0091
changelog 📝, 3.3.1
[ci skip]
2018-09-03 20:46:41 +02:00
Jannis R
035877c368
reachableFrom: retry 🐛 2018-09-03 20:38:56 +02:00
Jannis R
dfad3d9d84
changelog 📝, 3.3.0
[ci skip]
2018-09-03 18:37:21 +02:00
Jannis R
3ac04a0ebd reachableFrom(loc, [opt]) -> reachableFrom(address, [opt]) 2018-09-03 16:43:01 +02:00
Jannis R
e65b2d8780 tests for reachableFrom 2018-09-03 16:43:01 +02:00
Jannis R
8b572d6184 profiles: enable reachableFrom 2018-09-03 16:43:01 +02:00
Jannis R
f6040de6fb docs for readableFrom 📝 2018-09-03 16:43:01 +02:00
Jannis R
b36ccda79d reachableFrom(loc, [opt]) 2018-09-03 16:43:01 +02:00
Jannis R
d69c01ba14
parseLine: don't use p.nameS 🐛 2018-09-03 16:17:19 +02:00
Jannis R
5cb2b4f049
fix tests 💚 2018-09-03 15:55:09 +02:00
Jannis R
ccfee97e4b
changelog 📝, 3.2.1
[ci skip]
2018-09-03 15:46:15 +02:00
Jannis R
a24822d161
fix test output 💚 2018-09-03 15:46:15 +02:00
Jannis R
3c104e2233
debug hook logging request & response 2018-09-03 15:31:22 +02:00
Jannis R
e98cec1734
remove unused code, minor changes 2018-09-03 15:30:42 +02:00
Jannis R
b37bedba26
parseLine: prodCtx.lineId as id, nameS as name 2018-09-03 15:13:23 +02:00
Jannis R
044a5ee816
arrival.direction = null 🐛
For arrivals, `d.dirTxt` didn't contain the direction, but the origin.
2018-09-03 15:12:14 +02:00
Jannis R
ee7ad74fd3
fix changelog 📝, Windows build badge
[ci skip]
2018-08-27 13:18:30 +02:00
Jannis R
e4ddb49a2e
changelog 📝, 3.2.0
[ci skip]
2018-08-26 18:44:43 +02:00
Jannis R
6a73aa5295 CMTA tests 2018-08-26 18:27:30 +02:00
Jannis R
ebd1e60010 readme: link to CMTA profile 📝
[ci skip]
2018-08-26 18:27:30 +02:00
Jannis R
47a77d7dd2 CMTA: enable feature flags, minor changes 2018-08-26 18:27:30 +02:00
Jannis R
77994bc5d1 CMTA: update endpoint 🐛 2018-08-26 18:27:30 +02:00
Jannis R
6591d2be17 CMTA: adapt example code to hafas-client@3 📝 2018-08-26 18:27:30 +02:00
Jannis R
d0b0b56fbc CMTA: hafas-client@2 modes -> hafas-client@3 products 2018-08-26 18:27:30 +02:00
Nick Turskyi
6acbd8b1b1 CMTA: Corrected "nearby" example, enabled journeyLeg 2018-08-26 18:27:30 +02:00
Nick Turskyi
980eaa3b6e CMTA: Cleanup 2018-08-26 18:27:30 +02:00
Nick Turskyi
810aa53e1e CMTA: Removed VBB profile leftovers 2018-08-26 18:27:30 +02:00
Nick Turskyi
50de71b6f4 CMTA: correct examples, enabled radar 2018-08-26 18:27:30 +02:00
Nick Turskyi
533f8ece3c CMTA profile 2018-08-26 18:27:30 +02:00
Jannis R
313d97c1fc
changelog 📝, 3.1.2 2018-08-24 20:17:12 +02:00
Jannis R
f796337ce1
handle warnings without schedule sDate/eDate/lModDate 🐛
closes #78
2018-08-24 20:16:27 +02:00
Jannis R
4d3cbe9ed7
Appveyor Windows CI 💚 2018-08-23 21:29:39 +02:00
Jannis R
ad24c23701
changelog 📝, 3.1.1 2018-08-23 21:02:59 +02:00
Daniel Julius
39cc2f3e1a compability for windows
Without "node" it wouldn´t work on windows setups.
I´m tested it and then it works fine.
2018-08-23 21:01:49 +02:00
Jannis R
5ab47e8e8b
changelog 📝, 3.1.0
[ci skip]
2018-08-22 19:36:15 +02:00
Jannis R
1f13f68926
allow line.fahrtNr of null 💚 2018-08-22 19:33:38 +02:00
Jannis R
9257d3ad7d
parse line.fahrtNr, adapt tests , adapt docs 📝 2018-08-22 19:06:57 +02:00
Jannis R
858fc209bb
fix merge leftover 🐛 2018-08-17 22:05:51 +02:00
Jannis R
f5c0e8e58a
3.0.0 2018-08-17 21:53:25 +02:00
Jannis R
abf3661edc
merge next into master 2018-08-17 21:52:40 +02:00
Jannis R
8f7358b462
Nah.sh: mode bus for on-call transit
We might want to rename "on-call" to "demand-responsive".
2018-08-17 21:41:49 +02:00
Jannis R
40b56f70b7
changelog 📝, 2.10.3 2018-08-08 18:47:00 +02:00
Jannis R
50bd4409f5
better User-Agent randomization 🐛 2018-08-08 18:46:20 +02:00
Jannis R
ae31807eb7
better User-Agent randomization 🐛 2018-08-08 18:40:35 +02:00
Jannis R
ffc392b66b
docs: link to FPTF 1.1.1, minor fixes 📝
[ci skip]
2018-08-01 10:05:00 +02:00
Jannis R
0466e570ad docs for BVG profile 📝 2018-07-29 20:17:50 +02:00
Jannis R
05bd54f021 tests for BVG 2018-07-29 20:17:50 +02:00
Jannis R
a3ad876bf5 BVG profile 2018-07-29 20:17:50 +02:00
Jannis R
e20f65823b
adapt profile docs to 5d9d738 📝 2018-07-28 14:58:25 +02:00
Jannis R
96c1df5c3a
generate & send install-unique IDs 2018-07-26 19:04:00 +02:00
Jannis R
0b81a59c71
changelog 📝, 2.10.2 2018-07-25 11:38:07 +02:00
Jannis R
d54c26d9be
randomize User-Agent
The VBB endpoint blocks all requests with the exact User-Agent of
"https://github.com/public-transport/hafas-client".
2018-07-25 11:37:26 +02:00
Jannis R
8653e43b2b
refreshJourney: pass through userAgent 🐛 2018-07-25 11:24:01 +02:00
Jannis R
bec3249b01
changelog for refreshJourney 📝, tap-spec@5 2018-07-25 11:17:44 +02:00
Jannis R
067e807db7 INSA doesn't support refreshJourney 🐛 2018-07-25 10:05:52 +02:00
Jannis R
da10988b29 add tests for refreshJourneys (c88071f) 2018-07-25 10:05:52 +02:00
Jannis R
8a45d26fda add docs for refreshJourneys (c88071f) 📝 2018-07-25 10:05:52 +02:00
Jannis R
5b754aaa55 refreshJourney method 2018-07-25 10:05:52 +02:00
Jannis R
3dc492b686 docs/station: fix formatting 2018-07-24 18:29:31 +02:00
Jannis R
5f39d2875c adapt tests to 0a0cddc 2018-07-24 18:29:31 +02:00
Jannis R
f20931b6de adapt docs & examples to 0a0cddc 📝 2018-07-24 18:29:31 +02:00
Jannis R
5d9d738152 mandatory User-Agent param 💥 2018-07-24 18:29:31 +02:00
Jannis R
b5b2cfb38f
put leg-wide remarks into leg, not stopovers
[ci skip]
2018-07-16 14:43:01 +02:00
Jannis R
d44ec05a1d
adapt markup in docs to current code 📝 2018-07-16 12:39:13 +02:00
Jannis R
9c1c2f51e5
parse leg remarks even if it is a walking leg 🐛 2018-07-16 12:18:26 +02:00
Jannis R
36b24e27e4
fix Nah.sh station -> address tests 💚 2018-07-16 12:15:52 +02:00
Jannis R
c4511c949c
adapt tests & Nah.sh profile to 12e61be 2018-07-16 11:57:07 +02:00
Jannis R
e6130d7c23
changelog, related libs 📝, clean up code 2018-07-16 11:36:27 +02:00
Jannis R
12e61bea0a {arrival,departure}.station -> .stop 💥, adapt docs 📝 2018-07-13 16:07:23 +02:00
Jannis R
0c1cec01c2 adapt Nah.sh tests to 98a051b 💚 2018-07-13 16:07:23 +02:00
Jannis R
951c21eecc adapt tests to 98a051b 2018-07-13 16:07:23 +02:00
Jannis R
59fee11216 adapt docs to 98a051b 📝 2018-07-13 16:07:23 +02:00
Jannis R
a475f2048d parse stops and their stations 2018-07-13 16:07:23 +02:00
Jannis R
fe8e68e4a2
fix DB hints parsing 🐛 2018-07-13 12:17:15 +02:00
Jannis R
c0a04fc74f
tests for includeRelatedStations option
see 1551943
2018-07-10 22:33:55 +02:00
Jannis R
a2cd5ba187
docs & changelog for includeRelatedStations option 📝
see 1551943
2018-07-10 22:33:12 +02:00
Jannis R
1551943fdb
option: departures/arrivals at related stations
With default `true`
- because it seems to be the sensible default configuration
- to stay backwards-compatible
2018-07-10 18:59:59 +02:00
Jannis R
90519cff68
remove accidental logging
[ci skip]
2018-07-09 19:48:14 +02:00
Jannis R
efc6467c93
tests: validate former scheduled platforms 2018-07-09 19:46:13 +02:00
Jannis R
4529a93175
parse DB-specific hints inside DB profile 2018-07-09 19:32:23 +02:00
Jannis R
0d5a8fab1b
departures, arrivals, stopovers: former scheduled platform(s) 2018-07-09 13:12:26 +02:00
Jannis R
0199749a31
language option with default 'en' 2018-07-09 12:40:38 +02:00
Jannis R
c80f355d47
tests for departures with direction option 2018-07-07 21:33:35 +02:00
Jannis R
4a454917dd rename profile.journeyLeg to profile.trip 💥 2018-07-07 21:19:28 +02:00
Jannis R
a187f8ee97 adapt examples to e1bdd56 📝 2018-07-07 21:19:28 +02:00
Jannis R
ab5ca3db8b rename journeyLeg() to trip() 💥, adapt tests 2018-07-07 21:19:28 +02:00
Jannis R
86fc27e340 docs: journeyLeg() -> trip() 📝 2018-07-07 21:19:28 +02:00
Jannis R
2a6f1f9183
transfer flag for walking legs
[ci skip]
2018-07-07 14:14:25 +02:00
Jannis R
a34999b1c5
parse more hints
[ci skip]
2018-07-02 18:48:31 +02:00
Jannis R
65f3603953
fix warnings parsing part 2 🐛 2018-07-02 16:59:38 +02:00
Jannis R
4bcae146c1
fix warnings parsing 🐛 2018-07-02 16:55:39 +02:00
Jannis R
b6c530915f
2.10.1 2018-07-02 16:54:21 +02:00
Jannis R
04d550f80c
parse TRSF legs as walking 🐛
cherry-picked 2f40c20 from next
2018-07-02 16:51:29 +02:00
Jannis R
2f40c20175
parse TRSF legs as walking 🐛, add todos 2018-07-02 16:49:21 +02:00
Jannis R
d9b7df693a
parse hint & warning types using icons
[ci skip]
2018-06-30 18:24:55 +02:00
Jannis R
5f03c8e878
parse more hints 2018-06-30 18:03:43 +02:00
Jannis R
8923bcb619
changelog for 2.10.0 📝, 2.10.0 2018-06-30 14:39:21 +02:00
Jannis R
fccd3d0037
journeys: startWithWalking with default true
cherry-picked 9305a12 from next
2018-06-30 14:38:11 +02:00
Jannis R
c1bdade49f
departures: parse & expose platform 2018-06-30 14:30:17 +02:00
Jannis R
4da8689ace
walking legs: expose distance
cherry-picked bb6e42a from next
2018-06-30 14:21:43 +02:00
Jannis R
fa0570e3d8
changelog for 2.9.0 & 2.9.1 📝, 2.9.1 2018-06-30 13:58:27 +02:00
Jannis R
063e2b4254
parseStopover: fix first/last canceled stopovers 🐛
cherry-picked 440ed6d from next
2018-06-30 13:56:03 +02:00
Jannis R
a952b08b76
readme: how to use with react-native 📝
cherry-picked 6d9ffed from next
2018-06-30 13:55:44 +02:00
Jannis R
bdb9c15c7e
luxon@1, vbb-short-station-name@1 2018-06-30 13:40:39 +02:00
Jannis R
440ed6d1fb
parseStopover: fix first/last canceled stopovers 🐛
[ci skip]
2018-06-28 17:14:17 +02:00
Jannis R
bb6e42a662
walking legs: expose distance 2018-06-28 14:12:25 +02:00
Jannis R
31973431ff
option not to parse remarks 2018-06-28 13:45:56 +02:00
Jannis R
17aeacf594
arrivals/departures: fix remarks parsing 🐛 2018-06-28 13:32:42 +02:00
Jannis R
58f183506e
option to parse station lines, default off 💥, adapt docs 📝 2018-06-28 13:04:03 +02:00
Jannis R
471f075dea
fix nearby examples 📝 2018-06-28 13:01:18 +02:00
Jannis R
d3815f80d7
arrivals/departures: parse & expose platforms 2018-06-27 17:19:49 +02:00
Jannis R
eeb9ec2535
add todos, migrating to 3.x guide, related repos 📝 2018-06-27 11:49:57 +02:00
Jannis R
f6c824eecb fix tests 💚 2018-06-26 18:13:41 +02:00
Jannis R
3ade1af7a2 basic tests for arrivals 2018-06-26 18:13:41 +02:00
Jannis R
ac9819b1dd query arrivals , docs 📝 2018-06-26 18:13:41 +02:00
Jannis R
1d5f4ff31c parse arrivals 2018-06-26 18:13:41 +02:00
Jannis R
00ea10d9c8 journey leg, departure, movement: journeyId -> tripId 💥 2018-06-26 18:13:41 +02:00
Jannis R
f5eceafdf3
merge refactor-parse-fns into next 2018-06-26 13:07:06 +02:00
Jannis R
479bac428f
parse fn signatures: bugfix 🐛 2018-06-26 12:25:30 +02:00
Jannis R
b02f012b18
parse fn signatures: bugfixes 🐛 2018-06-26 11:48:30 +02:00
Jannis R
4c86b625c7
parse fn signatures: bugfixes 🐛 2018-06-26 11:47:44 +02:00
Jannis R
9305a129a8
journeys: startWithWalking with default true 2018-06-25 18:34:10 +02:00
Jannis R
6e60cc8bda
parse Komfort-Checkin & ICE Sprinter hints 2018-06-25 13:59:42 +02:00
Jannis R
a8aa2652df
parseJourneyLeg: fix remarks indices 🐛 2018-06-25 13:54:30 +02:00
Jannis R
0db84ce644
merge remarks into next 2018-06-25 13:20:13 +02:00
Jannis R
6d9ffeda94
readme: how to use with react-native 📝
Hopefully prevents situations like in #56 in the future.

https://github.com/public-transport/hafas-client/issues/56#issuecomment-399915315
2018-06-25 13:12:14 +02:00
Jannis R
3c00ed29d0
fix test broken by 3e672ee 💚 2018-06-25 11:48:30 +02:00
Jannis R
108eda4450
fix tests broken by 3e672ee 💚 2018-06-25 11:39:21 +02:00
Jannis R
8c726dce01
changelog for 3.0.0 📝 2018-06-25 11:36:05 +02:00
Jannis R
ce880c06bd
adapt tests & docs to 021ae45 & 3e672ee 📝 2018-06-25 11:35:01 +02:00
Jannis R
3e672eeabd
stopover.type, stopover.station -> stopover.stop 💥
To be compatible with `friendly-public-transport-format@1.1.1`.
2018-06-25 11:34:25 +02:00
Jannis R
96f9f93957
parseStopover: arrivalPlatform, departurePlatform 2018-06-22 13:42:01 +02:00
Jannis R
edab8fe4a9
2.9.0 2018-06-20 23:26:01 +02:00
Jannis R
f60bebd5ae
VBB: strip "Bus " & "Tram " from line names 2018-06-20 23:25:21 +02:00
Jannis R
ebe4fa64d8 opt.passedStations -> opt.stopovers 💥 2018-06-19 08:23:49 +02:00
Jannis R
6611f262bf leg.passed -> leg.stopovers 💥
Some didn't unterstand what "passed" means in this context.
"stopovers" is a lot less ambiguous; Also, it aligns with
`parseStopover` and FPTF.
2018-06-19 08:23:49 +02:00
Jannis R
3e18f5d415
gitignore lockfile, add & remove todos, minor changes 2018-06-13 20:25:56 +02:00
Jannis R
b6fbaa5825
parse fns: opt param 💥
- parseLine
- parseDeparture
- parseJourney
- parseJourneyLeg
- parseLocation
- parseMovement
- parseNearby
- parseStopover
2018-06-13 20:05:33 +02:00
Jannis R
6ca7924f7b
parsePolyline: profile param 💥 2018-06-13 20:05:33 +02:00
Jannis R
a45d640272
request fn: opt param 💥 2018-06-13 20:05:33 +02:00
Jannis R
8881d8a1a4
parse fns: individual params -> data object 💥
From now on, all higher-level parse fns will be able to access more
of the response data while keeping their signature.

- parseLine
- parseDeparture
- parseJourney
- parseJourneyLeg
- parseLocation
- parseMovement
- parsePolyline
- parseNearby
- parseStopover
2018-06-13 20:05:24 +02:00
Jannis R
49186ae2d1
journey leg passed stations: parse & expose delays
backporting 21c273c to master
2018-06-13 18:14:19 +02:00
Jannis R
1299d7f04f
parse more hints 2018-06-11 21:37:13 +02:00
Jannis R
871db25bc9
parse more hints, add todos 2018-06-11 19:50:44 +02:00
Jannis R
3556130f6b
parse more hints 2018-06-11 18:41:53 +02:00
Jannis R
d3d23140fd
(more) remarks for journeys, journey legs & stopovers 2018-06-11 11:37:00 +02:00
Jannis Redmann
47155cdb83
merge #57: rewrite the tests 2018-06-10 15:06:08 +02:00
Jannis R
b419477a7d
merge next into tests-rewrite 2018-06-10 14:57:51 +02:00
Jannis R
46c05eba05 adapt tests to 3c9c5cb 2018-06-10 14:47:29 +02:00
Jannis R
2d11cfae1e adapt docs to 3c9c5cb 📝 2018-06-10 14:47:29 +02:00
Jannis R
665bed9f79 rename location(id) -> station(id) 💥
see #17 for reasons
closes #17
2018-06-10 14:47:29 +02:00
Jannis R
21c273cec7
journey leg passed stations: parse & expose delays 2018-06-07 18:52:47 +02:00
Jannis R
fa2cdc5177
pass warnings into parsers, apply warnings to journey legs 2018-06-07 18:48:45 +02:00
Jannis R
d909be3b65
parseWarning 2018-06-07 18:46:44 +02:00
Jannis R
b6e37595a5
remarks for journey legs 2018-06-07 16:39:07 +02:00
Jannis R
d2257c26ff
rename d.remarks -> d.hints, parseRemark -> parseHint
HAFAS returns notes for journey legs, stopovers and departures.

There are two kinds of notes: "remarks" (in `remL`) and HAFAS
Information Manager (HIM) notes (in `himL`). The former describe
the regular operating situation, e.g. "bicycles allows", whereas
the latter describe cancellations, construction work, etc.

The planned naming scheme for hafas-client:
- hints: notes from `remL` for regular operation
- warnings: notes from `himL` for cancellations, construction, etc
- remarks: both "notes" and "warnings"

This commit prepares the new naming scheme by renaming the
existing parsing logic of `remL` to "hints". Follow-up commits
will add `parseWarning`.
2018-06-07 16:34:50 +02:00
Jannis R
f3609ebd80
WIP parse remarks 2018-06-07 15:41:00 +02:00
Jannis R
0136189aa4
tests: fix isRoughlyEqual calls 2018-06-07 12:59:50 +02:00
Jannis R
a7c550ab69
send Accept: application/json 🐛 2018-06-07 12:13:31 +02:00
Jannis R
92310ebdab
2.8.1 2018-06-07 12:04:48 +02:00
Jannis R
769f2e33f6
send Accept: application/json 🐛 2018-06-07 12:04:21 +02:00
Jannis R
7ec8540db4
changelog for 2.7.x and 2.8.0 📝 2018-06-04 19:11:59 +02:00
Jannis R
0775a27d1d
WIP parse remarks 2018-06-01 11:12:54 +02:00
Jannis R
938195753c
merge next into tests-rewrite 2018-05-31 14:00:58 +02:00
Jannis R
856a751b51 journeys: make opt.departure & opt.arrival mutually exclusive 2018-05-30 16:39:51 +02:00
Jannis R
0169e83731 journeys: add test for opt.arrival 2018-05-30 16:39:51 +02:00
Jannis R
a59b340d67 adapt tests to 1c467cd 2018-05-30 16:39:51 +02:00
Jannis R
c82ad234e0 journeys: opt.when -> opt.departure/opt.arrival 💥 2018-05-30 16:39:51 +02:00
Jannis R
f3d8304db8 INSA, Nah.sh: HTTPS 🔒 2018-05-30 16:05:05 +02:00
Jannis R
a17123401d
fix tests failing because of weird endpoints
- DB: `journeyLeg()` sometimes doesn't give the `direction` #49
- nah.sh: `departures()` at "Kiel Hbf" includes neighboring stations
- ÖBB: the endpoint always returns IDs of individual stops

Although these hacks make the tests less strict, we will finally be
able to use the more thorough tests from the `tests-rewrite` branch.
2018-05-30 15:51:59 +02:00
Jannis R
1bb1ce4f8b
merge next into tests-rewrite 2018-05-30 14:22:23 +02:00
Jannis R
a356a26e2f
throw if 0 products enabled 💥
This should have been the case previously, but the test didn't fail.
2018-05-28 20:37:19 +02:00
Jannis R
634b044bc5
nah.sh tests: fix products validation 🐛 2018-05-28 20:37:19 +02:00
Jannis R
57f3cdb7e0 parseLocation: null as fallback station name 2018-05-25 16:08:17 +02:00
Jannis R
7541bcae66 adapt nah.sh radar test to #34 2018-05-25 16:08:17 +02:00
Jannis R
187d2ac04e Nah.sh: enable radar despite failing test
see #34 for more details
2018-05-25 16:08:17 +02:00
Jannis R
deb88297a0 journeys: whenRepresents option 2018-05-24 22:06:46 +02:00
Jannis R
6063fa6651
journeys: fix polylines option 🐛 2018-05-24 21:54:25 +02:00
Jannis R
e479619387
cherry-pick 16c3f01: DB: 1.16 protocol, journeyLeg, fix polylines 🐛 2018-05-24 14:06:53 +02:00
Jannis R
16c3f01118
DB: 1.16 protocol, enable journeyLeg, 2.8.0
Although `journeyLeg()` can be unreliable for DB (#49), I enabled
it here. This is not a breaking change because, previously, you
were not able to use `journeyLeg()` in the first place. Let's hope
that it works for people. 🙈

By changing to the 1.16 protocol, we support the `polyline` option
of `journeyLeg()` as well.
2018-05-24 13:50:53 +02:00
Jannis R
908d53189a
DB journeys: fix polylines parsing 🐛, 2.7.5 2018-05-24 13:44:47 +02:00
Jannis R
709b7b4e32
luxon@1, vbb-short-station-name@1, 2.7.4 2018-05-24 10:52:18 +02:00
Jannis R
00b1eb387c
crypto.createHash -> create-hash, 2.7.3
closes #52
2018-05-24 10:29:50 +02:00
Jannis Redmann
c5aab72e71
merge #45 from format-location-err-msg
formatLocation: more helpful error messages
2018-05-24 10:28:50 +02:00
Jannis Redmann
bebb975584
Merge branch 'next' into format-location-err-msg 2018-05-24 10:28:18 +02:00
Jannis R
03b9ab9a83 expect parsePolyline in lib/validate-profile 2018-05-24 10:26:24 +02:00
Jannis R
8c896fe8c1 docs for new polyline format 📝 2018-05-24 10:26:24 +02:00
Jannis R
431574b756 parseJourneyLeg, parseMovement: use parsePolyline 💥, refactor 2018-05-24 10:26:24 +02:00
Jannis R
deefeb1f64 add parsePolyline to default profile 2018-05-24 10:26:24 +02:00
Jannis R
0ef03015e0
validate opt.when 💥 2018-05-21 17:10:42 +02:00
Jannis R
ef42edbfd7
crypto.createHash -> create-hash, 2.7.3
closes #52
2018-05-21 12:18:57 +02:00
Jannis R
0840d69ee9
radar: assert north > south & east > west 2018-05-16 21:53:33 +02:00
Jannis R
c9e77f3050
merge master into next 2018-05-16 19:41:45 +02:00
Jannis R
48f2cefb5b
parseMovement: expose journey (leg) id 2018-05-16 19:32:11 +02:00
Jannis R
a97e0d31e7
radar: fix polylines parsing 🐛, 2.7.2 2018-05-16 00:43:08 +02:00
Jannis R
aa480e01a2
radar: fix polylines parsing 🐛 2018-05-16 00:30:27 +02:00
Jannis R
7b5f13524d
2.7.0 2018-05-15 23:49:56 +02:00
Jannis R
39aac10a17
parseMovement: empty default polylines arr 🐛 2018-05-15 23:04:13 +02:00
Jannis R
9a0bfc39a4
radar: polylines option, return polylines 2018-05-15 19:41:08 +02:00
Jannis R
06e759966c
tests: isValidWhen -> assertValidWhen 2018-05-14 00:47:47 +02:00
Jannis R
196681513c
parseJourneyLeg: null as fallback direction 🐛 2018-05-14 00:13:11 +02:00
Jannis R
4d908e1f72
tests: fix isRoughEqual call 🐛, minor change 2018-05-14 00:13:11 +02:00
Jannis R
2ca7e64fd5
journeys detour tests: use helper fn 2018-05-14 00:13:09 +02:00
Jannis R
c435e25390
parseJourneyLeg: null as fallback direction 🐛 2018-05-13 22:52:33 +02:00
Jannis R
0783d9e68a
fix Gitter badge 2018-05-13 22:42:02 +02:00
Jannis R
5cea7e47e4
merge next into tests-rewrite 2018-05-13 00:05:10 +02:00
Jannis R
bdc23c64e2
cherry-pick c60213a 2018-05-07 12:34:56 +02:00
Jannis R
df293e31cc
fix test helpers 🐛 2018-05-07 12:33:53 +02:00
Jannis R
2623fc44c6
merge master into next 2018-05-07 11:53:55 +02:00
Jannis R
47aea604df
fix error message 🐛 2018-05-03 10:29:43 +02:00
Jannis R
71d087aa23 refactor polyline parsing, add todo 2018-05-03 00:17:17 +02:00
Jannis R
37770654e1 journeyLeg: polyline option 2018-05-03 00:17:17 +02:00
Jannis R
7c6e87afff journey legs: return polylines 2018-05-03 00:17:17 +02:00
Jannis R
49afc8a75b journeys: polylines option 2018-05-03 00:17:17 +02:00
Jannis R
629385599c
2.6.0 2018-04-29 14:30:05 +02:00
Jannis R
5d10d76a15
journey legs: parse cycle 2018-04-29 14:29:29 +02:00
Jannis R
3c052e9fef
2.5.3 2018-04-29 14:22:56 +02:00
Jannis R
d676b8430d
fix journey leg alternatives 🐛
- use realtime data if available
- don't filter by departure station (HAFAS IDs are complicated)
2018-04-29 13:41:23 +02:00
Jannis R
7f02bfe4d5
add missing test helper fn 2018-04-26 16:17:53 +02:00
Jannis R
c769638005
add missing test helper fn, add todos, clean up 2018-04-25 13:24:27 +02:00
Jannis R
fecd2aefc0
journeys fails with no product tests: use helper fn 2018-04-25 13:23:53 +02:00
Jannis R
2ffcf02946
validate-fptf@2 2018-04-25 12:48:05 +02:00
Jannis R
cb5e01ed5b
departures tests: use helper fn 2018-04-24 18:16:59 +02:00
Jannis R
9501dab9f4
journeys from station to POI tests: use helper fn 2018-04-24 18:16:52 +02:00
Jannis R
c030724663
2.5.2 2018-04-24 17:04:55 +02:00
Jannis R
c60213a135
DB: tram mode should be train 🐛 2018-04-24 17:04:55 +02:00
Jannis R
3d69ae225d
DB: tram mode should be train 🐛 2018-04-24 16:59:35 +02:00
Jannis R
1018369576
journeys from station to address tests: use helper fn 2018-04-24 15:49:54 +02:00
Jannis R
6818635ee4
earlier/later journeys test: use helper fn 2018-04-24 15:28:36 +02:00
Jannis R
b364269041
Nah.sh: enable radar despite failing test
see #34 for more details
2018-04-23 16:30:57 +02:00
Jannis R
63e303b6f8
journeys from station to station test: use helper fn 2018-04-23 15:45:20 +02:00
Jannis R
279dfa4f8f
ÖBB tests: use new validators 2018-04-20 11:04:54 +02:00
Jannis R
e1f7e074be
NAH.SH tests: use new validators 2018-04-19 21:32:01 +02:00
Jannis R
0ce5e9114f
INSA tests: use new validators 2018-04-19 18:14:43 +02:00
Jannis R
a92afc3c28
test validators: bugfixes 🐛 2018-04-19 18:14:42 +02:00
Jannis R
e87ccf5a3b
DB: add currency to price 🐛, enable journeyLeg 2018-04-19 15:21:49 +02:00
Jannis R
46ce4bbbe0
DB tests: use new validators 2018-04-19 15:21:46 +02:00
Jannis R
1fb6d64f8a
VBB tests: use new validators 2018-04-18 23:56:11 +02:00
Jannis R
a2abf3b47d
tests: more validators 2018-04-18 23:54:09 +02:00
Jannis R
08a33497a0
pull validators from test/lib/util, use validate-fptf more 2018-04-18 23:53:51 +02:00
Jannis R
486929acc7
tests: move util, co, validate-line-without-mode into lib 2018-04-18 16:16:31 +02:00
Jannis R
41b574c468
tests: move assertValidStationProducts into assertValidStation 2018-04-18 16:12:59 +02:00
Jannis R
8ce89f0fe6
formatLocation: more helpful error messages 2018-04-17 18:49:49 +02:00
Julian Amelung
16e6dd6d14 Changed Journeys to Departures.
the endpoint which is discussed here is departures not journeys. 
If you use journeys with this parameters, you get mad with debugging.
2018-04-17 18:33:38 +02:00
Jannis R
3680f1fe94
fix products bitmask parsing 🐛 2018-04-09 19:37:44 +02:00
Jannis R
c8a144427e
2.5.1 2018-04-05 14:23:27 +02:00
Jannis R
afc0124982
fix stopover parsing 🐛 2018-04-05 14:23:14 +02:00
Jannis R
03e5cd350d
async stack traces: NODE_ENV=dev -> NODE_DEBUG=hafas-client 2018-04-05 14:17:30 +02:00
Jannis R
4fd7108ec6
VBB: strip "Tram " from line names 2018-03-31 14:03:23 +02:00
Jannis R
046b8c4117
VBB: strip "Bus " from line names 2018-03-29 23:17:50 +02:00
Jannis R
d96cbfb228
stopover: default arrival & departure fields 🐛, >= for collecting journeys 2018-03-29 02:45:15 +02:00
Julius Tens
261cc5ed2c add link to insa-hafas 2018-03-25 21:34:50 +02:00
Julius Tens
e8f21216a5
Merge pull request #40 from public-transport/profile-boilerplate
add simple profile boilerplate
2018-03-25 21:28:28 +02:00
Jannis R
27085d1db0
add simple profile boilerplate 2018-03-24 18:18:34 +01:00
Jannis R
2430a74414
adapt docs to 005f3f8 📝 2018-03-23 21:19:25 +01:00
Julius Tens
fe8f9c29f9
Merge pull request #39 from public-transport/remove-journey-shorthands
remove journey shorthands
2018-03-21 21:40:05 +01:00
Jannis R
4cba773eb0
adapt tests to 0e80be0 2018-03-21 01:55:53 +01:00
Jannis R
005f3f8e4d
remove journey.departure, .arrival, … 💥
closes #36
2018-03-21 01:55:31 +01:00
Jannis R
87ec80d404
NAH.SH: use new products markup 🐛 2018-03-21 01:54:31 +01:00
Jannis R
cfd79b1be1
parseJourney: use parseJourneyLeg from profile 🐛 2018-03-21 01:14:37 +01:00
Jannis R
98139f9210
prepare move to public-transport org 2018-03-19 22:34:08 +01:00
Jannis R
e71908ed1c
changelog for 2.4.x 2018-03-19 22:19:45 +01:00
Jannis R
f037ddf74c
writing a profile guide: runkit permalink 2018-03-19 22:01:22 +01:00
Jannis R
f37728c35b
writing a profile guide: runkit permalink 2018-03-19 22:00:25 +01:00
Jannis R
db1ad18cd5
adapt writing a profile guide to #32 2018-03-19 21:55:53 +01:00
Jannis R
ec0c283bf4
merge master into next 2018-03-19 21:18:53 +01:00
Jannis Redmann
7aba19f137
merge pull request #32 from refactor-products
new products markup
2018-03-18 13:22:24 +01:00
Jannis R
94988d98c0
yet another fix 🐛 2018-03-18 00:30:54 +01:00
Jannis R
ccd2dc0783
let parseProducts and formatProductsFilter get the real profile 🐛 2018-03-18 00:17:10 +01:00
Jannis R
854b0bd35e
homegrown isObj -> lodash/isObject 2018-03-18 00:13:44 +01:00
Jannis R
ad4d60f3ca
allow for overwriting parseProducts & formatProductsFilter 2018-03-18 00:11:51 +01:00
Julius Tens
a0fb841b8e
Merge pull request #33 from derhuerst/better-radar-signature
radar(north, west, south, east) -> radar({north, west, south, east})
2018-03-17 21:04:27 +01:00
Jannis R
83cae914a4
fix radar signature 🐛 2018-03-17 20:58:03 +01:00
Jannis R
89060afc8d
adapt docs and examples to 40b559f 📝 2018-03-16 17:28:52 +01:00
Jannis R
40b559f80d
radar(n, w, s, e) -> radar({n, w, s, e}) 💥, adapt tests 2018-03-16 17:28:20 +01:00
Jannis R
bc51d257fd
adapt tests to new products markup 2018-03-16 17:15:09 +01:00
Jannis R
94bbe2361b
products[].product -> products[].id 2018-03-16 17:15:09 +01:00
Jannis R
bbb68d86d5
validate products in lib/validate-profile 2018-03-16 17:15:09 +01:00
Jannis R
08357dfa9d
parseLine: move mode & products parsing from profiles into main code 2018-03-16 17:15:09 +01:00
Jannis R
83248785e5
formatProducts: move factory from profiles into main code
and rename to `formatProductsFilter`
2018-03-16 17:15:08 +01:00
Jannis R
ce43f15ad5
parseProducts: move factory from profiles into main code 2018-03-16 17:15:08 +01:00
Jannis R
b7c1ee3b05
new products markup 2018-03-16 17:15:08 +01:00
270 changed files with 59596 additions and 5938 deletions

2
.dockerignore Normal file
View file

@ -0,0 +1,2 @@
.git
node_modules

3
.github/funding.yml vendored Normal file
View file

@ -0,0 +1,3 @@
liberapay: derhuerst
patreon: derhuerst
github: derhuerst

59
.github/workflows/build.yml vendored Normal file
View file

@ -0,0 +1,59 @@
name: Build NPM Package & Docker
on:
push:
tags:
- 'v*'
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push-docker:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
id: push
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-pkg:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

101
.github/workflows/test.yml vendored Normal file
View file

@ -0,0 +1,101 @@
name: test
on: [push, pull_request, workflow_call]
env:
npm_config_cache: /tmp/npm-cache
jobs:
lint-and-spellcheck:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: "Checkout code"
uses: actions/checkout@v4
- name: "Use Node.js"
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- run: npm install
- name: Run lint check
run: npm run lint
- name: Run spell check
run: npm run test-spelling
unit-tests:
runs-on: ubuntu-latest
strategy:
matrix:
node-version:
- 18.x
- 20.x
- 22.x
steps:
- name: checkout
uses: actions/checkout@v4
- name: setup Node.js v${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- id: cache-npm
name: restore npm cache
uses: actions/cache@v4
with:
key: npm-cache-${{ github.ref_name }}-${{ matrix.node-version }}-unit-tests
path: ${{ env.npm_config_cache }}
- run: npm install
- run: npm run test-unit
integration-tests:
runs-on: ubuntu-latest
strategy:
matrix:
node-version:
- 18.x
- 20.x
- 22.x
steps:
- name: checkout
uses: actions/checkout@v4
- name: setup Node.js v${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- id: cache-npm
name: restore npm cache
uses: actions/cache@v4
with:
key: npm-cache-${{ github.ref_name }}-${{ matrix.node-version }}-integration-tests
path: ${{ env.npm_config_cache }}
- run: npm install
- run: npm run test-integration
e2e-tests:
needs: [unit-tests, integration-tests]
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
- name: checkout
uses: actions/checkout@v4
- name: setup Node.js v${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- id: cache-npm
name: restore npm cache
uses: actions/cache@v4
with:
key: npm-cache-${{ github.ref_name }}-${{ matrix.node-version }}-e2e-tests
path: ${{ env.npm_config_cache }}
- run: npm install
- run: npm run test-e2e

3
.gitignore vendored
View file

@ -4,3 +4,6 @@ Thumbs.db
.nvm-version
node_modules
npm-debug.log
/.tap
*.ign.*

View file

@ -1,6 +0,0 @@
sudo: false
language: node_js
node_js:
- 'stable'
- '8'
- '6'

22
Dockerfile Normal file
View file

@ -0,0 +1,22 @@
FROM node:18-alpine
LABEL org.opencontainers.image.title="db-vendo-client"
LABEL org.opencontainers.image.description="A clean REST API wrapping around the new Deutsche Bahn API."
LABEL org.opencontainers.image.authors="Traines <git@traines.eu>"
LABEL org.opencontainers.image.documentation="https://github.com/public-transport/db-vendo-client"
LABEL org.opencontainers.image.source="https://github.com/public-transport/db-vendo-client"
LABEL org.opencontainers.image.licenses="ISC"
WORKDIR /app
# install dependencies
#RUN apk add --update git
ADD package.json package-lock.json /app/
RUN npm install && npm cache clean --force
# add source code
ADD . /app
EXPOSE 3000
ENV PORT 3000
CMD ["node", "api.js"]

View file

@ -1,4 +1,7 @@
Copyright (c) 2017, Jannis R
# ISC License
- Copyright © 2024 Jannis R
- Copyright © 2025 traines-source
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

52
api.js Normal file
View file

@ -0,0 +1,52 @@
import {createClient} from './index.js';
import {profile as dbProfile} from './p/db/index.js';
import {profile as dbnavProfile} from './p/dbnav/index.js';
import {profile as dbwebProfile} from './p/dbweb/index.js';
import {profile as dbrisProfile} from './p/dbris/index.js';
import {profile as dbbahnhofProfile} from './p/dbbahnhof/index.js';
import {profile as dbregioguideProfile} from './p/dbregioguide/index.js';
import {mapRouteParsers} from './lib/api-parsers.js';
import {createHafasRestApi as createApi} from 'hafas-rest-api';
const config = {
hostname: process.env.HOSTNAME || 'localhost',
port: process.env.PORT ? parseInt(process.env.PORT) : 3000,
name: 'db-vendo-client',
description: 'db-vendo-client',
homepage: 'https://github.com/public-transport/db-vendo-client',
version: '6',
docsLink: 'https://github.com/public-transport/db-vendo-client',
openapiSpec: true,
logging: true,
aboutPage: true,
enrichStations: true,
etags: 'strong',
csp: 'default-src \'none\'; style-src \'self\' \'unsafe-inline\'; img-src https:',
mapRouteParsers,
};
const profiles = {
db: dbProfile,
dbnav: dbnavProfile,
dbweb: dbwebProfile,
dbris: dbrisProfile,
dbbahnhof: dbbahnhofProfile,
dbregioguide: dbregioguideProfile,
};
const start = async () => {
const vendo = createClient(
profiles[process.env.DB_PROFILE] || dbnavProfile,
process.env.USER_AGENT || 'link-to-your-project-or-email',
config,
);
const api = await createApi(vendo, config);
api.listen(config.port, (err) => {
if (err) {
console.error(err);
}
});
};
start();

7
contributing.md Normal file
View file

@ -0,0 +1,7 @@
# Contributing
Thanks for helping! 🙏
## Adding integration/end-to-end tests
Refer to the [testing docs](docs/tests.md).

644
cspell.config.json Normal file
View file

@ -0,0 +1,644 @@
{
"version": "0.2",
"language": "en",
"words": [
"Abfahrt",
"abfahrten",
"abfahrts",
"abfrage",
"abgangs",
"Abgelaufen",
"Abonnement",
"Abschnitte",
"abschnitts",
"Adelsheim",
"Adenauerplatz",
"agilis",
"Ahorn",
"Ahrensfelde",
"Aktualisierung",
"Alexanderplatz",
"alterseingabe",
"Altstadt",
"Alzey",
"andere",
"Anfang",
"anfrage",
"Anfrage",
"anfragezeit",
"Angebot",
"angebote",
"angebots",
"angebotsbeziehung",
"angebotseinholung",
"ANGEBOTSINFORMATION",
"Angebotsoption",
"angefragten",
"Angeltürn",
"ankuenfte",
"ankunft",
"ankunfts",
"Anmeldung",
"ANRUFPFLICHTIG",
"ANRUFPFLICHTIGEVERKEHRE",
"Anteil",
"anzahl",
"anzeige",
"Anzeigen",
"APPLEPAY",
"ARGUMENTE",
"arrs",
"Arverio",
"Aschaffenburg",
"attribut",
"Atze",
"Auerbach",
"AUSFALL",
"ausgegeben",
"auslastung",
"auslastungs",
"Auslastungsinformation",
"auslastungsmeldungen",
"auslastungstexte",
"Ausreserviert",
"außergewöhnlich",
"Ausserhalb",
"außerhalb",
"Ausstattung",
"Auswahl",
"autonome",
"bahnbonus",
"BAHNCARD",
"Bahnhof",
"bahnhofs",
"Bahnhofsinfo",
"bahnhofstafel",
"bahnhofstafeln",
"BARRIEREFREI",
"Bayerischer",
"BEFÖRDERER",
"begrenzt",
"behaviour",
"Behindertengerechte",
"Behindertengerechtes",
"Benoit",
"Beratzhausen",
"bereits",
"besonderer",
"Besucherpark",
"betrag",
"Beusselstraße",
"bezeichnung",
"Bietigheim",
"Bismarckstr",
"Bissingen",
"bitmasks",
"Blaschkoallee",
"Blissestr",
"BNWNZF",
"Böhme",
"BONVOYO",
"Bordbistro",
"Bordrestaurant",
"Boxberg",
"Breckerfeld",
"Britz",
"brokentrip",
"brutto",
"Buch",
"Buchbar",
"buchbarkeit",
"BUCHEN",
"BUCHUNG",
"buchungs",
"Bundesbahnen",
"Bundesplatz",
"BUSSE",
"bzgl",
"capacitorjs",
"Chaussee",
"checkin",
"childrens",
"CITYTICKET",
"clie",
"cncl",
"codeshares",
"conds",
"consumability",
"Consumability",
"Creglingen",
"crosssell",
"Ctrf",
"customisation",
"customisations",
"Damm",
"Daten",
"Dauer",
"dauerhaft",
"dbnav",
"dbregioguide",
"dbris",
"dbweb",
"Deldicque",
"DELFI",
"derhuerst",
"Deutz",
"dhid",
"differenzpreis",
"Dinkelsbühl",
"distanz",
"Dombühl",
"echtzeit",
"Eggmühl",
"ehemals",
"Eicholzheim",
"einchecken",
"eine",
"einfache",
"Einrichtung",
"Einstieg",
"einstiegs",
"Einstiegshilfe",
"Einstiegstyp",
"Eisenacher",
"emis",
"empfehlen",
"Ende",
"entfällt",
"Entgelt",
"ereignis",
"Erforderlich",
"erforderlicher",
"Ergoldsbach",
"Erlenbach",
"ERMAESSIGUNG",
"ermaessigungen",
"erster",
"ERWACHSENER",
"erwarten",
"erwartet",
"Eubigheim",
"Eurocity",
"eventuell",
"externe",
"Fahrkarte",
"fahrplan",
"Fahrplanperiode",
"Fahrpreis",
"Fahrradbeförderung",
"FAHRRADMITNAHME",
"Fahrt",
"FAHRZEUG",
"Fahrzeuggebundene",
"FAMILIENKIND",
"Fehler",
"Fehrbelliner",
"Fernbf",
"Fernverkehr",
"Flexpreis",
"Flix",
"Fltr",
"Flughafen",
"FPTF",
"Freising",
"Friedrichshall",
"Friedrichstr",
"frueher",
"Frwd",
"FUSSWEG",
"Fußweg",
"FVFFLPI",
"FVFSPPI",
"FVFSSPI",
"FVKBACI",
"GARE",
"Garten",
"Gastronomie",
"Gattung",
"gekauft",
"Geltungzeitpunkt",
"GENERALABONNEMENT",
"geolocation",
"geopositions",
"Geringe",
"gesamt",
"Gesundbrunnen",
"gleis",
"Gneisenaustr",
"Goerdelersteg",
"grafisch",
"Greifswalder",
"Grenzallee",
"Grünanlagen",
"gruppen",
"Gütersloh",
"GUTSCHEIN",
"haben",
"hafas",
"Hagelstadt",
"Halbtax",
"HALBTAXABO",
"Halemweg",
"Halensee",
"Hallerstraße",
"halte",
"Haltestellen",
"Hansering",
"Hansestadt",
"Haselhorst",
"Hauptbahnhof",
"Heidelberger",
"Hennef",
"Hermannplatz",
"Hermannstraße",
"hessen",
"Heuchelhof",
"HINFAHRT",
"Hinweis",
"Hinweise",
"HOCH",
"HOCHGESCHWINDIGKEITSZUEGE",
"Hohe",
"Hohenstadt",
"Hohenzollerndamm",
"Hüngheim",
"IBNR",
"Ihren",
"Ihrer",
"Informationen",
"INKLUSIVE",
"Innsbrucker",
"Instanz",
"INTERCITYUNDEUROCITYZUEGE",
"INTERREGIOUNDSCHNELLZUEGE",
"inventarsystem",
"irregulaere",
"Jakob",
"Jannis",
"Jannowitzbrücke",
"jetzt",
"Johannisthaler",
"journeystop",
"JUGENDLICHER",
"Jungfernheide",
"Kanal",
"KATALOG",
"kategorie",
"Kategorien",
"kategorisierung",
"kein",
"KEINE",
"Kennung",
"Kennzeichen",
"Kirche",
"klasse",
"KLASSENLOS",
"KLEINKIND",
"Kleistpark",
"Klima",
"KLIMATICKET",
"Köfering",
"Köln",
"kombinations",
"komfort",
"konditionen",
"konditions",
"Konstanzer",
"kontext",
"Kontingente",
"KRCC",
"KREDITKARTE",
"Kristjan",
"Kurz",
"kurztext",
"Landsberger",
"Landshut",
"langtext",
"LASTSCHRIFT",
"Lauda",
"letzte",
"letztes",
"leuchtturm",
"Lichtenberg",
"liegt",
"linien",
"Lipschitzallee",
"Loesungs",
"Ludwigsburg",
"luxon",
"materialisierungs",
"Maxnet",
"MBAAA",
"Mehringdamm",
"Meidling",
"Meldungen",
"Merchingen",
"Messe",
"Mierendorffplatz",
"Millis",
"Minden",
"mitteltext",
"mittlere",
"Mobilitätseingeschränkte",
"Mobilitätsservice",
"Möckernbrücke",
"Möckmühl",
"modul",
"moeckmuehl",
"Moeglich",
"möglich",
"Montabaur",
"Moosburg",
"Mosbach",
"Movas",
"München",
"Musiktheater",
"mwst",
"mxtxm",
"Nachgelagert",
"Nachricht",
"Nahreisezug",
"NAHVERKEHRSONSTIGEZUEGE",
"Naturkundemuseum",
"Neckarsulm",
"netto",
"Neufahrn",
"Neukölln",
"Neumarkt",
"NICHT",
"Niederbay",
"NIEDRIG",
"noch",
"noopener",
"Nord",
"noreferrer",
"Notiz",
"Notizen",
"NULLPREIS",
"nummer",
"nutzungs",
"Obereubigheim",
"Oberpf",
"Oberschefflenz",
"Obertraubling",
"Oberwittstadt",
"Ohne",
"orte",
"Ostbahnhof",
"Osterburken",
"Österreichische",
"Ostkreuz",
"Parchimer",
"Parsberg",
"passend",
"Passlist",
"Paulsternstr",
"Pauschalpreis",
"Pergamonkeller",
"Pergamonweg",
"Perleberg",
"PFLICHT",
"PLAETZE",
"planungs",
"platf",
"Platz",
"platzbedarfe",
"platzprofil",
"pollyjs",
"polyline",
"polylines",
"Positionen",
"Preis",
"preise",
"preisunterdrueckung",
"Prenzlauer",
"prio",
"priorisierte",
"prioritaet",
"produkt",
"produkte",
"produktgattungen",
"Profil",
"PRUEFEN",
"PUBLICTRANSPORT",
"Punkte",
"rabatt",
"Radzio",
"RAILPLUS",
"randomised",
"Ravenstein",
"Referenz",
"referenzen",
"referenziertes",
"Regio",
"Regionalbf",
"regulaere",
"regulaerer",
"reise",
"REISEANGEBOT",
"reiseloesung",
"reisende",
"reisenden",
"REISESTELLENKARTE",
"reisetag",
"Reisezentrum",
"REMENTR",
"REMRESR",
"Reservierbar",
"Reservieren",
"Reservierung",
"reservierungen",
"reservierungs",
"RESERVIERUNGSANGEBOT",
"RESERVIERUNGSENTGELT",
"reservierungspflicht",
"Rhein",
"richtung",
"roehrt",
"Rohrdamm",
"Roigheim",
"Rollstuhl",
"rollstuhlgerechte",
"Römisches",
"Rosenthal",
"Rothenburg",
"Rudow",
"Rueck",
"Rüsselsheim",
"Saale",
"Sammelfaehig",
"satz",
"SBAHN",
"SBAHNEN",
"Scharnweberstr",
"SCHIFF",
"SCHIFFE",
"Schlachthof",
"schnelle",
"Schöneberg",
"Schönefeld",
"Schönhauser",
"Schwedter",
"Seckach",
"Sennfeld",
"servicekategorie",
"SHCARD",
"sich",
"SICT",
"Sieg",
"Siegburg",
"Siemensdamm",
"Siglingen",
"sitzplatz",
"Sitzplatzreservierung",
"slugg",
"Sonnenallee",
"Sören",
"spaeter",
"Sparpreis",
"spezifische",
"Spichernstr",
"Spittelmarkt",
"Stadtgebiet",
"Stadtmitte",
"Stadtpark",
"Steinach",
"Storkower",
"STRASSENBAHN",
"stufe",
"stufenfrei",
"suchbegriff",
"Suche",
"Südkreuz",
"Südstern",
"Sutter",
"tage",
"täglich",
"tapjs",
"tarif",
"Tarifbereiche",
"Tarifgebiet",
"Tarifzone",
"Tauber",
"teilpreis",
"teilstrecken",
"Tempelhof",
"Texte",
"Tiergarten",
"Toel",
"Torfstr",
"Torfstraße",
"Traines",
"traveller",
"Travellers",
"travelling",
"Treptower",
"Tsua",
"tvlr",
"UBAHN",
"ueber",
"uebergreifende",
"ueberschrift",
"Uiffingen",
"Umbuchungen",
"Umstiege",
"umstiegs",
"Umstiegsdauer",
"Umstiegszeit",
"unsere",
"unter",
"Unterwittstadt",
"upsell",
"ursprungs",
"ushrp",
"uuidv",
"Vaihingen",
"vendo",
"verbindung",
"verbindungen",
"verbindungs",
"verbindungsabschnitt",
"verbindungssuche",
"Verfuegbar",
"verfügbar",
"verkehrmittel",
"verkehrsmittel",
"Verkehrstage",
"VERKNUEPFT",
"Verlauf",
"vertraglicher",
"vlexx",
"Voordeelurenabo",
"Vorhanden",
"VORTEILE",
"VORTEILSCARD",
"Vorverkaufszeitraum",
"waehrung",
"wagenreihung",
"wählen",
"Wannsee",
"Wegener",
"Weichselstr",
"wenden",
"wenn",
"Westbahn",
"Westend",
"Westf",
"westhafen",
"Westkreuz",
"wichtig",
"Wilmersdorfer",
"wird",
"Witzleben",
"wochentage",
"Worringen",
"wunsch",
"Wunschplatz",
"Württemberg",
"württembergallee",
"Würzburg",
"Wutzkyallee",
"Yorckstr",
"Yureka",
"Zahlungsarten",
"Zeitpunkt",
"Zeitraum",
"zgck",
"ziel",
"Zimmern",
"Zitadelle",
"Zoologischer",
"Zuege",
"zugart",
"zugattrib",
"zugattribute",
"Zuges",
"zugfahrt",
"zuglaeufe",
"Zuglauf",
"zugnummer",
"zulaessige",
"Zusammenfassung",
"Züttlingen",
"Zwickauer",
"zwischenhalte",
"bestprice",
"intervalle",
"Intervalle",
"tagesbest",
"dbbahnhof",
"Deutschlandticket",
"fahrverguenstigungen",
"cancelation"
],
"ignorePaths": [
"docs/dumps/**",
"test/e2e/fixtures/**",
"test/fixtures/**",
"test/parse/remarks.js",
"test/parse/dbnav-journey.js"
],
"dictionaries": [
"node"
]
}

19
docs/api.md Normal file
View file

@ -0,0 +1,19 @@
# `db-vendo-client` API
Also see the [root readme](https://github.com/public-transport/db-vendo-client) for a shortlist of differences of db-vendo-client to hafas-client and of differences between the profiles.
- [`journeys(from, to, [opt])`](journeys.md) get journeys between locations
- [`refreshJourney(refreshToken, [opt])`](refresh-journey.md) fetch up-to-date/more details of a `journey`
- `journeysFromTrip(tripId, previousStopover, to, [opt])` not supported
- [`trip(id, lineName, [opt])`](trip.md) get details for a trip
- `tripsByName(lineNameOrFahrtNr, [opt])` not supported
- [`departures(station, [opt])`](departures.md) query the next departures at a station
- [`arrivals(station, [opt])`](arrivals.md) query the next arrivals at a station
- [`locations(query, [opt])`](locations.md) find stations, POIs and addresses
- [`stop(id, [opt])`](stop.md) get details about a stop/station
- [`nearby(location, [opt])`](nearby.md) show stations & POIs around
- `radar(north, west, south, east, [opt])` not supported
- `reachableFrom(address, [opt])` not supported
- `remarks([opt])` not supported
- `lines(query, [opt])` not supported
- `serverInfo([opt])` not supported

3
docs/arrivals.md Normal file
View file

@ -0,0 +1,3 @@
# `arrivals(station, [opt])`
Just like [`departures(station, [opt])`](departures.md), except that it resolves with arrival times instead of departure times.

View file

@ -1,6 +0,0 @@
# Changelog
## `2.5.0`
- new [Schleswig-Holstein (NAH.SH)](https://de.wikipedia.org/wiki/Nahverkehrsverbund_Schleswig-Holstein) [profile](../p/nahsh)
- new [*writing a profile* guide](./writing-a-profile.md)

90
docs/db-apis.md Normal file
View file

@ -0,0 +1,90 @@
# New DB Board and Route Planning APIs (beyond HAFAS and IRIS)
(Beware that a DB journey is what you usually call a trip (a vehicle travelling at a certain time) and a DB trip is what you usually call a journey (result of a route search from A to B).)
## RIS::Boards
https://apis.deutschebahn.com/db/apis/ris-boards/v1/public/
EPs:
* departures/<evaNo>
* arrivals/<evaNo>
Notes:
* docs (also helpful for other RIS-based APIs below): https://developers.deutschebahn.com/db-api-marketplace/apis/product/ris-boards-transporteure/api/ris-boards-transporteure#/RISBoards_151/overview
* needs an API Key
* provides remarks
* does not provide loadFactor
* no route planning
* uses RIS trip IDs
* boards up to 12 hours
## bahnhof.de RIS
https://www.bahnhof.de/api/boards/departures?evaNumbers=8000105&filterTransports=BUS&duration=60&locale=de
Notes:
* no API Key needed
* provides remarks
* uses RIS trip IDs
* no route planning
* boards up to 6 hours, only from current time (or unknown parameter)
## Regio Guide RIS
https://regio-guide.de/@prd/zupo-travel-information/api/public/ri/
EPs:
* departure/8000105?modeOfTransport=HIGH_SPEED_TRAIN,REGIONAL_TRAIN,CITY_TRAIN,INTER_REGIONAL_TRAIN,UNKNOWN,BUS,TRAM,SUBWAY&timeStart=2024-12-11T15:08:25.678Z&timeEnd=2024-12-12T01:53:25.678&expandTimeFrame=TIME_END&&occupancy=true
* board/arrival/<evaNo>
* routing-search (with POST body, see regio-guide.de)
* trip/<tripId-from-routing-search>
* journey/<journeyId-from-trip>
Notes:
* no API Key needed
* no remarks in boards (or with unknown param), only some in journey
* cancelled trips are completely missing from boards (?)
* uses RIS trip IDs, does not expose them directly in the routing-search response
* loadFactor for some regional services, not for long distance services
* boards up to 12 hours
* routing-search returns polylines (!)
## Vendo/Movas Navigator API
https://app.vendo.noncd.db.de/mob/
EPs:
* bahnhofstafel/abfahrt
* bahnhofstafel/ankunft
* location/search
* angebote/fahrplan (for route planning)
* zuglauf
* zuglaeufe/ICE_947/halte/by-abfahrt/8000207_2024 (coach sequence)
* angebote/recon (tickets)
* trip/recon (polylines)
Notes:
* see [traffic dumps](dumps/)
* no API Key needed
* used by new DB Navigator
* HAFAS trip IDs
* boards only 1 hour (or unknown param)
* does not contain machine-readable cancelled info in the boards (only "Halt entfällt" string), but contains relevant remarks
* loadFactor only on journeys (?)
* polylines only for zuglauf and trip/recon
* limited remarks on boards
## Vendo/Movas bahn.de API
https://int.bahn.de/web/api/
EPs:
* angebote/fahrplan (for route planning)
* reiseloesung/orte
* reiseloesung/orte/nearby
* reiseloesung/verbindung
* reiseloesung/fahrt
* reiseloesung/abfahrten?datum=2024-12-30&zeit=11:55:00&ortExtId=8011160&ortId=A%3D1%40O%3DBerlin+Hbf%40X%3D13369549%40Y%3D52525589%40U%3D80%40L%3D8011160%40i%3DU%C3%97008065969%40&mitVias=true&maxVias=8&verkehrsmittel[]=ICE&verkehrsmittel[]=EC_IC&verkehrsmittel[]=IR&verkehrsmittel[]=REGIONAL
* reiseloesung/ankuenfte
Notes:
* no API Key needed
* uses HAFAS trip IDs
* provides loadFactor
* polylines only for /verbindung and /fahrt

View file

@ -24,38 +24,103 @@ With `opt`, you can override the default options, which look like this:
```js
{
when: new Date(),
direction: null, // only show departures heading to this station
duration: 10 // show departures for the next n minutes
direction: null, // only supported in `dbweb` and with `enrichStations=true` (experimental)
line: null, // not supported
duration: 10, // show departures for the next n minutes
results: null, // max. number of results; `null` means "whatever HAFAS wants"
subStops: true, // not supported
entrances: true, // not supported
linesOfStops: false, // not supported
remarks: true, // parse & expose hints & warnings?
stopovers: false, // fetch & parse previous/next stopovers?, only supported with `dbweb` profile
// departures at related stations
// e.g. those that belong together on the metro map.
includeRelatedStations: true,
moreStops: null // also include departures/arrivals for array of up to nine additional station evaNumbers (not supported with dbnav and dbweb)
language: 'en' // language to get results in
}
```
The maximum supported duration depends on the profile (see main readme), e.g. 720 for `db` and 60 for `dbnav`. In order to use the `dbris` profile, you need to pass the env vars `DB_API_KEY` and `DB_CLIENT_ID`.
If you pass an object `opt.products`, its fields will partially override the default products defined in the profile.
## Response
*Note:* As stated in the [*Friendly Public Transport Format* `1.0.1`](https://github.com/public-transport/friendly-public-transport-format/tree/1.0.1), the `when` field includes the current delay. The `delay` field, if present, expresses how much the former differs from the schedule.
*Note:* As stated in the [*Friendly Public Transport Format* v2 draft spec](https://github.com/public-transport/friendly-public-transport-format/blob/3bd36faa721e85d9f5ca58fb0f38cdbedb87bbca/spec/readme.md), the `when` field includes the current delay. The `delay` field, if present, expresses how much the former differs from the schedule.
You may pass the `journeyId` field into [`journeyLeg(ref, lineName, [opt])`](journey-leg.md) to get details on the vehicle's journey.
You may pass a departure's `tripId` into [`trip(id, lineName, [opt])`](trip.md) to get details on the whole trip. For the `dbnav`/`dbweb` profile HAFAS trip ids will be returned, for the `db` profile, RIS trip ids will be returned, then the `trip()` endpoint supports both id types.
As an example, we're going to use the [VBB profile](../p/vbb):
For `db` profile, cancelled trips will not be contained in the response! For the `db` and `dbnav` profile, only the most important remarks will be contained in the boards.
```js
const createClient = require('hafas-client')
const vbbProfile = require('hafas-client/p/vbb')
import {createClient} from 'db-vendo-client'
import {profile as dbnavProfile} from 'db-vendo-client/p/dbnav/index.js'
const client = createClient(vbbProfile)
const userAgent = 'link-to-your-project-or-email' // adapt this to your project!
const client = createClient(dbnavProfile, userAgent)
// S Charlottenburg
client.journeys('900000024101', {duration: 3})
.then(console.log)
.catch(console.error)
const {
departures,
realtimeDataUpdatedAt,
} = await client.departures('8089165', {duration: 3})
```
The response may look like this:
`realtimeDataUpdatedAt` is currently not set in db-vendo-client, because the upstream APIs don't provide it.
`departures` may look like this:
```js
[ {
journeyId: '1|31431|28|86|17122017',
tripId: '1|31431|28|86|17122017',
trip: 31431,
station: {
direction: 'S Spandau',
// Depending on the HAFAS endpoint, the destination may be present:
destination: {
type: 'stop',
id: '8089165',
name: 'S Spandau',
location: {
type: 'location',
id: '8089165',
latitude: 52.534794,
longitude: 13.197477
},
products: {
suburban: true,
subway: true,
tram: false,
bus: true,
ferry: false,
express: true,
regional: true,
},
},
line: {
type: 'line',
id: '18299',
fahrtNr: '12345',
mode: 'train',
product: 'suburban',
public: true,
name: 'S9',
symbol: 'S',
nr: 9,
metro: false,
express: false,
night: false,
operator: {
type: 'operator',
id: 's-bahn-berlin-gmbh',
name: 'S-Bahn Berlin GmbH'
}
},
currentTripPosition: {
type: 'location',
latitude: 52.500851,
longitude: 13.283755,
},
stop: {
type: 'station',
id: '900000024101',
name: 'S Charlottenburg',
@ -74,90 +139,77 @@ The response may look like this:
regional: true
}
},
when: '2017-12-17T19:32:00.000+01:00',
delay: null
line: {
type: 'line',
id: '18299',
name: 'S9',
public: true,
mode: 'train',
product: 'suburban',
symbol: 'S',
nr: 9,
metro: false,
express: false,
night: false,
productCode: 0,
operator: {
type: 'operator',
id: 's-bahn-berlin-gmbh',
name: 'S-Bahn Berlin GmbH'
}
},
direction: 'S Spandau'
}, {
journeyId: '1|30977|8|86|17122017',
trip: 30977,
station: { /* … */ },
when: null,
when: '2017-12-17T19:32:00+01:00',
plannedWhen: '2017-12-17T19:32:00+01:00',
delay: null,
platform: '2',
plannedPlatform: '2'
}, {
cancelled: true,
tripId: '1|30977|8|86|17122017',
trip: 30977,
direction: 'S Westkreuz',
line: {
type: 'line',
id: '16441',
name: 'S5',
public: true,
fahrtNr: '54321',
mode: 'train',
product: 'suburban',
public: true,
name: 'S5',
symbol: 'S',
nr: 5,
metro: false,
express: false,
night: false,
productCode: 0,
operator: { /* … */ }
},
direction: 'S Westkreuz'
}, {
journeyId: '1|28671|4|86|17122017',
trip: 28671,
station: {
type: 'station',
id: '900000024202',
name: 'U Wilmersdorfer Str.',
location: {
type: 'location',
latitude: 52.506415,
longitude: 13.306777
},
products: {
suburban: false,
subway: true,
tram: false,
bus: false,
ferry: false,
express: false,
regional: false
}
currentTripPosition: {
type: 'location',
latitude: 52.505004,
longitude: 13.322391,
},
when: '2017-12-17T19:35:00.000+01:00',
delay: 0,
stop: { /* … */ },
when: null,
plannedWhen: '2017-12-17T19:33:00+01:00'
delay: null,
platform: null,
plannedPlatform: '2',
prognosedPlatform: '2'
}, {
tripId: '1|28671|4|86|17122017',
trip: 28671,
direction: 'U Rudow',
line: {
type: 'line',
id: '19494',
name: 'U7',
public: true,
fahrtNr: '11111',
mode: 'train',
product: 'subway',
public: true,
name: 'U7',
symbol: 'U',
nr: 7,
metro: false,
express: false,
night: false,
productCode: 1,
operator: { /* … */ }
},
direction: 'U Rudow'
currentTripPosition: {
type: 'location',
latitude: 52.49864,
longitude: 13.307622,
},
stop: { /* … */ },
when: '2017-12-17T19:35:00+01:00',
plannedWhen: '2017-12-17T19:35:00+01:00',
delay: 0,
platform: null,
plannedPlatform: null
} ]
```

View file

@ -0,0 +1,18 @@
POST /mob/angebote/fahrplan HTTP/1.1
Accept: application/x.db.vendo.mob.verbindungssuche.v8+json
x-feature-reiseketten-enabled: false
X-Correlation-ID: 68f7ceba-70e7-4a88-b9b0-454809655314_3fbcc823-2a69-46f4-9484-6d94b1c0116a
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: 4779d837-2aa8-4613-9904-8f950367c3c0
Content-Type: application/x.db.vendo.mob.verbindungssuche.v8+json
Content-Length: 1120
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"autonomeReservierung":false,"einstiegsTypList":["STANDARD"],"klasse":"KLASSE_2","reiseHin":{"wunsch":{"abgangsLocationId":"A\u003d1@O\u003dMünchen Hbf@X\u003d11558339@Y\u003d48140229@U\u003d81@L\u003d8000261@B\u003d1@p\u003d1734722398@i\u003dU×008020347@","verkehrsmittel":["ALL"],"zeitWunsch":{"reiseDatum":"2025-01-02T15:21:31.877957+01:00","zeitPunktArt":"ABFAHRT"},"zielLocationId":"A\u003d1@O\u003dStuttgart Hbf@X\u003d9181636@Y\u003d48784081@U\u003d81@L\u003d8000096@B\u003d1@p\u003d1734722398@i\u003dU×008029034@"}},"reisendenProfil":{"reisende":[{"ermaessigungen":["CH-GENERAL-ABONNEMENT KLASSE_2","CH-GENERAL-ABONNEMENT KLASSE_1","CH-HALBTAXABO_OHNE_RAILPLUS KLASSENLOS","A-VORTEILSCARD KLASSENLOS"],"reisendenTyp":"SENIOR"},{"ermaessigungen":["CH-GENERAL-ABONNEMENT KLASSE_2","CH-GENERAL-ABONNEMENT KLASSE_1","CH-HALBTAXABO_OHNE_RAILPLUS KLASSENLOS","A-VORTEILSCARD KLASSENLOS"],"reisendenTyp":"SENIOR"},{"ermaessigungen":["KLIMATICKET_OE KLASSENLOS","NL-40_OHNE_RAILPLUS KLASSENLOS","BAHNCARD100 KLASSE_1","BAHNCARD100 KLASSE_2"],"reisendenTyp":"ERWACHSENER"}]},"reservierungsKontingenteVorhanden":false}

View file

@ -0,0 +1,17 @@
POST /mob/angebote/recon/autonomereservierung HTTP/1.1
Accept: application/x.db.vendo.mob.verbindungssuche.v8+json
X-Correlation-ID: 68f7ceba-70e7-4a88-b9b0-454809655314_3fbcc823-2a69-46f4-9484-6d94b1c0116a
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: 7d70a4fc-751f-4893-b2e2-11c925c0538b
Content-Type: application/x.db.vendo.mob.verbindungssuche.v8+json
Content-Length: 1872
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"einstiegsTypList":["STANDARD"],"klasse":"KLASSE_2","reisendenProfil":{"reisende":[{"alter":63,"ermaessigungen":["KLIMATICKET_OE KLASSENLOS","NL-40_OHNE_RAILPLUS KLASSENLOS"],"reisendenTyp":"ERWACHSENER"}]},"reservierungsKontingenteVorhanden":false,"verbindungHin":{"kontext":"¶HKI¶T$A\u003d1@O\u003dMünchen Hbf@X\u003d11558339@Y\u003d48140229@L\u003d8000261@a\u003d128@$A\u003d1@O\u003dStuttgart Hbf@X\u003d9181636@Y\u003d48784081@L\u003d8000096@a\u003d128@$202501021628$202501021832$ICE 912$$1$$$$$$§T$A\u003d1@O\u003dStuttgart Hbf@X\u003d9181636@Y\u003d48784081@L\u003d8000096@a\u003d128@$A\u003d1@O\u003dParis Est@X\u003d2359120@Y\u003d48876976@L\u003d8700011@a\u003d128@$202501021852$202501022214$TGV 9570$$1$$$$$$¶KC¶#VE#2#CF#100#CA#0#CM#0#SICT#0#AM#81#AM2#0#RT#7#¶KCC¶I1ZFIzEjRVJHIzIjSElOIzAjRUNLIzU2NDAyOHw1NjQwMjh8NTY0Mzc0fDU2NDM3NHwwfDB8NTY1fDU2Mzk1OHwxfDB8MjZ8MHwwfC0yMTQ3NDgzNjQ4I0dBTSMyMDEyNTE2MjgjClojVk4jMSNTVCMxNzM0NzIyMzk4I1BJIzEjWkkjMTk3Mzc3I1RBIzAjREEjMjAxMjUjMVMjODAwMDI2MSMxVCMxNjI4I0xTIzgwMDAwODAjTFQjMjIwMyNQVSM4MSNSVCMxI0NBI0lDRSNaRSM5MTIjWkIjSUNFICA5MTIjUEMjMCNGUiM4MDAwMjYxI0ZUIzE2MjgjVE8jODAwMDA5NiNUVCMxODMyIwpaI1ZOIzEjU1QjMTczNDcyMjM5OCNQSSMxI1pJIzIzOTQ0OSNUQSMwI0RBIzIwMTI1IzFTIzgwMDAwOTYjMVQjMTg1MiNMUyM4NzAwMDExI0xUIzIyMTQjUFUjODEjUlQjMSNDQSNSSFQjWkUjOTU3MCNaQiNUR1YgOTU3MCNQQyMwI0ZSIzgwMDAwOTYjRlQjMTg1MiNUTyM4NzAwMDExI1RUIzIyMTQj¶KRCC¶#VE#1#¶SC¶1_H4sIAAAAAAACA32PS07DMBiEr1J5XarfTtM8JEsmDRWgAhGiCIRYhMZtg/IotlMRRTkHl2HXi/EnEWxA7Dzj8XzjhhykIj6hE8clYyLfDYowmNyHEw+1km/Eb0hR5Qvi2+PuEBAfxqSsTBgbiWEGzAYKjPTmXZp3JrUZBUBr0zec0DF5LepFZtSS+E8NMfW+i0W3NyGG8jLp1MX1HMUhzqq+AphF2ud+03y3HYqRnMj9slwPNVmaYPKUU3HDr46fxXoni9H5y0Y8cEpt27UsTzzyqUunwJgnVtylYsldAGAzKgJ8t+fUsaYOY5bnipSvjh8ALjBAT+AYbYZPLvolsVJ/oqNYpXp0pg1ymWV7lEGPdZ2Z58x+sA5y6T9Yh1IL4Dd2K01UZnWWFugZVcneuiwrVcg6KKsi0cTfxJkeLqJY6yzV5jsr1yUOjHMMNW3bfgFUarsn8gEAAA\u003d\u003d"}}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,18 @@
POST /mob/angebote/recon HTTP/1.1
Accept: application/x.db.vendo.mob.verbindungssuche.v8+json
x-feature-reiseketten-enabled: false
X-Correlation-ID: e1927e98-0d8c-45f2-a161-965622ccd56a_e8cf6ea4-4103-4707-aa44-2287646a87f9
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: dcf2d458-4e11-4e40-a6e3-8922544387e8
Content-Type: application/x.db.vendo.mob.verbindungssuche.v8+json
Content-Length: 2749
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"einstiegsTypList":["STANDARD"],"klasse":"KLASSE_2","reisendenProfil":{"reisende":[{"ermaessigungen":["KEINE_ERMAESSIGUNG KLASSENLOS"],"reisendenTyp":"ERWACHSENER"}]},"reservierungsKontingenteVorhanden":false,"verbindungHin":{"kontext":"¶HKI¶T$A\u003d1@O\u003dMünchen Hbf@X\u003d11558339@Y\u003d48140229@L\u003d8000261@a\u003d128@$A\u003d1@O\u003dFrankfurt(Main)Hbf@X\u003d8663785@Y\u003d50107149@L\u003d8000105@a\u003d128@$202501030000$202501030438$ICE 618$$1$$$$$$§T$A\u003d1@O\u003dFrankfurt(Main)Hbf@X\u003d8663785@Y\u003d50107149@L\u003d8000105@a\u003d128@$A\u003d1@O\u003dKassel-Wilhelmshöhe@X\u003d9447114@Y\u003d51312558@L\u003d8003200@a\u003d128@$202501030512$202501030644$ICE 1088$$1$$$$$$§T$A\u003d1@O\u003dKassel-Wilhelmshöhe@X\u003d9447114@Y\u003d51312558@L\u003d8003200@a\u003d128@$A\u003d1@O\u003dHamm(Westf)Hbf@X\u003d7807824@Y\u003d51678077@L\u003d8000149@a\u003d128@$202501030703$202501030850$RE 26708$$1$$$$$$§T$A\u003d1@O\u003dHamm(Westf)Hbf@X\u003d7807824@Y\u003d51678077@L\u003d8000149@a\u003d128@$A\u003d1@O\u003dMünster(Westf)Hbf@X\u003d7635716@Y\u003d51956563@L\u003d8000263@a\u003d128@$202501030859$202501030922$RE 32916$$1$$$$$$¶KC¶#VE#2#CF#100#CA#0#CM#0#SICT#0#AM#81#AM2#0#RT#7#¶KCC¶I1ZFIzEjRVJHIzQ1MzE2I0hJTiMwI0VDSyM1NjQ0ODB8NTY0NDgwfDU2NDk1NHw1NjUwNDJ8MHwwfDU2NXw1NjQ0MTN8NHwwfDh8MHwwfC0yMTQ3NDgzNjQ4I0dBTSMzMDEyNTAwMDAjClojVk4jMSNTVCMxNzM0NzIyMzk4I1BJIzEjWkkjMTk1OTUyI1RBIzAjREEjMzAxMjUjMVMjODAwMDI2MSMxVCMwI0xTIzgwMDAxOTkjTFQjMTEyMyNQVSM4MSNSVCMxI0NBI0lDRSNaRSM2MTgjWkIjSUNFICA2MTgjUEMjMCNGUiM4MDAwMjYxI0ZUIzAjVE8jODAwMDEwNSNUVCM0MzgjClojVk4jMSNTVCMxNzM0NzIyMzk4I1BJIzEjWkkjMTkyODc1I1RBIzAjREEjMzAxMjUjMVMjODAwMDEwNSMxVCM1MTIjTFMjODAwMDE5OSNMVCMxMDE4I1BVIzgxI1JUIzEjQ0EjSUNFI1pFIzEwODgjWkIjSUNFIDEwODgjUEMjMCNGUiM4MDAwMTA1I0ZUIzUxMiNUTyM4MDAzMjAwI1RUIzY0NCMKWiNWTiMxI1NUIzE3MzQ3MjIzOTgjUEkjMSNaSSMyMTg2NjIjVEEjMCNEQSMzMDEyNSMxUyM4MDAzMjAwIzFUIzcwMyNMUyM4MDAwMTQ5I0xUIzg1MCNQVSM4MSNSVCMxI0NBI0RQTiNaRSMyNjcwOCNaQiNSRSAyNjcwOCNQQyMzI0ZSIzgwMDMyMDAjRlQjNzAzI1RPIzgwMDAxNDkjVFQjODUwIwpaI1ZOIzEjU1QjMTczNDcyMjM5OCNQSSMxI1pJIzIxNzk5NiNUQSMwI0RBIzMwMTI1IzFTIzgwMDAxNzEjMVQjODQzI0xTIzgwMDAzMTYjTFQjOTUxI1BVIzgxI1JUIzEjQ0EjRFBOI1pFIzMyOTE2I1pCI1JFIDMyOTE2I1BDIzMjRlIjODAwMDE0OSNGVCM4NTkjVE8jODAwMDI2MyNUVCM5MjIj¶KRCC¶#VE#1#¶SC¶1_H4sIAAAAAAACA32P3UrDMACFX0VypVBHfpr+QSB2ZahMV8T5g3hR13SrdO1M0mEpfQ5fxru9mGmLFyJ6l3Nycr6TFuyFBAFAE9cDFhDv2ogonNxFE99oKd5A0IKy3s5AQK3+EIIAWqCqdZRoYcIYYgoRxGAwb/PtYGKbQGisbGg4RRZ4LZtZoeUcBE8t0M2uj8U3i8iEtlXaq4vrqRH7pKh7ZSoJ6J6HTdPNeiw25FTs5tVqrCny1CTPGOILdnX4LFcbUR6dv2T8gSFEqUeIzx+Z7SEbYuzzJfMQnzMPQogdxEPzbseQS2wXY+J7PGfLwweEHsTQeNyMUXr85GxYkkj5J1ppIY/vhdLZyTjAdQh1kWP4FPnUoQ75ySf/8RFE6Dd/LXRcFU2Rl8bTshaDdVnVshRNWNVlqkCQJYUaL+JEqSJX+jsrVlWcyGRrQm3XdV8RCJMF+wEAAA\u003d\u003d"}}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,17 @@
POST /mob/location/search HTTP/1.1
Accept: application/x.db.vendo.mob.location.v3+json
X-Correlation-ID: 4f2e274e-6e5c-4711-9125-87229046bba3_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: 560187ed-f13a-4654-bc62-b9f69f989563
Content-Type: application/x.db.vendo.mob.location.v3+json
Content-Length: 45
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"locationTypes":["ALL"],"searchTerm":"test"}

View file

@ -0,0 +1,17 @@
HTTP/1.1 200 OK
Date: Mon, 16 Dec 2024 18:29:33 GMT
Content-Type: application/x.db.vendo.mob.location.v3+json
Content-Length: 2994
Connection: keep-alive
server-timing: intid;desc=a0c42ccdea3bbb18
Server-Timing: intid;desc=a0c42ccdea3bbb18
Server-Timing: intid;desc=a0c42ccdea3bbb18
x-correlation-id: 4f2e274e-6e5c-4711-9125-87229046bba3_64466773-556f-4aa8-b128-0948c4d60887
Strict-Transport-Security: max-age=16070400; includeSubDomains
X-XSS-Protection: 0
server-timing: intid;desc=a0c42ccdea3bbb18
Content-Security-Policy: frame-ancestors 'none';
X-Content-Type-Options: nosniff
Set-Cookie: TS01be2125=01d513bcd1e15efa531633ee310f49108472c2b1a482b002a4d22b5cf935d3d6970510c0b134616b579c639af340fe261746662484; Path=/; Domain=.app.vendo.noncd.db.de; Secure; HTTPOnly
[{"name":"Tessin West","stationId":"7983","locationId":"A=1@O=Tessin West@X=12442572@Y=54034438@U=81@L=8079604@B=1@p=1734031727@i=U×008030295@","evaNr":"8079604","coordinates":{"latitude":54.0344,"longitude":12.442203},"weight":1489,"products":["NAHVERKEHRSONSTIGEZUEGE","BUSSE","ANRUFPFLICHTIGEVERKEHRE"],"locationType":"ST"},{"name":"Testa Grigia","locationId":"A=1@O=Testa Grigia@X=7707540@Y=45934474@U=81@L=8511303@B=1@p=1734031727@i=U×008511303@","evaNr":"8511303","coordinates":{"latitude":45.934475,"longitude":7.70754},"weight":3825,"products":["NAHVERKEHRSONSTIGEZUEGE"],"locationType":"ST"},{"name":"Teschenhagen","stationId":"6172","locationId":"A=1@O=Teschenhagen@X=13374232@Y=54389368@U=81@L=8013104@B=1@p=1734031727@i=U×008028497@","evaNr":"8013104","coordinates":{"latitude":54.38936,"longitude":13.374196},"weight":3825,"products":["NAHVERKEHRSONSTIGEZUEGE"],"locationType":"ST"},{"name":"Testelt","locationId":"A=1@O=Testelt@X=4946863@Y=51009783@U=81@L=8800244@B=1@p=1734031727@i=U×008833266@","evaNr":"8800244","coordinates":{"latitude":51.009785,"longitude":4.946863},"weight":2627,"products":["INTERCITYUNDEUROCITYZUEGE","NAHVERKEHRSONSTIGEZUEGE"],"locationType":"ST"},{"name":"Tessin","stationId":"6174","locationId":"A=1@O=Tessin@X=12462618@Y=54032020@U=81@L=8013106@B=1@p=1734031727@i=U×008027109@","evaNr":"8013106","coordinates":{"latitude":54.032,"longitude":12.461656},"weight":2402,"products":["NAHVERKEHRSONSTIGEZUEGE","BUSSE"],"locationType":"ST"},{"name":"Chemnitz Zentralhaltestelle","locationId":"A=1@O=Chemnitz Zentralhaltestelle@X=12922263@Y=50831626@U=81@L=8017419@B=1@p=1734031727@i=U×008042918@","evaNr":"8017419","coordinates":{"latitude":50.831627,"longitude":12.922263},"weight":5813,"products":["NAHVERKEHRSONSTIGEZUEGE","BUSSE","STRASSENBAHN","ANRUFPFLICHTIGEVERKEHRE"],"locationType":"ST"},{"name":"Teschow","stationId":"6173","locationId":"A=1@O=Teschow@X=11637956@Y=53994355@U=81@L=8013105@B=1@p=1734031727@i=U×008027118@","evaNr":"8013105","coordinates":{"latitude":53.994175,"longitude":11.637687},"weight":1524,"products":["NAHVERKEHRSONSTIGEZUEGE","BUSSE"],"locationType":"ST"},{"name":"Tesperhude Hudehof, Geesthacht","locationId":"A=1@O=Tesperhude Hudehof, Geesthacht@X=10431253@Y=53404393@U=81@L=694334@B=1@p=1734031727@","evaNr":"694334","coordinates":{"latitude":53.404392,"longitude":10.431253},"weight":912,"products":["BUSSE"],"locationType":"ST"},{"name":"Tesperhude Strandweg, Geesthacht","locationId":"A=1@O=Tesperhude Strandweg, Geesthacht@X=10427424@Y=53402316@U=81@L=694333@B=1@p=1734031727@","evaNr":"694333","coordinates":{"latitude":53.402317,"longitude":10.427424},"weight":912,"products":["BUSSE"],"locationType":"ST"},{"name":"Testorf Umspannwerk, Wangels","locationId":"A=1@O=Testorf Umspannwerk, Wangels@X=10778516@Y=54250161@U=81@L=700240@B=1@p=1734031727@","evaNr":"700240","coordinates":{"latitude":54.25016,"longitude":10.778516},"weight":220,"products":["BUSSE","ANRUFPFLICHTIGEVERKEHRE"],"locationType":"ST"}]

View file

@ -0,0 +1,18 @@
POST /mob/angebote/fahrplan HTTP/1.1
Accept: application/x.db.vendo.mob.verbindungssuche.v8+json
x-feature-reiseketten-enabled: false
X-Correlation-ID: 0564dcdf-edbf-4412-a147-7299f6481470_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: 0d0c6c50-3bea-4cb7-b008-09bc92a0d96a
Content-Type: application/x.db.vendo.mob.verbindungssuche.v8+json
Content-Length: 679
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"autonomeReservierung":false,"einstiegsTypList":["STANDARD"],"klasse":"KLASSE_2","reiseHin":{"wunsch":{"abgangsLocationId":"A\u003d1@O\u003dBerlin Hbf@X\u003d13369549@Y\u003d52525589@U\u003d81@L\u003d8011160@B\u003d1@p\u003d1734031727@i\u003dU×008065969@","verkehrsmittel":["ALL"],"zeitWunsch":{"reiseDatum":"2024-12-16T19:28:48.659812+01:00","zeitPunktArt":"ABFAHRT"},"zielLocationId":"A\u003d1@O\u003dKöln Hbf@X\u003d6958730@Y\u003d50943029@U\u003d81@L\u003d8000207@B\u003d1@p\u003d1734031727@i\u003dU×008015458@"}},"reisendenProfil":{"reisende":[{"ermaessigungen":["KEINE_ERMAESSIGUNG KLASSENLOS"],"reisendenTyp":"ERWACHSENER"}]},"reservierungsKontingenteVorhanden":false}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,17 @@
POST /mob/trip/recon HTTP/1.1
Accept: application/x.db.vendo.mob.verbindungssuche.v8+json
X-Correlation-ID: 0564dcdf-edbf-4412-a147-7299f6481470_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: 757b9806-028b-4b0e-bdde-2441c2e1e1ee
Content-Type: application/x.db.vendo.mob.verbindungssuche.v8+json
Content-Length: 1162
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"reconCtx":"¶HKI¶T$A\u003d1@O\u003dBerlin Hbf@X\u003d13369549@Y\u003d52525589@L\u003d8011160@a\u003d128@$A\u003d1@O\u003dKöln Hbf@X\u003d6958730@Y\u003d50943029@L\u003d8000207@a\u003d128@$202412161946$202412170057$ICE 842$$1$$$$$$¶KC¶#VE#2#CF#100#CA#0#CM#0#SICT#0#AM#81#AM2#0#RT#7#¶KCC¶I1ZFIzEjRVJHIzEjSElOIzAjRUNLIzUzOTc0Nnw1Mzk3NDZ8NTQwMDU3fDU0MDA1N3wwfDB8NTY1fDUzOTcyNXwxfDB8MTA1MHwwfDB8LTIxNDc0ODM2NDgjR0FNIzE2MTIyNDE5NDYjClojVk4jMSNTVCMxNzM0MDMxNzI3I1BJIzEjWkkjMTc3NjUxI1RBIzAjREEjMTYxMjI0IzFTIzgwMTAyNTUjMVQjMTkzNCNMUyM4MDAwMjA3I0xUIzEwMDU3I1BVIzgxI1JUIzEjQ0EjSUNFI1pFIzg0MiNaQiNJQ0UgIDg0MiNQQyMwI0ZSIzgwMTExNjAjRlQjMTk0NiNUTyM4MDAwMjA3I1RUIzEwMDU3Iw\u003d\u003d¶KRCC¶#VE#1#¶SC¶1_H4sIAAAAAAACA32P7UrDMBiFb0Xyu4436WcKgdiV4cfQIk4U8Udds1lJ25mmw1J6Hd6JN7AbM20ZCIrkT87JyXnet0N7oVCI8MwPkIXEhzYijmb38YwarcQ7CjtUNsUCha41XCIUgoWqRsepFiZMgDiYYA+N5l1eDCamJAAw1mZsOMUWeivbhdRqicKnDul2N8SS25vYhIoqG9TF9dyIfSqbsQKIjfrncab563YqNuRM7JbVeqqReWaSZwzzGxYJJfPy5Pxlwx8Ytm2Pug7lj8wl5rgB5SsWYL5kAWCMPeCR+bVj2LcdsLFPfJ6z1eETIADPpR7lZpRaTysuxjlSpf4EXx2+5JFroIFvw4AF6thAfmABCPj/YLHruMFv7FbopJKt2c14WjVitC6rRpWijaqmzGoUblJZTw9JWtcyr/UxK9ZVkqq0MKGu7/tvvH4lCvABAAA\u003d"}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,17 @@
POST /mob/trip/recon HTTP/1.1
Accept: application/x.db.vendo.mob.verbindungssuche.v8+json
X-Correlation-ID: 0564dcdf-edbf-4412-a147-7299f6481470_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: f30d7ef5-d9a2-428b-acc2-e8bb68c7d705
Content-Type: application/x.db.vendo.mob.verbindungssuche.v8+json
Content-Length: 2507
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"reconCtx":"¶HKI¶T$A\u003d1@O\u003dBerlin Hbf@X\u003d13369549@Y\u003d52525589@L\u003d8098160@a\u003d128@$A\u003d1@O\u003dHannover Hbf@X\u003d9741017@Y\u003d52376764@L\u003d8000152@a\u003d128@$202412162128$202412162322$ICE 840$$1$$$$$$§T$A\u003d1@O\u003dHannover Hbf@X\u003d9741017@Y\u003d52376764@L\u003d8000152@a\u003d128@$A\u003d1@O\u003dHanau Hbf@X\u003d8929003@Y\u003d50120957@L\u003d8000150@a\u003d128@$202412170030$202412170414$IC 60471$$1$$$$$$§T$A\u003d1@O\u003dHanau Hbf@X\u003d8929003@Y\u003d50120957@L\u003d8000150@a\u003d128@$A\u003d1@O\u003dFrankfurt(Main)Hbf@X\u003d8663785@Y\u003d50107149@L\u003d8000105@a\u003d128@$202412170455$202412170515$RB 15501$$1$$$$$$§T$A\u003d1@O\u003dFrankfurt(Main)Hbf@X\u003d8663785@Y\u003d50107149@L\u003d8000105@a\u003d128@$A\u003d1@O\u003dKöln Hbf@X\u003d6958730@Y\u003d50943029@L\u003d8000207@a\u003d128@$202412170526$202412170633$ICE 222$$1$$$$$$¶KC¶#VE#2#CF#100#CA#0#CM#0#SICT#0#AM#81#AM2#0#RT#7#¶KCC¶I1ZFIzEjRVJHIzI2MCNISU4jNDU1I0VDSyM1Mzk4NDh8NTM5ODQ4fDU0MDM5M3w1NDAzOTN8MHwwfDU2NXw1Mzk4NDh8NHwwfDE4fDB8MHwtMjE0NzQ4MzY0OCNHQU0jMTYxMjI0MjEyOCMKWiNWTiMxI1NUIzE3MzQwMzE3MjcjUEkjMSNaSSMxNzc2MTkjVEEjMCNEQSMxNjEyMjQjMVMjODA5ODE2MCMxVCMyMTI4I0xTIzgwMDAxNTIjTFQjMjMyMiNQVSM4MSNSVCMxI0NBI0lDRSNaRSM4NDAjWkIjSUNFICA4NDAjUEMjMCNGUiM4MDk4MTYwI0ZUIzIxMjgjVE8jODAwMDE1MiNUVCMyMzIyIwpaI1ZOIzEjU1QjMTczNDAzMTcyNyNQSSMxI1pJIzE3MzY1MSNUQSMwI0RBIzE2MTIyNCMxUyM4MDAyNTUzIzFUIzIxNTIjTFMjODUwMzAwMCNMVCMxMTAwNSNQVSM4MSNSVCMxI0NBI0lDI1pFIzYwNDcxI1pCI0lDIDYwNDcxI1BDIzEjRlIjODAwMDE1MiNGVCMxMDAzMCNUTyM4MDAwMTUwI1RUIzEwNDE0IwpaI1ZOIzEjU1QjMTczNDAzMTcyNyNQSSMxI1pJIzE4NzYxOCNUQSMwI0RBIzE3MTIyNCMxUyM4MDA2MTMyIzFUIzQxOCNMUyM4MDAwMTA1I0xUIzUxNSNQVSM4MSNSVCMxI0NBI1JCI1pFIzE1NTAxI1pCI1JCIDE1NTAxI1BDIzMjRlIjODAwMDE1MCNGVCM0NTUjVE8jODAwMDEwNSNUVCM1MTUjClojVk4jMSNTVCMxNzM0MDMxNzI3I1BJIzEjWkkjMjExNDMzI1RBIzAjREEjMTcxMjI0IzFTIzgwMDAxMDUjMVQjNTI2I0xTIzg0MDAwNTgjTFQjOTI5I1BVIzgxI1JUIzEjQ0EjSUNFI1pFIzIyMiNaQiNJQ0UgIDIyMiNQQyMwI0ZSIzgwMDAxMDUjRlQjNTI2I1RPIzgwMDAyMDcjVFQjNjMzIw\u003d\u003d¶KRCC¶#VE#1#¶SC¶1_H4sIAAAAAAACA32P7UrDMBiFb0Xyu4436WcKgdiV4cfQIk4U8Udds1lJ25mmw1J6Hd6JN7AbM20ZCIrkT87JyXnet0N7oVCI8MwPkIXEhzYijmb38YwarcQ7CjtUNsUCha41XCIUgoWqRsepFiZMgDiYYA+N5l1eDCamJAAw1mZsOMUWeivbhdRqicKnDul2N8SS25vYhIoqG9TF9dyIfSqbsQKIjfrncab563YqNuRM7JbVeqqReWaSZwzzGxYJJfPy5Pxlwx8Ytm2Pug7lj8wl5rgB5SsWYL5kAWCMPeCR+bVj2LcdsLFPfJ6z1eETIADPpR7lZpRaTysuxjlSpf4EXx2+5JFroIFvw4AF6thAfmABCPj/YLHruMFv7FbopJKt2c14WjVitC6rRpWijaqmzGoUblJZTw9JWtcyr/UxK9ZVkqq0MKGu7/tvvH4lCvABAAA\u003d"}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,15 @@
GET /mob/location/details/8011160 HTTP/1.1
Accept: application/x.db.vendo.mob.location.v3+json
Content-Type: application/x.db.vendo.mob.location.v3+json
X-Correlation-ID: 0564dcdf-edbf-4412-a147-7299f6481470_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: b9bd5e93-e6d2-4998-bc5a-17b72ca65ca3
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0

View file

@ -0,0 +1,17 @@
HTTP/1.1 200 OK
Date: Mon, 16 Dec 2024 18:36:50 GMT
Content-Type: application/x.db.vendo.mob.location.v3+json
Content-Length: 1158
Connection: keep-alive
server-timing: intid;desc=5ae5ce547c4a8b38
Server-Timing: intid;desc=5ae5ce547c4a8b38
Server-Timing: intid;desc=5ae5ce547c4a8b38
x-correlation-id: 0564dcdf-edbf-4412-a147-7299f6481470_64466773-556f-4aa8-b128-0948c4d60887
Strict-Transport-Security: max-age=16070400; includeSubDomains
X-XSS-Protection: 0
server-timing: intid;desc=5ae5ce547c4a8b38
Content-Security-Policy: frame-ancestors 'none';
X-Content-Type-Options: nosniff
Set-Cookie: TS01be2125=01d513bcd125629ac814505605565f3e87a8081db30d56beae22efb148df982534183fd830148fa0901fa5a36116fab13d52c5d86a; Path=/; Domain=.app.vendo.noncd.db.de; Secure; HTTPOnly
{"haltName":"Berlin Hbf","produktGattungen":[{"produktGattung":"HOCHGESCHWINDIGKEITSZUEGE","produkte":[{"name":"ICE"},{"name":"RJ"}]},{"produktGattung":"INTERCITYUNDEUROCITYZUEGE","produkte":[{"name":"EC"},{"name":"IC"},{"name":"NJ"}]},{"produktGattung":"INTERREGIOUNDSCHNELLZUEGE","produkte":[{"name":"BUS"},{"name":"Bus"},{"name":"D"},{"name":"EN"},{"name":"ES"},{"name":"FLX"},{"name":"UEX"}]},{"produktGattung":"NAHVERKEHRSONSTIGEZUEGE","produkte":[{"name":"FEX"},{"name":"HBX"},{"name":"R"},{"name":"RB"},{"name":"RE"},{"name":"RSM"},{"name":"Bus RE3"},{"name":"Bus RE5"},{"name":"Bus RE7"},{"name":"Bus RE8"},{"name":"Bus S7"}]},{"produktGattung":"SBAHNEN","produkte":[{"name":"S 3"},{"name":"S 5"},{"name":"S 7"},{"name":"S 9"},{"name":"S 45"}]},{"produktGattung":"BUSSE","produkte":[{"name":"Bus 120"},{"name":"Bus 123"},{"name":"Bus 142"},{"name":"Bus 147"},{"name":"Bus 245"},{"name":"Bus M41"},{"name":"Bus M85"},{"name":"Bus N5"},{"name":"Bus N20"},{"name":"Bus N40"}]},{"produktGattung":"UBAHN","produkte":[{"name":"U 5"}]},{"produktGattung":"STRASSENBAHN","produkte":[{"name":"STR 12"},{"name":"STR M5"},{"name":"STR M8"},{"name":"STR M10"}]}]}

View file

@ -0,0 +1,17 @@
POST /mob/bahnhofstafel/abfahrt HTTP/1.1
Accept: application/x.db.vendo.mob.bahnhofstafeln.v2+json
X-Correlation-ID: 0564dcdf-edbf-4412-a147-7299f6481470_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: b2d3fe71-a8d6-4675-bbe5-a5081368a6ab
Content-Type: application/x.db.vendo.mob.bahnhofstafeln.v2+json
Content-Length: 197
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"anfragezeit":"21:28","datum":"2024-12-16","ursprungsBahnhofId":"A\u003d1@O\u003dBerlin Hbf@X\u003d13369549@Y\u003d52525589@U\u003d81@L\u003d8098160@i\u003dU×008031922@","verkehrsmittel":["ALL"]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,17 @@
POST /mob/bahnhofstafel/abfahrt HTTP/1.1
Accept: application/x.db.vendo.mob.bahnhofstafeln.v2+json
X-Correlation-ID: 0564dcdf-edbf-4412-a147-7299f6481470_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: 8c20d0c0-3c0b-40ef-bc95-849c65e375df
Content-Type: application/x.db.vendo.mob.bahnhofstafeln.v2+json
Content-Length: 378
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"anfragezeit":"21:28","datum":"2024-12-16","ursprungsBahnhofId":"A\u003d1@O\u003dBerlin Hbf@X\u003d13369549@Y\u003d52525589@U\u003d81@L\u003d8098160@i\u003dU×008031922@","verkehrsmittel":["HOCHGESCHWINDIGKEITSZUEGE","INTERCITYUNDEUROCITYZUEGE","INTERREGIOUNDSCHNELLZUEGE","NAHVERKEHRSONSTIGEZUEGE","SBAHNEN","BUSSE","SCHIFFE","UBAHN","STRASSENBAHN","ANRUFPFLICHTIGEVERKEHRE"]}

View file

@ -0,0 +1,17 @@
POST /mob/bahnhofstafel/ankunft HTTP/1.1
Accept: application/x.db.vendo.mob.bahnhofstafeln.v2+json
X-Correlation-ID: 0564dcdf-edbf-4412-a147-7299f6481470_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: d7e7526d-1d69-41d1-bf48-9c2ed5f4a302
Content-Type: application/x.db.vendo.mob.bahnhofstafeln.v2+json
Content-Length: 378
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"anfragezeit":"21:28","datum":"2024-12-16","ursprungsBahnhofId":"A\u003d1@O\u003dBerlin Hbf@X\u003d13369549@Y\u003d52525589@U\u003d81@L\u003d8098160@i\u003dU×008031922@","verkehrsmittel":["HOCHGESCHWINDIGKEITSZUEGE","INTERCITYUNDEUROCITYZUEGE","INTERREGIOUNDSCHNELLZUEGE","NAHVERKEHRSONSTIGEZUEGE","SBAHNEN","BUSSE","SCHIFFE","UBAHN","STRASSENBAHN","ANRUFPFLICHTIGEVERKEHRE"]}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,17 @@
POST /mob/location/search HTTP/1.1
Accept: application/x.db.vendo.mob.location.v3+json
X-Correlation-ID: 0564dcdf-edbf-4412-a147-7299f6481470_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: 91946e30-da87-4813-9a13-48dce2cd2cdd
Content-Type: application/x.db.vendo.mob.location.v3+json
Content-Length: 44
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"locationTypes":["ST"],"searchTerm":"test"}

View file

@ -0,0 +1,17 @@
HTTP/1.1 200 OK
Date: Mon, 16 Dec 2024 18:39:38 GMT
Content-Type: application/x.db.vendo.mob.location.v3+json
Content-Length: 2994
Connection: keep-alive
server-timing: intid;desc=6e7cf7863b2dbf7b
Server-Timing: intid;desc=6e7cf7863b2dbf7b
Server-Timing: intid;desc=6e7cf7863b2dbf7b
x-correlation-id: 0564dcdf-edbf-4412-a147-7299f6481470_64466773-556f-4aa8-b128-0948c4d60887
Strict-Transport-Security: max-age=16070400; includeSubDomains
X-XSS-Protection: 0
server-timing: intid;desc=6e7cf7863b2dbf7b
Content-Security-Policy: frame-ancestors 'none';
X-Content-Type-Options: nosniff
Set-Cookie: TS01be2125=01d513bcd109bdf5d864ee9ff6d510d0c0e6688e510fd271d9dba08fe92a99ec7d68b43cb8eddd472ec4074727d7ed3137ea220214; Path=/; Domain=.app.vendo.noncd.db.de; Secure; HTTPOnly
[{"name":"Tessin West","stationId":"7983","locationId":"A=1@O=Tessin West@X=12442572@Y=54034438@U=81@L=8079604@B=1@p=1734031727@i=U×008030295@","evaNr":"8079604","coordinates":{"latitude":54.0344,"longitude":12.442203},"weight":1489,"products":["NAHVERKEHRSONSTIGEZUEGE","BUSSE","ANRUFPFLICHTIGEVERKEHRE"],"locationType":"ST"},{"name":"Testa Grigia","locationId":"A=1@O=Testa Grigia@X=7707540@Y=45934474@U=81@L=8511303@B=1@p=1734031727@i=U×008511303@","evaNr":"8511303","coordinates":{"latitude":45.934475,"longitude":7.70754},"weight":3825,"products":["NAHVERKEHRSONSTIGEZUEGE"],"locationType":"ST"},{"name":"Teschenhagen","stationId":"6172","locationId":"A=1@O=Teschenhagen@X=13374232@Y=54389368@U=81@L=8013104@B=1@p=1734031727@i=U×008028497@","evaNr":"8013104","coordinates":{"latitude":54.38936,"longitude":13.374196},"weight":3825,"products":["NAHVERKEHRSONSTIGEZUEGE"],"locationType":"ST"},{"name":"Testelt","locationId":"A=1@O=Testelt@X=4946863@Y=51009783@U=81@L=8800244@B=1@p=1734031727@i=U×008833266@","evaNr":"8800244","coordinates":{"latitude":51.009785,"longitude":4.946863},"weight":2627,"products":["INTERCITYUNDEUROCITYZUEGE","NAHVERKEHRSONSTIGEZUEGE"],"locationType":"ST"},{"name":"Tessin","stationId":"6174","locationId":"A=1@O=Tessin@X=12462618@Y=54032020@U=81@L=8013106@B=1@p=1734031727@i=U×008027109@","evaNr":"8013106","coordinates":{"latitude":54.032,"longitude":12.461656},"weight":2402,"products":["NAHVERKEHRSONSTIGEZUEGE","BUSSE"],"locationType":"ST"},{"name":"Chemnitz Zentralhaltestelle","locationId":"A=1@O=Chemnitz Zentralhaltestelle@X=12922263@Y=50831626@U=81@L=8017419@B=1@p=1734031727@i=U×008042918@","evaNr":"8017419","coordinates":{"latitude":50.831627,"longitude":12.922263},"weight":5813,"products":["NAHVERKEHRSONSTIGEZUEGE","BUSSE","STRASSENBAHN","ANRUFPFLICHTIGEVERKEHRE"],"locationType":"ST"},{"name":"Teschow","stationId":"6173","locationId":"A=1@O=Teschow@X=11637956@Y=53994355@U=81@L=8013105@B=1@p=1734031727@i=U×008027118@","evaNr":"8013105","coordinates":{"latitude":53.994175,"longitude":11.637687},"weight":1524,"products":["NAHVERKEHRSONSTIGEZUEGE","BUSSE"],"locationType":"ST"},{"name":"Tesperhude Hudehof, Geesthacht","locationId":"A=1@O=Tesperhude Hudehof, Geesthacht@X=10431253@Y=53404393@U=81@L=694334@B=1@p=1734031727@","evaNr":"694334","coordinates":{"latitude":53.404392,"longitude":10.431253},"weight":912,"products":["BUSSE"],"locationType":"ST"},{"name":"Tesperhude Strandweg, Geesthacht","locationId":"A=1@O=Tesperhude Strandweg, Geesthacht@X=10427424@Y=53402316@U=81@L=694333@B=1@p=1734031727@","evaNr":"694333","coordinates":{"latitude":53.402317,"longitude":10.427424},"weight":912,"products":["BUSSE"],"locationType":"ST"},{"name":"Testorf Umspannwerk, Wangels","locationId":"A=1@O=Testorf Umspannwerk, Wangels@X=10778516@Y=54250161@U=81@L=700240@B=1@p=1734031727@","evaNr":"700240","coordinates":{"latitude":54.25016,"longitude":10.778516},"weight":220,"products":["BUSSE","ANRUFPFLICHTIGEVERKEHRE"],"locationType":"ST"}]

View file

@ -0,0 +1,18 @@
POST /mob/angebote/fahrplan HTTP/1.1
Accept: application/x.db.vendo.mob.verbindungssuche.v8+json
x-feature-reiseketten-enabled: false
X-Correlation-ID: 67b8a500-1983-49f5-a4ff-177d58b395ed_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: be862f65-99be-46af-a622-8bc332dc70df
Content-Type: application/x.db.vendo.mob.verbindungssuche.v8+json
Content-Length: 1122
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"autonomeReservierung":false,"einstiegsTypList":["STANDARD"],"klasse":"KLASSE_2","reiseHin":{"wunsch":{"abgangsLocationId":"A\u003d1@O\u003dBerlin Hbf@X\u003d13369549@Y\u003d52525589@U\u003d81@L\u003d8011160@B\u003d1@p\u003d1734031727@i\u003dU×008065969@","economic":true,"minUmstiegsdauer":20,"verkehrsmittel":["NAHVERKEHRSONSTIGEZUEGE","SBAHNEN","BUSSE","SCHIFFE","UBAHN","STRASSENBAHN","ANRUFPFLICHTIGEVERKEHRE"],"viaLocations":[{"locationId":"A\u003d1@O\u003dHannover Hbf@X\u003d9741017@Y\u003d52376764@U\u003d81@L\u003d8000152@B\u003d1@p\u003d1734031727@i\u003dU×008013552@","minUmstiegsdauer":60,"verkehrsmittel":["NAHVERKEHRSONSTIGEZUEGE","SBAHNEN","BUSSE","SCHIFFE","UBAHN","STRASSENBAHN","ANRUFPFLICHTIGEVERKEHRE"]}],"zeitWunsch":{"reiseDatum":"2024-12-16T19:28:48.659+01:00","zeitPunktArt":"ABFAHRT"},"zielLocationId":"A\u003d1@O\u003dKöln Hbf@X\u003d6958730@Y\u003d50943029@U\u003d81@L\u003d8000207@B\u003d1@p\u003d1734031727@i\u003dU×008015458@"}},"reisendenProfil":{"reisende":[{"ermaessigungen":["KEINE_ERMAESSIGUNG KLASSENLOS"],"reisendenTyp":"ERWACHSENER"}]},"reservierungsKontingenteVorhanden":false}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,18 @@
POST /mob/angebote/fahrplan HTTP/1.1
Accept: application/x.db.vendo.mob.verbindungssuche.v8+json
x-feature-reiseketten-enabled: false
X-Correlation-ID: b8d93b08-71ac-4cc2-836e-cd2683e34478_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: c752e01a-e03e-42a5-bcd3-26b1cc2574b3
Content-Type: application/x.db.vendo.mob.verbindungssuche.v8+json
Content-Length: 783
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"autonomeReservierung":false,"einstiegsTypList":["STANDARD"],"klasse":"KLASSE_2","reiseHin":{"wunsch":{"abgangsLocationId":"A\u003d1@O\u003dKöln Hbf@X\u003d6958730@Y\u003d50943029@U\u003d81@L\u003d8000207@B\u003d1@p\u003d1734031727@i\u003dU×008015458@","minUmstiegsdauer":20,"verkehrsmittel":["NAHVERKEHRSONSTIGEZUEGE","SBAHNEN","BUSSE","SCHIFFE","UBAHN","STRASSENBAHN","ANRUFPFLICHTIGEVERKEHRE"],"zeitWunsch":{"reiseDatum":"2024-12-16T19:45:47.459239+01:00","zeitPunktArt":"ABFAHRT"},"zielLocationId":"A\u003d1@O\u003dBerlin Hbf@X\u003d13369549@Y\u003d52525589@U\u003d81@L\u003d8011160@B\u003d1@p\u003d1734031727@i\u003dU×008065969@"}},"reisendenProfil":{"reisende":[{"ermaessigungen":["BAHNCARD25 KLASSE_2"],"reisendenTyp":"SENIOR"}]},"reservierungsKontingenteVorhanden":false}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,15 @@
GET /mob/zuglauf/2%7C%23VN%231%23ST%231734031727%23PI%231%23ZI%23178229%23TA%230%23DA%23161224%231S%238000207%231T%231926%23LS%238098160%23LT%2310012%23PU%2381%23RT%231%23CA%23ICE%23ZE%23947%23ZB%23ICE%20%20947%23PC%230%23FR%238000207%23FT%231926%23TO%238098160%23TT%2310012%23 HTTP/1.1
Accept: application/x.db.vendo.mob.zuglauf.v2+json
Content-Type: application/x.db.vendo.mob.zuglauf.v2+json
X-Correlation-ID: b8d93b08-71ac-4cc2-836e-cd2683e34478_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: 57c6969b-e937-4591-accf-0850e7b72278
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,15 @@
GET /mob/zuglaeufe/ICE_947/halte/by-abfahrt/8000207_2024-12-16T19:26:00+01:00/wagenreihung HTTP/1.1
Accept: application/x.db.vendo.mob.wagenreihung.v3+json
Content-Type: application/x.db.vendo.mob.wagenreihung.v3+json
X-Correlation-ID: b8d93b08-71ac-4cc2-836e-cd2683e34478_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: 4ce19a5d-9da2-480d-a278-543fade2f485
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0

View file

@ -0,0 +1,15 @@
GET /mob/zuglaeufe/ICE_947/halte/by-abfahrt/8000207_2024-12-16T19:26:00+01:00/wagenreihung HTTP/1.1
Accept: application/x.db.vendo.mob.wagenreihung.v3+json
Content-Type: application/x.db.vendo.mob.wagenreihung.v3+json
X-Correlation-ID: b8d93b08-71ac-4cc2-836e-cd2683e34478_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: 4ce19a5d-9da2-480d-a278-543fade2f485
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0

View file

@ -0,0 +1,17 @@
HTTP/1.1 200 OK
Date: Mon, 16 Dec 2024 18:48:06 GMT
Content-Type: application/x.db.vendo.mob.wagenreihung.v3+json
Content-Length: 4538
Connection: keep-alive
server-timing: intid;desc=8f64b8dc41cc78fe
Server-Timing: intid;desc=8f64b8dc41cc78fe
Server-Timing: intid;desc=8f64b8dc41cc78fe
x-correlation-id: b8d93b08-71ac-4cc2-836e-cd2683e34478_64466773-556f-4aa8-b128-0948c4d60887
Strict-Transport-Security: max-age=16070400; includeSubDomains
X-XSS-Protection: 0
server-timing: intid;desc=8f64b8dc41cc78fe
Content-Security-Policy: frame-ancestors 'none';
X-Content-Type-Options: nosniff
Set-Cookie: TS01be2125=01d513bcd1b784b8e477d277c1a5b018395e42eab8d1fee3cb97bf2b9ec80a7dd3763f495c187c41e167ab4fcf87709c96c07cb192; Path=/; Domain=.app.vendo.noncd.db.de; Secure; HTTPOnly
{"status":"MATCHES_SCHEDULE","gleis":{"start":{"position":0},"ende":{"position":487},"sektoren":[{"bezeichnung":"G","start":{"position":0},"ende":{"position":96.75},"gleisabschnittswuerfelPosition":58,"ersteKlasse":false},{"bezeichnung":"F","start":{"position":96.75},"ende":{"position":161.75},"gleisabschnittswuerfelPosition":135.5,"ersteKlasse":false},{"bezeichnung":"E","start":{"position":161.75},"ende":{"position":216.4},"gleisabschnittswuerfelPosition":188,"ersteKlasse":false},{"bezeichnung":"D","start":{"position":216.4},"ende":{"position":275.525},"gleisabschnittswuerfelPosition":244.8,"ersteKlasse":false},{"bezeichnung":"C","start":{"position":275.525},"ende":{"position":327.4},"gleisabschnittswuerfelPosition":306.25,"ersteKlasse":false},{"bezeichnung":"B","start":{"position":327.4},"ende":{"position":371.5},"gleisabschnittswuerfelPosition":348.55,"ersteKlasse":false},{"bezeichnung":"A","start":{"position":371.5},"ende":{"position":487},"gleisabschnittswuerfelPosition":394.45,"ersteKlasse":true}],"bezeichnung":"5"},"fahrzeuggruppen":[{"fahrzeuge":[{"fahrzeugtyp":{"fahrzeugkategorie":"POWERCAR","baureihe":"I4020","ersteKlasse":false,"zweiteKlasse":false},"status":"OPEN","orientierung":"FORWARDS","positionAmGleis":{"start":{"position":427.44},"ende":{"position":448},"sektor":"A"},"ausstattungsmerkmale":[]},{"fahrzeugtyp":{"fahrzeugkategorie":"PASSENGERCARRIAGE_FIRST_CLASS","baureihe":"Apmz","ersteKlasse":true,"zweiteKlasse":false},"status":"OPEN","orientierung":"BACKWARDS","positionAmGleis":{"start":{"position":401.04},"ende":{"position":427.44},"sektor":"A"},"ausstattungsmerkmale":[{"art":"SEATS_SEVERELY_DISABLED","status":"UNDEFINED"},{"art":"AIR_CONDITION","status":"UNDEFINED"},{"art":"ZONE_QUIET","status":"UNDEFINED"}],"ordnungsnummer":27},{"fahrzeugtyp":{"fahrzeugkategorie":"PASSENGERCARRIAGE_FIRST_CLASS","baureihe":"Apmz","ersteKlasse":true,"zweiteKlasse":false},"status":"OPEN","orientierung":"FORWARDS","positionAmGleis":{"start":{"position":374.64},"ende":{"position":401.04},"sektor":"A"},"ausstattungsmerkmale":[{"art":"SEATS_BAHN_COMFORT","status":"UNDEFINED"},{"art":"AIR_CONDITION","status":"UNDEFINED"}],"ordnungsnummer":26},{"fahrzeugtyp":{"fahrzeugkategorie":"DININGCAR","baureihe":"WRmbsz","ersteKlasse":false,"zweiteKlasse":false},"status":"OPEN","orientierung":"BACKWARDS","positionAmGleis":{"start":{"position":348.24},"ende":{"position":374.64},"sektor":"B"},"ausstattungsmerkmale":[{"art":"INFO","status":"UNDEFINED"},{"art":"TOILET_WHEELCHAIR","status":"UNDEFINED"},{"art":"WHEELCHAIR_SPACE","status":"AVAILABLE"}],"ordnungsnummer":25},{"fahrzeugtyp":{"fahrzeugkategorie":"PASSENGERCARRIAGE_ECONOMY_CLASS","baureihe":"Bpmbz","ersteKlasse":false,"zweiteKlasse":true},"status":"OPEN","orientierung":"BACKWARDS","positionAmGleis":{"start":{"position":321.84},"ende":{"position":348.24},"sektor":"B"},"ausstattungsmerkmale":[{"art":"SEATS_SEVERELY_DISABLED","status":"UNDEFINED"},{"art":"ZONE_FAMILY","status":"UNDEFINED"},{"art":"CABIN_INFANT","status":"UNDEFINED"},{"art":"AIR_CONDITION","status":"UNDEFINED"},{"art":"TOILET_WHEELCHAIR","status":"UNDEFINED"},{"art":"WHEELCHAIR_SPACE","status":"AVAILABLE"}],"ordnungsnummer":24},{"fahrzeugtyp":{"fahrzeugkategorie":"PASSENGERCARRIAGE_ECONOMY_CLASS","baureihe":"Bpmz","ersteKlasse":false,"zweiteKlasse":true},"status":"OPEN","orientierung":"BACKWARDS","positionAmGleis":{"start":{"position":295.44},"ende":{"position":321.84},"sektor":"C"},"ausstattungsmerkmale":[{"art":"SEATS_BAHN_COMFORT","status":"UNDEFINED"},{"art":"AIR_CONDITION","status":"UNDEFINED"}],"ordnungsnummer":23},{"fahrzeugtyp":{"fahrzeugkategorie":"PASSENGERCARRIAGE_ECONOMY_CLASS","baureihe":"Bpmz","ersteKlasse":false,"zweiteKlasse":true},"status":"OPEN","orientierung":"BACKWARDS","positionAmGleis":{"start":{"position":269.04},"ende":{"position":295.44},"sektor":"C"},"ausstattungsmerkmale":[{"art":"AIR_CONDITION","status":"UNDEFINED"},{"art":"ZONE_QUIET","status":"UNDEFINED"}],"ordnungsnummer":22},{"fahrzeugtyp":{"fahrzeugkategorie":"CONTROLCAR_ECONOMY_CLASS","baureihe":"Bpmzf","ersteKlasse":false,"zweiteKlasse":true},"status":"OPEN","orientierung":"FORWARDS","positionAmGleis":{"start":{"position":242.64},"ende":{"position":269.04},"sektor":"D"},"ausstattungsmerkmale":[{"art":"AIR_CONDITION","status":"UNDEFINED"}],"ordnungsnummer":21}],"fahrtreferenz":{"typ":"HIGH_SPEED_TRAIN","linie":"","ziel":{"bezeichnung":"Berlin Hbf"},"gattung":"ICE","fahrtnummer":947},"bezeichnung":"ICE0225"}],"fahrtrichtung":"RECHTS","gleisSoll":"4","gleisVorschau":"5"}

View file

@ -0,0 +1,17 @@
POST /mob/angebote/recon/autonomereservierung HTTP/1.1
Accept: application/x.db.vendo.mob.verbindungssuche.v8+json
X-Correlation-ID: b8d93b08-71ac-4cc2-836e-cd2683e34478_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: c88c72b9-3515-4acf-b052-3e71578c9461
Content-Type: application/x.db.vendo.mob.verbindungssuche.v8+json
Content-Length: 2276
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"einstiegsTypList":["STANDARD"],"klasse":"KLASSE_2","reisendenProfil":{"reisende":[{"ermaessigungen":["BAHNCARD25 KLASSE_2"],"reisendenTyp":"SENIOR"}]},"reservierungsKontingenteVorhanden":false,"verbindungHin":{"kontext":"¶HKI¶T$A\u003d1@O\u003dKöln Hbf@X\u003d6958730@Y\u003d50943029@L\u003d8000207@a\u003d128@$A\u003d1@O\u003dFrankfurt(Main)Hbf@X\u003d8663785@Y\u003d50107149@L\u003d8000105@a\u003d128@$202412162342$202412170220$IC 60403$$1$$$$$$§T$A\u003d1@O\u003dFrankfurt(Main)Hbf@X\u003d8663785@Y\u003d50107149@L\u003d8000105@a\u003d128@$A\u003d1@O\u003dErfurt Hbf@X\u003d11037989@Y\u003d50972352@L\u003d8010101@a\u003d128@$202412170249$202412170518$ICE 698$$1$$$$$$§T$A\u003d1@O\u003dErfurt Hbf@X\u003d11037989@Y\u003d50972352@L\u003d8010101@a\u003d128@$A\u003d1@O\u003dBerlin Hbf@X\u003d13369549@Y\u003d52525589@L\u003d8098160@a\u003d128@$202412170527$202412170729$ICE 1606$$1$$$$$$¶KC¶#VE#2#CF#100#CA#0#CM#0#SICT#0#AM#81#AM2#0#RT#7#¶KCC¶I1ZFIzEjRVJHIzQ1MzE1I0hJTiMwI0VDSyM1Mzk5OTV8NTM5OTgyfDU0MDQ0OXw1NDA0NDl8MHwwfDU2NXw1Mzk5NTN8M3wwfDh8MHwwfC0yMTQ3NDgzNjQ4I0dBTSMxNjEyMjQyMzQyIwpaI1ZOIzEjU1QjMTczNDAzMTcyNyNQSSMxI1pJIzE3MzU2MyNUQSMwI0RBIzE2MTIyNCMxUyM4NDAwMDU4IzFUIzIwMTUjTFMjODUwMzAwMCNMVCMxMDgwNSNQVSM4MSNSVCMxI0NBI0lDI1pFIzYwNDAzI1pCI0lDIDYwNDAzI1BDIzEjRlIjODAwMDIwNyNGVCMyMzQyI1RPIzgwMDAxMDUjVFQjMTAyMjAjClojVk4jMSNTVCMxNzM0MDMxNzI3I1BJIzEjWkkjMTc3MTQ3I1RBIzAjREEjMTYxMjI0IzFTIzgwMDAyNjEjMVQjMjE1MSNMUyM4MDk4MTYwI0xUIzEwNzU1I1BVIzgxI1JUIzEjQ0EjSUNFI1pFIzY5OCNaQiNJQ0UgIDY5OCNQQyMwI0ZSIzgwMDAxMDUjRlQjMTAyNDkjVE8jODAxMDEwMSNUVCMxMDUxOCMKWiNWTiMxI1NUIzE3MzQwMzE3MjcjUEkjMSNaSSMxNzQ1MzgjVEEjMCNEQSMxNzEyMjQjMVMjODAxMDEwMSMxVCM1MjcjTFMjODAwMjU1MyNMVCM5MzkjUFUjODEjUlQjMSNDQSNJQ0UjWkUjMTYwNiNaQiNJQ0UgMTYwNiNQQyMwI0ZSIzgwMTAxMDEjRlQjNTI3I1RPIzgwOTgxNjAjVFQjNzI5Iw\u003d\u003d¶KRCC¶#VE#1#¶SC¶1_H4sIAAAAAAACA32P7UrDMBiFb0Xyu443adM2hUDsyvBjaBEnivijrtms9GOm6bCUXod34g3sxkxbBoIi+ZNz3pPzvOnQXioUIDzzfGQh+aGNiMLZfTRjRiv5joIOlU2xQAG1hkuIArBQ1ego0dKECRAHE+yi0bzLisHEzKEAxtqMDafYQm9lu8i1WqLgqUO63Q2x+PYmMqGiSgd1cT03Yp/kzVgBxEb987jT/HU7FRtyKnfLaj3V5Flqkmccixt+dfjKy5Pzl4144C6jvmeDeOQUmGMDYWLFfSyW3AcAAp4IzZsdx57tgI094omMrw6fAD5g6lBfmEVqPX1wMW6RKPUnNpQqz45cbNsG7bABTMyh/g8wxtiFf8AuZS77Dd5KHVd5ayDG06qRo3VZNaqUbVg1ZVqjYJPk9TSIk7rOs1ofs3JdxYlKChPq+r7/Bvf6c1bwAQAA"}}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,17 @@
POST /mob/bahnhofstafel/abfahrt HTTP/1.1
Accept: application/x.db.vendo.mob.bahnhofstafeln.v2+json
X-Correlation-ID: b8d93b08-71ac-4cc2-836e-cd2683e34478_64466773-556f-4aa8-b128-0948c4d60887
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: 2b250673-6250-4bcd-8dc3-8cf83c0a7686
Content-Type: application/x.db.vendo.mob.bahnhofstafeln.v2+json
Content-Length: 376
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"anfragezeit":"20:35","datum":"2024-12-16","ursprungsBahnhofId":"A\u003d1@O\u003dKöln Hbf@X\u003d6958730@Y\u003d50943029@U\u003d81@L\u003d8000207@i\u003dU×008015458@","verkehrsmittel":["HOCHGESCHWINDIGKEITSZUEGE","INTERCITYUNDEUROCITYZUEGE","INTERREGIOUNDSCHNELLZUEGE","NAHVERKEHRSONSTIGEZUEGE","SBAHNEN","BUSSE","SCHIFFE","UBAHN","STRASSENBAHN","ANRUFPFLICHTIGEVERKEHRE"]}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,17 @@
HTTP/1.1 200 OK
Date: Wed, 18 Dec 2024 21:38:58 GMT
Content-Type: application/x.db.vendo.mob.bahnhofstafeln.v2+json
Content-Length: 590
Connection: keep-alive
server-timing: intid;desc=bf069d97495f8dad
Server-Timing: intid;desc=bf069d97495f8dad
Server-Timing: intid;desc=bf069d97495f8dad
x-correlation-id: faddeefb-53f2-41a9-9879-e1c4edd7845f_5a24d491-8e2e-4cd8-85b5-ddd1d7d322c8
Strict-Transport-Security: max-age=16070400; includeSubDomains
X-XSS-Protection: 0
server-timing: intid;desc=bf069d97495f8dad
Content-Security-Policy: frame-ancestors 'none';
X-Content-Type-Options: nosniff
Set-Cookie: TS01be2125=01d513bcd1e76575d2a4e5c74d05675d588d2a35d6e7b8b0e5cad991641ebd4a05f4c1b051774f52d1a60eac0d3365250488a0be85; Path=/; Domain=.app.vendo.noncd.db.de; Secure; HTTPOnly
{"bahnhofstafelAbfahrtPositionen":[{"zuglaufId":"2|#VN#1#ST#1734378327#PI#1#ZI#514236#TA#0#DA#181224#1S#541958#1T#1944#LS#548569#LT#2108#PU#81#RT#1#CA#rfb#ZE#8175#ZB#RUF 8175#PC#9#FR#541958#FT#1944#TO#548569#TT#2108#","kurztext":"RUF","mitteltext":"RUF 8175","abfrageOrt":{"name":"Penzing Ortsmitte, Aidenbach","locationId":"A=1@O=Penzing Ortsmitte, Aidenbach@X=13063430@Y=48562182@U=81@L=548572@","evaNr":"548572"},"richtung":"Köching Abzw. Haidenburg Wartehäuschen, Aidenbach","echtzeitNotizen":[],"abgangsDatum":"2024-12-18T21:03:00+01:00","produktGattung":"ANRUFPFLICHTIGEVERKEHRE"}]}

View file

@ -0,0 +1,17 @@
HTTP/1.1 200 OK
Date: Wed, 18 Dec 2024 21:42:04 GMT
Content-Type: application/x.db.vendo.mob.bahnhofstafeln.v2+json
Content-Length: 2498
Connection: keep-alive
server-timing: intid;desc=4e6f4ce0b26b14cb
Server-Timing: intid;desc=4e6f4ce0b26b14cb
Server-Timing: intid;desc=4e6f4ce0b26b14cb
x-correlation-id: faddeefb-53f2-41a9-9879-e1c4edd7845f_5a24d491-8e2e-4cd8-85b5-ddd1d7d322c8
Strict-Transport-Security: max-age=16070400; includeSubDomains
X-XSS-Protection: 0
server-timing: intid;desc=4e6f4ce0b26b14cb
Content-Security-Policy: frame-ancestors 'none';
X-Content-Type-Options: nosniff
Set-Cookie: TS01be2125=01d513bcd1b5c4411e233c8956b40fa37e9050070c341e1782b80282d570eb1ed0cb63a2fab4db66435d0bad351471a04f949cac0d; Path=/; Domain=.app.vendo.noncd.db.de; Secure; HTTPOnly
{"bahnhofstafelAbfahrtPositionen":[{"zuglaufId":"2|#VN#1#ST#1734378327#PI#1#ZI#989203#TA#17#DA#181224#1S#368702#1T#930#LS#936350#LT#935#PU#81#RT#1#CA#FAE#ZE#FÄ1#ZB#Fähre #PC#6#FR#368702#FT#930#TO#936350#TT#935#","kurztext":"Fähre","mitteltext":"Fähre","abfrageOrt":{"name":"Hohe Düne Fähre, Rostock","locationId":"A=1@O=Hohe Düne Fähre, Rostock@X=12097404@Y=54176710@U=81@L=368702@","evaNr":"368702"},"richtung":"Warnemünde","echtzeitNotizen":[],"abgangsDatum":"2024-12-18T09:30:00+01:00","produktGattung":"SCHIFF"},{"zuglaufId":"2|#VN#1#ST#1734378327#PI#1#ZI#417851#TA#1#DA#181224#1S#936250#1T#947#LS#939255#LT#1021#PU#81#RT#1#CA#Bus#ZE#18#ZB#Bus 18#PC#5#FR#936250#FT#947#TO#939255#TT#1021#","kurztext":"Bus","mitteltext":"Bus 18","abfrageOrt":{"name":"Hohe Düne Fähre, Rostock","locationId":"A=1@O=Hohe Düne Fähre, Rostock@X=12098627@Y=54176485@U=81@L=936250@","evaNr":"936250"},"richtung":"Dierkower Kreuz","echtzeitNotizen":[],"abgangsDatum":"2024-12-18T09:47:00+01:00","produktGattung":"BUS"},{"zuglaufId":"2|#VN#1#ST#1734378327#PI#1#ZI#989203#TA#18#DA#181224#1S#368702#1T#950#LS#936350#LT#955#PU#81#RT#1#CA#FAE#ZE#FÄ1#ZB#Fähre #PC#6#FR#368702#FT#950#TO#936350#TT#955#","kurztext":"Fähre","mitteltext":"Fähre","abfrageOrt":{"name":"Hohe Düne Fähre, Rostock","locationId":"A=1@O=Hohe Düne Fähre, Rostock@X=12097404@Y=54176710@U=81@L=368702@","evaNr":"368702"},"richtung":"Warnemünde","echtzeitNotizen":[],"abgangsDatum":"2024-12-18T09:50:00+01:00","produktGattung":"SCHIFF"},{"zuglaufId":"2|#VN#1#ST#1734378327#PI#1#ZI#420342#TA#0#DA#181224#1S#936250#1T#1007#LS#842059#LT#1018#PU#81#RT#1#CA#Bus#ZE#17#ZB#Bus 17#PC#5#FR#936250#FT#1007#TO#842059#TT#1018#","kurztext":"Bus","mitteltext":"Bus 17","abfrageOrt":{"name":"Hohe Düne Fähre, Rostock","locationId":"A=1@O=Hohe Düne Fähre, Rostock@X=12098627@Y=54176485@U=81@L=936250@","evaNr":"936250"},"richtung":"Markgrafenheide Ost","echtzeitNotizen":[],"abgangsDatum":"2024-12-18T10:07:00+01:00","produktGattung":"BUS"},{"zuglaufId":"2|#VN#1#ST#1734378327#PI#1#ZI#989203#TA#19#DA#181224#1S#368702#1T#1010#LS#936350#LT#1015#PU#81#RT#1#CA#FAE#ZE#FÄ1#ZB#Fähre #PC#6#FR#368702#FT#1010#TO#936350#TT#1015#","kurztext":"Fähre","mitteltext":"Fähre","abfrageOrt":{"name":"Hohe Düne Fähre, Rostock","locationId":"A=1@O=Hohe Düne Fähre, Rostock@X=12097404@Y=54176710@U=81@L=368702@","evaNr":"368702"},"richtung":"Warnemünde","echtzeitNotizen":[],"abgangsDatum":"2024-12-18T10:10:00+01:00","produktGattung":"SCHIFF"}]}

View file

@ -0,0 +1,17 @@
HTTP/1.1 200 OK
Date: Wed, 18 Dec 2024 21:43:02 GMT
Content-Type: application/x.db.vendo.mob.bahnhofstafeln.v2+json
Content-Length: 1030
Connection: keep-alive
server-timing: intid;desc=3007cc29ce998300
Server-Timing: intid;desc=3007cc29ce998300
Server-Timing: intid;desc=3007cc29ce998300
x-correlation-id: faddeefb-53f2-41a9-9879-e1c4edd7845f_5a24d491-8e2e-4cd8-85b5-ddd1d7d322c8
Strict-Transport-Security: max-age=16070400; includeSubDomains
X-XSS-Protection: 0
server-timing: intid;desc=3007cc29ce998300
Content-Security-Policy: frame-ancestors 'none';
X-Content-Type-Options: nosniff
Set-Cookie: TS01be2125=01d513bcd1778d8a6954cb4376d998b52e8b4b9edfa2de0eed859c823593d6a880ffc23b5ab8f107642d7ccfb36b5be2d8c9d6632f; Path=/; Domain=.app.vendo.noncd.db.de; Secure; HTTPOnly
{"bahnhofstafelAbfahrtPositionen":[{"gleis":"2","zuglaufId":"2|#VN#1#ST#1734378327#PI#1#ZI#338816#TA#0#DA#181224#1S#8000096#1T#712#LS#8100003#LT#1352#PU#81#RT#1#CA#DPF#ZE#963#ZB#WB 963#PC#2#FR#8000096#FT#712#TO#8100003#TT#1352#","kurztext":"WB","mitteltext":"WB 963","abfrageOrt":{"name":"Stuttgart Hbf","locationId":"A=1@O=Stuttgart Hbf@X=9181636@Y=48784081@U=81@L=8000096@i=U×008029034@","evaNr":"8000096","stationId":"6071"},"echtzeitNotizen":[],"abgangsDatum":"2024-12-18T07:12:00+01:00","produktGattung":"IR"},{"gleis":"8","zuglaufId":"2|#VN#1#ST#1734378327#PI#1#ZI#203510#TA#0#DA#181224#1S#8000096#1T#717#LS#8098160#LT#1315#PU#81#RT#1#CA#DPF#ZE#1240#ZB#FLX 1240#PC#2#FR#8000096#FT#717#TO#8098160#TT#1315#","kurztext":"FLX","mitteltext":"FLX 1240","abfrageOrt":{"name":"Stuttgart Hbf","locationId":"A=1@O=Stuttgart Hbf@X=9181636@Y=48784081@U=81@L=8000096@i=U×008029034@","evaNr":"8000096","stationId":"6071"},"richtung":"Berlin Hbf","echtzeitNotizen":[],"abgangsDatum":"2024-12-18T07:17:00+01:00","produktGattung":"IR"}]}

View file

@ -0,0 +1,17 @@
POST /mob/location/search HTTP/1.1
Accept: application/x.db.vendo.mob.location.v3+json
X-Correlation-ID: 0079a47f-6208-4507-9d9a-0e02802ef52c_5a24d491-8e2e-4cd8-85b5-ddd1d7d322c8
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: 205f5fd7-f96a-4e07-a47d-bb3edb8c443e
Content-Type: application/x.db.vendo.mob.location.v3+json
Content-Length: 52
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"locationTypes":["ALL"],"searchTerm":"schillerstr"}

View file

@ -0,0 +1,17 @@
HTTP/1.1 200 OK
Date: Wed, 18 Dec 2024 22:19:20 GMT
Content-Type: application/x.db.vendo.mob.location.v3+json
Content-Length: 2877
Connection: keep-alive
server-timing: intid;desc=8a52db25dd785bfe
Server-Timing: intid;desc=8a52db25dd785bfe
Server-Timing: intid;desc=8a52db25dd785bfe
x-correlation-id: 0079a47f-6208-4507-9d9a-0e02802ef52c_5a24d491-8e2e-4cd8-85b5-ddd1d7d322c8
Strict-Transport-Security: max-age=16070400; includeSubDomains
X-XSS-Protection: 0
server-timing: intid;desc=8a52db25dd785bfe
Content-Security-Policy: frame-ancestors 'none';
X-Content-Type-Options: nosniff
Set-Cookie: TS01be2125=01d513bcd1de3bcb4b755a3859cad31611f802372756db9780547d536b115fb805b4cb7fe4f2aefad293244318a0660f18cf234872; Path=/; Domain=.app.vendo.noncd.db.de; Secure; HTTPOnly
[{"name":"Schillerstr., Ofterdingen","locationId":"A=1@O=Schillerstr., Ofterdingen@X=9030635@Y=48420917@U=81@L=750308@B=1@p=1734378327@","evaNr":"750308","coordinates":{"latitude":48.420918,"longitude":9.030635},"weight":995,"products":["BUSSE","ANRUFPFLICHTIGEVERKEHRE"],"locationType":"ST"},{"name":"Schillerstr., Lutherstadt Wittenberg","locationId":"A=1@O=Schillerstr., Lutherstadt Wittenberg@X=12660057@Y=51875984@U=81@L=963037@B=1@p=1734378327@","evaNr":"963037","coordinates":{"latitude":51.875984,"longitude":12.660057},"weight":943,"products":["BUSSE","ANRUFPFLICHTIGEVERKEHRE"],"locationType":"ST"},{"name":"Schillerstr., Geithain","locationId":"A=1@O=Schillerstr., Geithain@X=12691420@Y=51058568@U=81@L=200268@B=1@p=1734378327@","evaNr":"200268","coordinates":{"latitude":51.058567,"longitude":12.69142},"weight":941,"products":["BUSSE"],"locationType":"ST"},{"name":"Schillerstr., Zwickau","locationId":"A=1@O=Schillerstr., Zwickau@X=12493001@Y=50715018@U=81@L=983776@B=1@p=1734378327@","evaNr":"983776","coordinates":{"latitude":50.71502,"longitude":12.493001},"weight":941,"products":["NAHVERKEHRSONSTIGEZUEGE","BUSSE","STRASSENBAHN","ANRUFPFLICHTIGEVERKEHRE"],"locationType":"ST"},{"name":"Schillerstr., Überherrn","locationId":"A=1@O=Schillerstr., Überherrn@X=6705494@Y=49239322@U=81@L=835123@B=1@p=1734378327@","evaNr":"835123","coordinates":{"latitude":49.239323,"longitude":6.705494},"weight":941,"products":["BUSSE"],"locationType":"ST"},{"name":"Schillerstr./Forstweg, Brieselang","locationId":"A=1@O=Schillerstr./Forstweg, Brieselang@X=12988073@Y=52583830@U=81@L=734788@B=1@p=1734378327@","evaNr":"734788","coordinates":{"latitude":52.58383,"longitude":12.988073},"weight":941,"products":["BUSSE"],"locationType":"ST"},{"name":"Schillerstr., Berlin","locationId":"A=1@O=Schillerstr., Berlin@X=13410584@Y=52591948@U=81@L=732759@B=1@p=1734378327@","evaNr":"732759","coordinates":{"latitude":52.59195,"longitude":13.410584},"weight":412,"products":["STRASSENBAHN"],"locationType":"ST"},{"name":"Schillerstr., Schöneiche b. Berlin","locationId":"A=1@O=Schillerstr., Schöneiche b. Berlin@X=13709386@Y=52476958@U=81@L=738128@B=1@p=1734378327@","evaNr":"738128","coordinates":{"latitude":52.47696,"longitude":13.709386},"weight":412,"products":["STRASSENBAHN"],"locationType":"ST"},{"name":"Schillerstr., Markdorf","locationId":"A=1@O=Schillerstr., Markdorf@X=9386033@Y=47727336@U=81@L=801101@B=1@p=1734378327@","evaNr":"801101","coordinates":{"latitude":47.727337,"longitude":9.386033},"weight":272,"products":["BUSSE","ANRUFPFLICHTIGEVERKEHRE"],"locationType":"ST"},{"name":"Schillerstr., Salzwedel","locationId":"A=1@O=Schillerstr., Salzwedel@X=11160072@Y=52850918@U=81@L=957938@B=1@p=1734378327@","evaNr":"957938","coordinates":{"latitude":52.850918,"longitude":11.160072},"weight":272,"products":["BUSSE","ANRUFPFLICHTIGEVERKEHRE"],"locationType":"ST"}]

View file

@ -0,0 +1,18 @@
POST /mob/angebote/fahrplan HTTP/1.1
Accept: application/x.db.vendo.mob.verbindungssuche.v8+json
x-feature-reiseketten-enabled: false
X-Correlation-ID: 84f2ab9b-d4a7-4e98-9a29-113783f0d431_5a24d491-8e2e-4cd8-85b5-ddd1d7d322c8
X-Device-Os-Name: Android
X-Device-Os-Version: 32
X-Device-Model: Google Pixel 3a
X-App-Version: 24.32.2
Accept-Language: en,de
X-INSTANA-ANDROID: a33cf0fb-5fd8-4c2f-befa-d4c1963cf3b7
Content-Type: application/x.db.vendo.mob.verbindungssuche.v8+json
Content-Length: 686
Host: app.vendo.noncd.db.de
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0
{"autonomeReservierung":false,"einstiegsTypList":["STANDARD"],"klasse":"KLASSE_2","reiseHin":{"wunsch":{"abgangsLocationId":"A\u003d2@O\u003dBerlin - Bohnsdorf, Schillerstraße 10@H\u003d10@X\u003d13585128@Y\u003d52398257@U\u003d92@L\u003d980126874@B\u003d1@p\u003d1706613073@","verkehrsmittel":["ALL"],"zeitWunsch":{"reiseDatum":"2024-12-18T22:38:09.928078+01:00","zeitPunktArt":"ABFAHRT"},"zielLocationId":"A\u003d1@O\u003dBerlin Hbf@X\u003d13369549@Y\u003d52525589@U\u003d81@L\u003d8011160@B\u003d1@p\u003d1734031727@i\u003dU×008065969@"}},"reisendenProfil":{"reisende":[{"ermaessigungen":["BAHNCARD25 KLASSE_2"],"reisendenTyp":"SENIOR"}]},"reservierungsKontingenteVorhanden":false}

File diff suppressed because one or more lines are too long

15
docs/dumps/readme.md Normal file
View file

@ -0,0 +1,15 @@
# Dumps from DB Navigator API app.vendo.noncd.db.de
In this directory, some intercepted traffic from DB Navigator. (Repo license does not apply to this directory.)
You can browse some responses of the bahn.de API and others in the [fixtures](https://github.com/public-transport/db-vendo-client/tree/main/test/fixtures) and [e2e fixtures](https://github.com/public-transport/db-vendo-client/tree/main/test/e2e/fixtures).
How to intercept DB Navigator traffic:
1. Download/extract Split APK
2. Merge APK (e.g. using [APKEditor](https://github.com/REAndroid/APKEditor))
3. decompile using apktool
4. edit [res/xml/network_security_config.xml](https://developer.android.com/privacy-and-security/security-config) to allow user CAs not just in debug
5. recompile using apktool, sign
6. install on an Android
7. intercept with a mitm decryption tool of your choice by installing CA cert into Android store (e.g. [PCAPdroid](https://github.com/emanuele-f/PCAPdroid) with [mitm addon](https://github.com/emanuele-f/PCAPdroid-mitm), no root needed)

View file

@ -1,118 +0,0 @@
# `journeyLeg(ref, lineName, [opt])`
This method can be used to refetch information about a leg of a journey. Note that it is not supported by every profile/endpoint.
Let's say you used [`journeys`](journeys.md) and now want to get more up-to-date data about the arrival/departure of a leg. You'd pass in a journey leg `id` like `'1|24983|22|86|18062017'`. `lineName` must be the name of the journey leg's `line.name`. You can get them like this:
```js
const createClient = require('hafas-client')
const vbbProfile = require('hafas-client/p/vbb')
const client = createClient(vbbProfile)
// Hauptbahnhof to Heinrich-Heine-Str.
client.journeys('900000003201', '900000100008', {results: 1})
.then(([journey]) => {
const leg = journey.legs[0]
return client.journeyLeg(leg.id, leg.line.name)
})
.then(console.log)
.catch(console.error)
```
With `opt`, you can override the default options, which look like this:
```js
{
when: new Date(),
passedStations: true // return stations on the way?
}
```
## Response
*Note:* As stated in the [*Friendly Public Transport Format* `1.0.1`](https://github.com/public-transport/friendly-public-transport-format/tree/1.0.1), the returned `departure` and `arrival` times include the current delay. The `departureDelay`/`arrivalDelay` fields express how much they differ from the schedule.
As an example, we're going to use the [VBB profile](../p/vbb):
```js
const createClient = require('hafas-client')
const vbbProfile = require('hafas-client/p/vbb')
const client = createClient(vbbProfile)
client.journeyLeg('1|31431|28|86|17122017', 'S9', {when: 1513534689273})
.then(console.log)
.catch(console.error)
```
The response looked like this:
```js
{
id: '1|31431|28|86|17122017',
origin: {
type: 'station',
id: '900000260005',
name: 'S Flughafen Berlin-Schönefeld',
location: {
type: 'location',
latitude: 52.390796,
longitude: 13.51352
},
products: {
suburban: true,
subway: false,
tram: false,
bus: true,
ferry: false,
express: false,
regional: true
}
},
departure: '2017-12-17T18:37:00.000+01:00',
departurePlatform: '13',
destination: {
type: 'station',
id: '900000029101',
name: 'S Spandau',
location: {
type: 'location',
latitude: 52.534794,
longitude: 13.197477
},
products: {
suburban: true,
subway: false,
tram: false,
bus: true,
ferry: false,
express: true,
regional: true
}
},
arrival: '2017-12-17T19:49:00.000+01:00',
arrivalPlatform: '2',
line: {
type: 'line',
id: '18299',
name: 'S9',
public: true,
mode: 'train',
product: 'suburban',
symbol: 'S',
nr: 9,
metro: false,
express: false,
night: false,
productCode: 0,
operator: {
type: 'operator',
id: 's-bahn-berlin-gmbh',
name: 'S-Bahn Berlin GmbH'
}
},
direction: 'S Spandau',
passed: [ /* … */ ]
}
```

View file

@ -22,12 +22,13 @@
{
type: 'location',
id: '123',
poi: true,
name: 'foo restaurant',
latitude: 1.23,
longitude: 3.21
}
// an address, which is an FTPF `location` object
// an address, which is an FPTF `location` object
{
type: 'location',
address: 'foo street 1',
@ -40,16 +41,23 @@ With `opt`, you can override the default options, which look like this:
```js
{
when: new Date(),
// Use either `departure` or `arrival` to specify a date/time.
departure: new Date(),
arrival: null,
earlierThan: null, // ref to get journeys earlier than the last query
laterThan: null, // ref to get journeys later than the last query
results: 5, // how many journeys?
results: null, // number of journeys  `null` means "whatever HAFAS returns"
via: null, // let journeys pass this station
passedStations: false, // return stations on the way?
transfers: 5, // maximum of 5 transfers
stopovers: false, // return stations on the way?
transfers: -1, // Maximum nr of transfers. Default: Let HAFAS decide.
transferTime: 0, // minimum time for a single transfer in minutes
accessibility: 'none', // 'none', 'partial' or 'complete'
accessibility: 'none', // not supported
bike: false, // only bike-friendly journeys
walkingSpeed: 'normal', // not supported
// Consider walking to nearby stations at the beginning of a journey?
startWithWalking: true, // always true (?)
products: {
// these entries may vary from profile to profile
suburban: true,
@ -57,41 +65,82 @@ With `opt`, you can override the default options, which look like this:
tram: true,
bus: true,
ferry: true,
express: true,
nationalExpress: true,
national: true,
regional: true
regionalExpress: true // this is actually FlixTrain and co.
},
tickets: false // return tickets? only available with some profiles
tickets: false, // return tickets? only available for [refreshJourney](refresh-journey.md)
polylines: false, // return a shape for each leg? only available for [refreshJourney](refresh-journey.md)
subStops: true, // not supported
entrances: true, // not supported
remarks: true, // parse & expose hints & warnings?
scheduledDays: false, // returns a field `serviceDays` (instead of `scheduledDays` in hafas-client!) with a different, human-readable structure
notOnlyFastRoutes: false, // if true, also show journeys that are mathematically non-optimal
bestprice: false, // search for lowest prices across the entire day, returns list of journeys sorted by price
firstClass: false, // first or second class for tickets
loyaltyCard: null, // BahnCards etc., see below
language: 'en', // language to get results in
}
```
## Response
*Note:* As stated in the [*Friendly Public Transport Format* `1.0.1`](https://github.com/public-transport/friendly-public-transport-format/tree/1.0.1), the returned `departure` and `arrival` times include the current delay. The `departureDelay`/`arrivalDelay` fields express how much they differ from the schedule.
*Note:* As stated in the [*Friendly Public Transport Format* v2 draft spec](https://github.com/public-transport/friendly-public-transport-format/blob/3bd36faa721e85d9f5ca58fb0f38cdbedb87bbca/spec/readme.md), the returned `departure` and `arrival` times include the current delay. The `departureDelay`/`arrivalDelay` fields express how much they differ from the schedule.
As an example, we're going to use the [VBB profile](../p/vbb):
```js
const createClient = require('hafas-client')
const vbbProfile = require('hafas-client/p/vbb')
import {createClient} 'db-vendo-client'
import {profile as dbProfile} from 'db-vendo-client/p/db/index.js'
const client = createClient(vbbProfile)
const userAgent = 'link-to-your-project-or-email' // adapt this to your project!
const client = createClient(dbProfile, userAgent)
// Hauptbahnhof to Heinrich-Heine-Str.
client.journeys('900000003201', '900000100008', {
// Frankfurt to Stuttgart
await client.journeys('8000105', '8000096', {
results: 1,
passedStations: true
stopovers: true
})
.then(console.log)
.catch(console.error)
```
The response may look like this:
`journeys()` will resolve with an object with the following fields:
- `journeys`
- `earlierRef`/`laterRef` pass them as `opt.earlierThan`/`opt.laterThan` into another `journeys()` call to retrieve the next "page" of journeys
- `realtimeDataUpdatedAt` is currently not set in db-vendo-client, because the upstream APIs don't provide it.
This object might look like this:
```js
[
{
{
journeys: [ {
legs: [ {
id: '1|31041|35|86|17122017',
tripId: '1|32615|6|86|10072018',
direction: 'S Ahrensfelde',
line: {
type: 'line',
id: '16845',
fahrtNr: '12345',
name: 'S7',
public: true,
mode: 'train',
product: 'suburban',
operator: {
type: 'operator',
id: 's-bahn-berlin-gmbh',
name: 'S-Bahn Berlin GmbH'
},
symbol: 'S',
nr: 7,
metro: false,
express: false,
night: false
},
currentLocation: {
type: 'location',
latitude: 52.51384,
longitude: 13.526806,
},
origin: {
type: 'station',
id: '900000003201',
@ -111,169 +160,162 @@ The response may look like this:
regional: true
}
},
departure: '2017-12-17T19:07:00.000+01:00',
departurePlatform: '16',
departure: '2018-07-10T23:54:00+02:00',
plannedDeparture: '2018-07-10T23:53:00+02:00',
departureDelay: 60,
departurePlatform: '15',
plannedDeparturePlatform: '14',
destination: {
type: 'station',
id: '900000024101',
name: 'S Charlottenburg',
id: '900000100004',
name: 'S+U Jannowitzbrücke',
location: {
type: 'location',
latitude: 52.504806,
longitude: 13.303846
},
products: {
suburban: true,
subway: false,
tram: false,
bus: true,
ferry: false,
express: false,
regional: true
}
products: { /* … */ }
},
arrival: '2017-12-17T19:47:00.000+01:00',
arrivalPlatform: '8',
arrivalDelay: 30,
line: {
type: 'line',
id: '16845',
name: 'S7',
public: true,
mode: 'train',
product: 'suburban',
symbol: 'S',
nr: 7,
metro: false,
express: false,
night: false,
productCode: 0,
operator: {
type: 'operator',
id: 's-bahn-berlin-gmbh',
name: 'S-Bahn Berlin GmbH'
}
},
direction: 'S Potsdam Hauptbahnhof',
passed: [ {
station: {
arrival: '2018-07-11T00:02:00+02:00',
plannedArrival: '2018-07-11T00:01:00+02:00',
arrivalDelay: 60,
arrivalPlatform: '3',
plannedArrivalPlatform: '3',
stopovers: [ {
stop: {
type: 'station',
id: '900000003201',
name: 'S+U Berlin Hauptbahnhof',
location: { /* … */ },
products: { /* … */ }
/* … */
},
arrival: null,
plannedArrival: null,
arrivalPlatform: null,
plannedArrivalPlatform: null,
departure: null,
cancelled: true
plannedDeparture: null,
departurePlatform: null,
plannedDeparturePlatform: null,
remarks: [
{type: 'hint', code: 'bf', text: 'barrier-free'},
{type: 'hint', code: 'FB', text: 'Bicycle conveyance'}
]
}, {
station: {
stop: {
type: 'station',
id: '900000003102',
name: 'S Bellevue',
location: { /* … */ },
products: { /* … */ }
id: '900000100001',
name: 'S+U Friedrichstr.',
/* … */
},
arrival: '2017-12-17T19:09:00.000+01:00',
departure: '2017-12-17T19:09:00.000+01:00'
}, /* … */ {
station: {
cancelled: true,
arrival: null,
plannedArrival: '2018-07-10T23:55:00+02:00',
prognosedArrival: '2018-07-10T23:56:00+02:00',
arrivalDelay: 60,
arrivalPlatform: null,
plannedArrivalPlatform: null,
departure: null,
plannedDeparture: '2018-07-10T23:56:00+02:00',
prognosedDeparture: '2018-07-10T23:57:00+02:00',
departureDelay: 60,
departurePlatform: null,
plannedDeparturePlatform: null,
remarks: [ /* … */ ]
},
/* … */
{
stop: {
type: 'station',
id: '900000024101',
name: 'S Charlottenburg',
location: { /* … */ },
products: { /* … */ }
id: '900000100004',
name: 'S+U Jannowitzbrücke',
/* … */
},
arrival: '2017-12-17T19:17:00.000+01:00',
departure: '2017-12-17T19:17:00.000+01:00'
arrival: '2018-07-11T00:02:00+02:00',
plannedArrival: '2018-07-11T00:01:00+02:00',
arrivalDelay: 60,
arrivalPlatform: null,
plannedArrivalPlatform: null,
departure: '2018-07-11T00:02:00+02:00',
plannedDeparture: '2018-07-11T00:02:00+02:00',
departureDelay: null,
departurePlatform: null,
plannedDeparturePlatform: null,
remarks: [ /* … */ ]
} ]
} ],
origin: {
type: 'station',
id: '900000003201',
name: 'S+U Berlin Hauptbahnhof',
location: { /* … */ },
products: { /* … */ }
},
departure: '2017-12-17T19:07:00.000+01:00',
destination: {
type: 'station',
id: '900000024101',
name: 'S Charlottenburg',
location: { /* … */ },
products: { /* … */ }
},
arrival: '2017-12-17T19:47:00.000+01:00',
arrivalDelay: 30
},
}, {
public: true,
walking: true,
distance: 558,
origin: {
type: 'station',
id: '900000100004',
name: 'S+U Jannowitzbrücke',
location: { /* … */ },
products: { /* … */ }
},
departure: '2018-07-11T00:01:00+02:00',
destination: {
type: 'station',
id: '900000100008',
name: 'U Heinrich-Heine-Str.',
location: { /* … */ },
products: { /* … */ }
},
arrival: '2018-07-11T00:10:00+02:00'
} ]
} ],
earlierRef: '…', // use with the `earlierThan` option
laterRef: '…' // use with the `laterThan` option
]
realtimeDataUpdatedAt: 1531259400, // 2018-07-10T23:50:00+02
}
```
Some [profiles](../p) are able to parse the ticket information, if returned by the API. For example, if you pass `tickets: true` with the [VBB profile](../p/vbb), each `journey` will have a tickets array that looks like this:
```js
[ {
name: 'Berlin Tarifgebiet A-B: Einzelfahrausweis Regeltarif',
price: 2.8,
tariff: 'Berlin',
coverage: 'AB',
variant: 'adult',
amount: 1
}, {
name: 'Berlin Tarifgebiet A-B: Einzelfahrausweis Ermäßigungstarif',
price: 1.7,
tariff: 'Berlin',
coverage: 'AB',
variant: 'reduced',
amount: 1,
reduced: true
}, /* … */ {
name: 'Berlin Tarifgebiet A-B: Tageskarte Ermäßigungstarif',
price: 4.7,
tariff: 'Berlin',
coverage: 'AB',
variant: '1 day, reduced',
amount: 1,
reduced: true,
fullDay: true
}, /* … */ {
name: 'Berlin Tarifgebiet A-B: 4-Fahrten-Karte Regeltarif',
price: 9,
tariff: 'Berlin',
coverage: 'AB',
variant: '4x adult',
amount: 4
} ]
```
If a journey leg has been cancelled, a `cancelled: true` will be added. Also, `departure`/`departureDelay`/`departurePlatform` and `arrival`/`arrivalDelay`/`arrivalPlatform` will be `null`.
To get more journeys earlier/later than the current set of results, pass `journeys.earlierRef`/`journeys.laterRef` into `opt.earlierThan`/`opt.laterThan`. For example, query *later* journeys as follows:
To get more journeys earlier/later than the current set of results, pass `earlierRef`/`laterRef` into `opt.earlierThan`/`opt.laterThan`. For example, query *later* journeys as follows:
```js
const hbf = '900000003201'
const heinrichHeineStr = '900000100008'
client.journeys(hbf, heinrichHeineStr)
.then((journeys) => {
const lastJourney = journeys[journeys.length - 1]
console.log('departure of last journey', lastJourney.departure)
const res1 = await client.journeys(hbf, heinrichHeineStr)
const lastJourney = res1.journeys[res1.journeys.length - 1]
console.log('departure of last journey', lastJourney.legs[0].departure)
// get later journeys
return client.journeys(hbf, heinrichHeineStr, {
laterThan: journeys.laterRef
})
// get later journeys
const res2 = await client.journeys(hbf, heinrichHeineStr, {
laterThan: res1.laterRef
})
.then((laterourneys) => {
const firstJourney = laterourneys[laterourneys.length - 1]
console.log('departure of first (later) journey', firstJourney.departure)
})
.catch(console.error)
const firstLaterJourney = res2.journeys[res2.journeys.length - 1]
console.log('departure of first (later) journey', firstLaterJourney.legs[0].departure)
```
```
departure of last journey 2017-12-17T19:07:00.000+01:00
departure of first (later) journey 2017-12-17T19:19:00.000+01:00
departure of last journey 2017-12-17T19:07:00+01:00
departure of first (later) journey 2017-12-17T19:19:00+01:00
```
## Using the `loyaltyCard` option
```js
import {data as loyaltyCards} from 'db-vendo-client/format/loyalty-cards.js' // see there for a list
hafas.journeys(from, to, {
loyaltyCard: {type: data.BAHNCARD, discount: 25}
})
```
## The `routingMode` option
The `routingMode` option is not supported by db-vendo-client. The behavior will be the same as the [`HYBRID` mode of hafas-client](https://github.com/public-transport/hafas-client/blob/main/p/db/readme.md#using-the-routingmode-option), i.e. cancelled trains/infeasible journeys will also be contained for informational purpose.

View file

@ -1,86 +0,0 @@
# `location(station)`
`station` must be in one of these formats:
```js
// a station ID, in a format compatible to the profile you use
'900000123456'
// an FPTF `station` object
{
type: 'station',
id: '900000123456',
name: 'foo station',
location: {
type: 'location',
latitude: 1.23,
longitude: 3.21
}
}
```
## Response
As an example, we're going to use the [VBB profile](../p/vbb):
```js
const createClient = require('hafas-client')
const vbbProfile = require('hafas-client/p/vbb')
const client = createClient(vbbProfile)
client.location('900000042101') // U Spichernstr.
.then(console.log)
.catch(console.error)
```
The response may look like this:
```js
{
type: 'station',
id: '900000042101',
name: 'U Spichernstr.',
location: {
type: 'location',
latitude: 52.496581,
longitude: 13.330616
},
products: {
suburban: false,
subway: true,
tram: false,
bus: true,
ferry: false,
express: false,
regional: false
},
lines: [ {
type: 'line',
id: 'u1',
name: 'U1',
public: true,
class: 2,
product: 'subway',
mode: 'train',
symbol: 'U',
nr: 1,
metro: false,
express: false,
night: false },
// …
{ type: 'line',
id: 'n9',
name: 'N9',
public: true,
class: 8,
product: 'bus',
mode: 'bus',
symbol: 'N',
nr: 9,
metro: false,
express: false,
night: true
} ]
}
```

View file

@ -6,34 +6,36 @@ With `opt`, you can override the default options, which look like this:
```js
{
fuzzy: true // find only exact matches?
, results: 10 // how many search results?
, stations: true
fuzzy: true // not supported
, results: 5 // how many search results?
, stops: true // return stops/stations?
, addresses: true
, poi: true // points of interest
, subStops: true // not supported
, entrances: true // not supported
, linesOfStops: false // not supported
, language: 'en' // language to get results in
}
```
## Response
As an example, we're going to use the [VBB profile](../p/vbb):
```js
const createClient = require('hafas-client')
const vbbProfile = require('hafas-client/p/vbb')
import {createClient} from 'db-vendo-client'
import {profile as dbnavProfile} from 'db-vendo-client/p/dbnav/index.js'
const client = createClient(vbbProfile)
const userAgent = 'link-to-your-project-or-email' // adapt this to your project!
const client = createClient(dbnavProfile, userAgent)
client.locations('Alexanderplatz', {results: 3})
.then(console.log)
.catch(console.error)
await client.locations('Alexanderplatz', {results: 3})
```
The response may look like this:
The result may look like this:
```js
[ {
type: 'station',
type: 'stop',
id: '900000100003',
name: 'S+U Alexanderplatz',
location: {
@ -52,14 +54,16 @@ The response may look like this:
}
}, { // point of interest
type: 'location',
name: 'Berlin, Holiday Inn Centre Alexanderplatz****',
id: '900980709',
poi: true,
name: 'Berlin, Holiday Inn Centre Alexanderplatz****',
latitude: 52.523549,
longitude: 13.418441
}, { // point of interest
type: 'location',
name: 'Berlin, Hotel Agon am Alexanderplatz',
id: '900980176',
poi: true,
name: 'Berlin, Hotel Agon am Alexanderplatz',
latitude: 52.524556,
longitude: 13.420266
} ]

View file

@ -1,43 +1,45 @@
# `nearby(location, [opt])`
This method can be used to find stations close to a location. Note that it is not supported by every profile/endpoint.
This method can be used to find stops/stations & POIs close to a location. Note that it is not supported by every profile/endpoint.
`location` must be an [*FPTF* `location` object](https://github.com/public-transport/friendly-public-transport-format/blob/1.0.1/spec/readme.md#location-objects).
`location` must be an [*FPTF* `location` object](https://github.com/public-transport/friendly-public-transport-format/blob/3bd36faa721e85d9f5ca58fb0f38cdbedb87bbca/spec/readme.md#location-objects).
With `opt`, you can override the default options, which look like this:
```js
{
results: 8, // maximum number of results
distance: null, // maximum walking distance in meters
poi: false, // return points of interest?
stations: true, // return stations?
poi: false, // not supported
stops: true, // return stops/stations?
subStops: true, // not supported
entrances: true, // not supported
linesOfStops: false, // not supported
language: 'en' // language to get results in
}
```
## Response
As an example, we're going to use the [VBB profile](../p/vbb):
```js
const createClient = require('hafas-client')
const vbbProfile = require('hafas-client/p/vbb')
import {createClient} from 'db-vendo-client'
import {profile as dbProfile} from 'db-vendo-client/p/db/index.js'
const client = createClient(vbbProfile)
const userAgent = 'link-to-your-project-or-email' // adapt this to your project!
const client = createClient(dbProfile, userAgent)
client.nearby({
await client.nearby({
type: 'location',
latitude: 52.5137344,
longitude: 13.4744798
}, {distance: 400})
.then(console.log)
.catch(console.error)
```
The response may look like this:
The result may look like this:
```js
[ {
type: 'station',
type: 'stop',
id: '900000120001',
name: 'S+U Frankfurter Allee',
location: {
@ -56,7 +58,7 @@ The response may look like this:
},
distance: 56
}, {
type: 'station',
type: 'stop',
id: '900000120540',
name: 'Scharnweberstr./Weichselstr.',
location: {
@ -67,7 +69,7 @@ The response may look like this:
products: { /* … */ },
distance: 330
}, {
type: 'station',
type: 'stop',
id: '900000160544',
name: 'Rathaus Lichtenberg',
location: {

2492
docs/openapi.yaml Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,158 +0,0 @@
# `radar(north, west, south, east, [opt])`
Use this method to find all vehicles currently in an area. Note that it is not supported by every profile/endpoint.
`north`, `west`, `south` and `eath` must be numbers (e.g. `52.52411`). Together, they form a [bounding box](https://en.wikipedia.org/wiki/Minimum_bounding_box).
With `opt`, you can override the default options, which look like this:
```js
{
results: 256, // maximum number of vehicles
duration: 30, // compute frames for the next n seconds
frames: 3, // nr of frames to compute
}
```
## Response
*Note:* As stated in the [*Friendly Public Transport Format* `1.0.1`](https://github.com/public-transport/friendly-public-transport-format/tree/1.0.1), the returned `departure` and `arrival` times include the current delay. The `departureDelay`/`arrivalDelay` fields express how much they differ from the schedule.
As an example, we're going to use the [VBB profile](../p/vbb):
```js
const createClient = require('hafas-client')
const vbbProfile = require('hafas-client/p/vbb')
const client = createClient(vbbProfile)
client.radar(52.52411, 13.41002, 52.51942, 13.41709, {results: 5})
.then(console.log)
.catch(console.error)
```
The response may look like this:
```js
[ {
location: {
type: 'location',
latitude: 52.521508,
longitude: 13.411267
},
line: {
type: 'line',
id: 's9',
name: 'S9',
public: true,
mode: 'train',
product: 'suburban',
symbol: 'S',
nr: 9,
metro: false,
express: false,
night: false,
operator: {
type: 'operator',
id: 's-bahn-berlin-gmbh',
name: 'S-Bahn Berlin GmbH'
}
},
direction: 'S Flughafen Berlin-Schönefeld',
trip: 31463,
nextStops: [ {
station: {
type: 'station',
id: '900000029101',
name: 'S Spandau',
location: {
type: 'location',
latitude: 52.534794,
longitude: 13.197477
},
products: {
suburban: true,
subway: false,
tram: false,
bus: true,
ferry: false,
express: true,
regional: true
}
},
arrival: null,
arrivalDelay: null,
departure: '2017-12-17T19:16:00.000+01:00',
departureDelay: null
} /* … */ ],
frames: [ {
origin: {
type: 'station',
id: '900000100003',
name: 'S+U Alexanderplatz',
location: { /* … */ },
products: { /* … */ }
},
destination: {
type: 'station',
id: '900000100004',
name: 'S+U Jannowitzbrücke',
location: { /* … */ },
products: { /* … */ }
},
t: 0
}, /* … */ {
origin: { /* Alexanderplatz */ },
destination: { /* Jannowitzbrücke */ },
t: 30000
} ]
}, {
location: {
type: 'location',
latitude: 52.523297,
longitude: 13.411151
},
line: {
type: 'line',
id: 'm2',
name: 'M2',
public: true,
mode: 'train',
product: 'tram',
symbol: 'M',
nr: 2,
metro: true,
express: false,
night: false,
operator: {
type: 'operator',
id: 'berliner-verkehrsbetriebe',
name: 'Berliner Verkehrsbetriebe'
}
},
direction: 'Heinersdorf',
trip: 26321,
nextStops: [ {
station: { /* S+U Alexanderplatz/Dircksenstr. */ },
arrival: null,
arrivalDelay: null,
departure: '2017-12-17T19:52:00.000+01:00',
departureDelay: null
}, {
station: { /* Memhardstr. */ },
arrival: '2017-12-17T19:54:00.000+01:00',
arrivalDelay: null,
departure: '2017-12-17T19:54:00.000+01:00',
departureDelay: null
}, /* … */ ],
frames: [ {
origin: { /* S+U Alexanderplatz/Dircksenstr. */ },
destination: { /* Memhardstr. */ },
t: 0
}, /* … */ {
origin: { /* Memhardstr. */ },
destination: { /* Mollstr./Prenzlauer Allee */ },
t: 30000
} ]
}, /* … */ ]
```

View file

@ -1,13 +1,154 @@
# API documentation
# `db-vendo-client` documentation
- [`journeys(from, to, [opt])`](journeys.md) get journeys between locations
- [`journeyLeg(ref, lineName, [opt])`](journey-leg.md) get details for a leg of a journey
- [`departures(station, [opt])`](departures.md) query the next departures at a station
- [`locations(query, [opt])`](locations.md) find stations, POIs and addresses
- [`location(id)`](location.md) get details about a location
- [`nearby(location, [opt])`](nearby.md) show stations & POIs around
- [`radar(north, west, south, east, [opt])`](radar.md) find all vehicles currently in a certain area
**[JS API documentation](api.md)**
## Writing a profile
[REST API OpenAPI schema](openapi.yaml) ([open in Swagger Editor](https://editor.swagger.io/?url=https://raw.githubusercontent.com/public-transport/db-vendo-client/refs/heads/main/docs/openapi.yaml))
Check [the guide](writing-a-profile.md).
## Migrating from an old (v5) `hafas-client` version
`db-vendo-client` tries to be as compatible as possible with `hafas-client` v6. If you were still on v5 or earlier, see the [`5` → `6` migration guide](https://github.com/public-transport/hafas-client/blob/main/docs/migrating-to-6.md) of `hafas-client`.
## Throttling requests
There's opt-in support for throttling requests to the endpoint.
```js
import {createClient} from 'db-vendo-client'
import {withThrottling} from 'db-vendo-client/throttle.js'
import {profile as dbProfile} from 'db-vendo-client/p/db/index.js'
const userAgent = 'link-to-your-project-or-email' // adapt this to your project!
// create a throttled HAFAS client with Deutsche Bahn profile
const client = createClient(withThrottling(dbProfile), userAgent)
// Berlin Jungfernheide to München Hbf
await client.journeys('8011167', '8000261', {results: 1})
```
You can also pass custom values for the nr of requests (`limit`) per interval into `withThrottling`:
```js
// 2 requests per second
const throttledDbProfile = withThrottling(dbProfile, 2, 1000)
const client = createClient(throttledDbProfile, userAgent)
```
## Retrying failed requests
There's opt-in support for retrying failed requests to the endpoint.
```js
import {createClient} from 'db-vendo-client'
import {withRetrying} from 'db-vendo-client/retry.js'
import {profile as dbProfile} from 'db-vendo-client/p/db/index.js'
const userAgent = 'link-to-your-project-or-email' // adapt this to your project!
// create a client with Deutsche Bahn profile that will retry on HAFAS errors
const client = createClient(withRetrying(dbProfile), userAgent)
```
You can pass custom options into `withRetrying`. They will be passed into [`retry`](https://github.com/tim-kos/node-retry#tutorial).
```js
// retry 2 times, after 10 seconds & 30 seconds
const retryingDbProfile = withRetrying(dbProfile, {
retries: 2,
minTimeout: 10 * 1000,
factor: 3
})
const client = createClient(retryingDbProfile, userAgent)
```
## User agent randomization
By default, `db-vendo-client` does not randomize the client name that you pass into `createClient`, and sends it as [`User-Agent`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) as it is. At least DB Navigator always sends the same user agent as well (cf. `dbnav` profile). You can turn on randomization by setting `profile.randomizeUserAgent` to `false`:
```js
const client = createClient({
...someProfile,
randomizeUserAgent: true,
}, userAgent)
```
## Logging requests
You can use `profile.logRequest` and `profile.logResponse` to process the raw [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response), respectively.
As an example, we can implement a custom logger:
```js
import {createClient} from 'db-vendo-client'
import {profile as dbProfile} from 'db-vendo-client/p/db/index.js'
const userAgent = 'link-to-your-project-or-email' // adapt this to your project!
const logRequest = (ctx, fetchRequest, requestId) => {
// ctx looks just like with the other profile.* hooks:
const {dbProfile, opt} = ctx
console.debug(requestId, fetchRequest.headers, fetchRequest.body + '')
}
const logResponse = (ctx, fetchResponse, body, requestId) => {
console.debug(requestId, fetchResponse.headers, body + '')
}
// create a client with Deutsche Bahn profile that debug-logs
const client = createClient({
...dbProfile,
logRequest,
logResponse,
}, userAgent)
```
```js
// logRequest output:
'29d0e3' {
accept: 'application/json',
'accept-encoding': 'gzip, br, deflate',
'content-type': 'application/json',
connection: 'keep-alive',
'user-agent': 'hafas842c51-clie842c51nt debug C842c51LI'
} {"lang":"de","svcReqL":[{"cfg":{"polyEnc":"GPA"},"meth":"LocMatch",…
// logResponse output:
'29d0e3' {
'content-encoding': 'gzip',
'content-length': '1010',
'content-type': 'application/json; charset=utf-8',
date: 'Thu, 06 Oct 2022 12:31:09 GMT',
server: 'Apache',
vary: 'User-Agent'
} {"ver":"1.45","lang":"deu","id":"sb42zgck4mxtxm4s","err":"OK","graph"…
```
The default `profile.logRequest` [`console.error`](https://nodejs.org/docs/latest-v10.x/api/console.html#console_console_error_data_args)s the request body, if you have set `$DEBUG` to `hafas-client`. Likewise, `profile.logResponse` `console.error`s the response body.
## Error handling
Unexpected errors e.g. due to bugs in `db-vendo-client` itself aside, its methods may reject with the following errors:
- `Error` A generic error, e.g. if the DB backend returned a HTTP error.
- `HafasError` A generic error to signal that something HAFAS-related went wrong, either in the client, or in the HAFAS endpoint.
Each `HafasError` error has the following properties:
- `isHafasError` Always `true`. Allows you to distinguish HAFAS-related errors from e.g. network errors.
- `code` A string representing the error type for all other error classes, e.g. `INVALID_REQUEST` for `HafasInvalidRequestError`. `null` for plain `HafasError`s.
- `isCausedByServer` Boolean, telling you if the HAFAS endpoint says that it couldn't process your request because *it* is unavailable/broken.
- `hafasCode` A HAFAS-specific error code, if the HAFAS endpoint returned one; e.g. `H890` when no journeys could be found. `null` otherwise.
- `request` The [Fetch API `Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) of the request.
- `url` The URL of the request.
- `response` The [Fetch API `Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response).
## Using `db-vendo-client` from another language
If you want to use `db-vendo-client` to access DB APIs but work with non-Node.js environments, you can use it together with [hafas-rest-api](https://github.com/public-transport/hafas-rest-api) to create a REST API (see the [root readme](https://github.com/public-transport/db-vendo-client/tree/main#usage) and the Docker image).
Or use [`hafas-client-rpc`](https://github.com/derhuerst/hafas-client-rpc) to create a [JSON-RPC](https://www.jsonrpc.org) interface that you can send commands to.
## General documentation and notes for DB APIs
[`db-apis.md`](db-apis.md)

39
docs/refresh-journey.md Normal file
View file

@ -0,0 +1,39 @@
# `refreshJourney(refreshToken, [opt])`
`refreshToken` must be a string, taken from `journey.refreshToken`.
With `opt`, you can override the default options, which look like this:
```js
{
stopovers: false, // return stations on the way?
polylines: false, // return a shape for each leg? mutually exclusive with tickets
tickets: false, // return tickets? mutually exclusive with polylines
subStops: true, // not supported
entrances: true, // not supported
remarks: true, // parse & expose hints & warnings?
language: 'en' // language to get results in
}
```
## Response
```js
import {createClient} from 'db-vendo-client'
import {profile as dbProfile} from 'db-vendo-client/p/db/index.js'
const userAgent = 'link-to-your-project-or-email' // adapt this to your project!
const client = createClient(dbProfile, userAgent)
const {journeys} = await client.journeys('8000105', '8000096', {results: 1})
// later, fetch up-to-date info on the journey
const {
journey,
realtimeDataUpdatedAt,
} = await client.refreshJourney(journeys[0].refreshToken, {stopovers: true, remarks: true})
```
`journey` is a *single* [*Friendly Public Transport Format* v2 draft](https://github.com/public-transport/friendly-public-transport-format/blob/3bd36faa721e85d9f5ca58fb0f38cdbedb87bbca/spec/readme.md) `journey`, in the same format as returned by [`journeys()`](journeys.md).
`realtimeDataUpdatedAt` is currently not set in db-vendo-client, because the upstream APIs don't provide it.

87
docs/stop.md Normal file
View file

@ -0,0 +1,87 @@
# `stop(id, [opt])`
This endpoint is not available with `dbweb` profile.
`id` must be in one of these formats:
```js
// a stop/station ID, in a format compatible with the profile you use
'900000123456'
// an FPTF `stop`/`station` object
{
type: 'station',
id: '900000123456',
name: 'foo station',
location: {
type: 'location',
latitude: 1.23,
longitude: 3.21
}
}
```
With `opt`, you can override the default options, which look like this:
```js
{
subStops: true, // not supported
entrances: true, // not supported
linesOfStops: false, // parse & expose lines at the stop/station?
language: 'en' // language to get results in
}
```
## Response
```js
import {createClient} from 'hafas-client'
import {profile as dbProfile} from 'hafas-client/p/db/index.js'
const userAgent = 'link-to-your-project-or-email' // adapt this to your project!
const client = createClient(dbProfile, userAgent)
await client.stop('900000042101') // U Spichernstr.
```
The result may look like this:
```js
{
type: 'stop',
id: '900000042101',
name: 'U Spichernstr.',
location: {
type: 'location',
latitude: 52.496581,
longitude: 13.330616
},
products: {
suburban: false,
subway: true,
tram: false,
bus: true,
ferry: false,
express: false,
regional: false
},
lines: [ {
type: 'line',
id: 'u1',
mode: 'train',
product: 'subway',
public: true,
name: 'U1',
},
// …
{
type: 'line',
id: 'n9',
mode: 'bus',
product: 'bus',
public: true,
name: 'N9',
} ]
}
```

26
docs/tests.md Normal file
View file

@ -0,0 +1,26 @@
# automated tests in `db-vendo-client`
Because transit data is inherently dynamic (e.g. a different set of departures being returned for a stop now than in 10 minutes), and because it is of paramount importance that `db-vendo-client` actually works with HAFAS endpoints *as they currently work*, its testing setup is a bit unusual.
`db-vendo-client` has three kinds of automated tests:
- unit tests, which test individual aspects of the case base in isolation (e.g. the parsing of HAFAS-formatted dates & times) run via `npm run test-unit`
- end-to-end (E2E) tests, which run actual HTTP requests against their respective profile's HAFAS endpoint run via `npm run test-e2e`
- integration tests, which are the E2E tests running against pre-recorded (and checked-in) HTTP request fixtures run via `npm run test-integration`
Because the E2E & integration tests are based on the same code, when changing this code, you should also update the integration test fixtures accordingly.
*Note:* In order to be as reproducible as possible, the tests query transit data for a certain *fixed* point in time on the future, hard-coded in each profile's test suite (a.k.a. each file `test/e2e/*.js`). In combination with the recording & mocking of HTTP requests, this effectively makes the integration tests deterministic.
## adding integration test fixtures
As an example, let's assume that we have added an entirely new test to [the *DB* profile's E2E tests](../test/e2e/db.js).
The behaviour of the HTTP request recording (into fixtures) and mocking (using the recorded fixtures) is controlled via an environment variable `$VCR_MODE`:
- By running the test(s) with `VCR_MODE=record`, we can record the HTTP requests being made. The tests will run just like without `$VCR_MODE`, except that they will query data for date+time specified in `T_MOCK` (e.g. [here](https://github.com/public-transport/db-vendo-client/blob/8ff945c07515155380de0acb33584e474d6d547c/test/e2e/db.js#L33)).
- Then, by running the test(s) with `VCR_MODE=playback`, because their HTTP requests match the pre-recorded fixtures, they work on the corresponding mocked HTTP responses.
Usually, you would not want to update all *already existing* recorded HTTP request fixtures of the test suite you have made changes in, as they are unrelated to the test you have added. To only record your *added* test, temporarily change `tap.test(…)` to read `tap.only(…)`, and run with `TAP_ONLY=1 VCR_MODE=record`; This will skip all unrelated tests entirely.
Then, check the augmented fixtures (in `test/e2e/fixtures`) into Git, and revert the `tap.only(…)` change. To make sure that everything works, run the entire test suite/file (*without `TAP_ONLY=1`*) with `VCR_MODE=playback`.
*Note:* It might be that the test suite/file you want to augment hasn't been updated in a while, so that `T_MOCK` is in the past. In this case, recording additional fixtures from actual HTTP requests of your added test is usually not possible because the HAFAS API is unable to serve old transit data. In this case, you will first have to change `T_MOCK` to a future date+time (a weekday as "normal" as possible) and re-record all tests' HTTP requests; Don't hesitate to get in touch with me if you have trouble with this.

183
docs/trip.md Normal file
View file

@ -0,0 +1,183 @@
# `trip(id, [opt])`
This method can be used to refetch information about a trip  a vehicle stopping at a set of stops at specific times.
Let's say you used [`journeys`](journeys.md) and now want to get more up-to-date data about the arrival/departure of a leg. You'd pass in the trip ID from `leg.tripId`, e.g. `'1|24983|22|86|18062017'`, and the name of the line from `leg.line.name` like this:
```js
import {createClient} from 'db-vendo-client'
import {profile as dbnavProfile} from 'db-vendo-client/p/dbnav/index.js'
const userAgent = 'link-to-your-project-or-email' // adapt this to your project!
const client = createClient(dbnavProfile, userAgent)
const {journeys} = client.journeys('8000096', '8000105', {results: 1})
const leg = journeys[0].legs[0]
await client.trip(leg.tripId)
```
With `opt`, you can override the default options, which look like this:
```js
{
stopovers: true, // return stations on the way?
polyline: false, // return a shape for the trip? only supported with HAFAS trip id (i.e. not with a trip id from a departure/arrival board of the `db` profile)
subStops: true, // not supported
entrances: true, // not supported
remarks: true, // parse & expose hints & warnings?
language: 'en' // language to get results in
}
```
## Response
*Note:* As stated in the [*Friendly Public Transport Format* v2 draft spec](https://github.com/public-transport/friendly-public-transport-format/blob/3bd36faa721e85d9f5ca58fb0f38cdbedb87bbca/spec/readme.md), the returned `departure` and `arrival` times include the current delay. The `departureDelay`/`arrivalDelay` fields express how much they differ from the schedule.
```js
import {createClient} from 'db-vendo-client'
import {profile as dbnavProfile} from 'db-vendo-client/p/dbnav/index.js'
const client = createClient(dbnavProfile)
const {
trip,
realtimeDataUpdatedAt,
} = await client.trip('1|31431|28|86|17122017', 'S9', {
when: 1513534689273,
})
```
`realtimeDataUpdatedAt` is currently not set in db-vendo-client, because the upstream APIs don't provide it.
When running the code above, `trip` looked like this:
```js
{
id: '1|31431|28|86|17122017',
direction: 'S Spandau',
line: {
type: 'line',
id: '18299',
fahrtNr: '12345',
name: 'S9',
public: true,
mode: 'train',
product: 'suburban',
symbol: 'S',
nr: 9,
metro: false,
express: false,
night: false,
operator: {
type: 'operator',
id: 's-bahn-berlin-gmbh',
name: 'S-Bahn Berlin GmbH'
}
},
currentLocation: {
type: 'location',
latitude: 52.447455,
longitude: 13.522464,
},
origin: {
type: 'station',
id: '900000260005',
name: 'S Flughafen Berlin-Schönefeld',
location: {
type: 'location',
latitude: 52.390796,
longitude: 13.51352
},
products: {
suburban: true,
subway: false,
tram: false,
bus: true,
ferry: false,
express: false,
regional: true
}
},
departure: '2017-12-17T18:37:00+01:00',
plannedDeparture: '2017-12-17T18:37:00+01:00',
departureDelay: null,
departurePlatform: '13',
plannedDeparturePlatform: '13',
destination: {
type: 'station',
id: '900000029101',
name: 'S Spandau',
location: {
type: 'location',
latitude: 52.534794,
longitude: 13.197477
},
products: {
suburban: true,
subway: false,
tram: false,
bus: true,
ferry: false,
express: true,
regional: true
}
},
arrival: '2017-12-17T19:50:30+01:00',
plannedArrival: '2017-12-17T19:49:00+01:00',
arrivalDelay: 90,
arrivalPlatform: '3a',
plannedArrivalPlatform: '2',
stopovers: [ /* … */ ]
}
```
### `polyline` option
Only supported with HAFAS trip id (i.e. not with a trip id from a departure/arrival board of the `db` profile).
If you pass `polyline: true`, the trip will have a `polyline` field, containing a [GeoJSON](http://geojson.org) [`FeatureCollection`](https://tools.ietf.org/html/rfc7946#section-3.3) of [`Point`s](https://tools.ietf.org/html/rfc7946#appendix-A.1).
```js
{
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [13.3875, 52.43993] // longitude, latitude
}
},
/* … */
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [13.38892, 52.49448] // longitude, latitude
}
},
/* … */
{
// intermediate point, without associated station
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: [13.28599, 52.58742] // longitude, latitude
}
},
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [13.28406, 52.58915] // longitude, latitude
}
}
]
}
```

View file

@ -1,166 +0,0 @@
# Writing a profile
**Per endpoint, `hafas-client` has an endpoint-specific customisation called *profile*** which may for example do the following:
- handle the additional requirements of the endpoint (e.g. authentication),
- extract additional information from the data provided by the endpoint,
- guard against triggering bugs of certain endpoints (e.g. time limits).
This guide is about writing such a profile. If you just want to use an already supported endpoint, refer to the [API documentation](readme.md) instead.
*Note*: **If you get stuck, ask for help by [creating an issue](https://github.com/derhuerst/hafas-client/issues/new)!** We want to help people expand the scope of this library.
## 0. How do the profiles work?
A profile contains of three things:
- **mandatory details about the HAFAS endpoint**
- `endpoint`: The protocol, host and path of the endpoint.
- `locale`: The [BCP 47](https://en.wikipedia.org/wiki/IETF_language_tag) [locale](https://en.wikipedia.org/wiki/Locale_(computer_software)) of your endpoint (or the area that your endpoint covers).
- `timezone`: An [IANA-time-zone](https://www.iana.org/time-zones)-compatible [timezone](https://en.wikipedia.org/wiki/Time_zone) of your endpoint.
- **flags indicating that features are supported by the endpoint** e.g. `journeyRef`
- **methods overriding the [default profile](../lib/default-profile.js)**
As an example, let's say we have an [Austrian](https://en.wikipedia.org/wiki/Austria) endpoint:
```js
const myProfile = {
endpoint: 'https://example.org/bin/mgate.exe',
locale: 'de-AT',
timezone: 'Europe/Vienna'
}
```
Assuming the endpoint returns all lines names prefixed with `foo `, We can strip them like this:
```js
// get the default line parser
const createParseLine = require('hafas-client/parse/line')
const createParseLineWithoutFoo = (profile, operators) => {
const parseLine = createParseLine(profile, operators)
// wrapper function with additional logic
const parseLineWithoutFoo = (l) => {
const line = parseLine(l)
line.name = line.name.replace(/foo /g, '')
return line
}
return parseLineWithoutFoo
}
profile.parseLine = createParseLineWithoutFoo
```
If you pass this profile into `hafas-client`, the `parseLine` method will override [the default one](../parse/line.js).
## 1. Setup
*Note*: There are many ways to find the required values. This way is rather easy and has worked for most of the apps that we've looked at so far.
1. **Get an iOS or Android device and download the "official" app** for the public transport provider that you want to build a profile for.
2. **Configure a [man-in-the-middle HTTP proxy](https://docs.mitmproxy.org/stable/concepts-howmitmproxyworks/)** like [mitmproxy](https://mitmproxy.org).
- Configure your device to trust the self-signed SSL certificate, [as outlined in the mitmproxy docs](https://docs.mitmproxy.org/stable/concepts-certificates/).
- *Note*: This method does not work if the app uses [public key pinning](https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning). In this case (the app won't be able to query data), please [create an issue](https://github.com/derhuerst/hafas-client/issues/new), so we can discuss other techniques.
3. **Record requests of the app.**
- [There's a video showing this step](https://stuff.jannisr.de/how-to-record-hafas-requests.mp4).
- Make sure to cover all relevant sections of the app, e.g. "journeys", "departures", "live map". Better record more than less; You will regret not having enough information later on.
- To help others in the future, post the requests (in their entirety!) on GitHub, e.g. in as format like [this](https://gist.github.com/derhuerst/5fa86ed5aec63645e5ae37e23e555886). This will also let us help you if you have any questions.
## 2. Basic profile
- **Identify the `endpoint`.** The protocol, host and path of the endpoint, *but not* the query string.
- *Note*: **`hafas-client` for now only supports the interface providing JSON** (generated from XML), which is being used by the corresponding iOS/Android apps. It supports neither the JSONP, nor the XML, nor the HTML interface. If the endpoint does not end in `mgate.exe`, it mostly likely won't work.
- **Identify the `locale`.** Basically guess work; Use the date & time formats as an indicator.
- **Identify the `timezone`.** This may be tricky, a for example [Deutsche Bahn](https://en.wikipedia.org/wiki/Deutsche_Bahn) returns departures for Moscow as `+01:00` instead of `+03:00`.
- **Copy the authentication** and other meta fields, namely `ver`, `ext`, `client` and `lang`.
- You can find these fields in the root of each request JSON. Check [a VBB request](https://gist.github.com/derhuerst/5fa86ed5aec63645e5ae37e23e555886#file-1-http-L13-L22) and [the corresponding VBB profile](https://github.com/derhuerst/hafas-client/blob/6e61097687a37b60d53e767f2711466b80c5142c/p/vbb/index.js#L22-L29) for an example.
- Add a function `transformReqBody(body)` to your profile, which assigns them to `body`.
- Some profiles have a `checksum` parameter (like [here](https://gist.github.com/derhuerst/2a735268bd82a0a6779633f15dceba33#file-journey-details-1-http-L1)) or two `mic` & `mac` parameters (like [here](https://gist.github.com/derhuerst/5fa86ed5aec63645e5ae37e23e555886#file-1-http-L1)). If you see one of them in your requests, jump to [*Appendix A: checksum, mic, mac*](#appendix-a-checksum-mic-mac). Unfortunately, this is necessary to get the profile working.
## 3. Products
In `hafas-client`, there's a difference between the `mode` and the `product` field:
- The `mode` field describes the mode of transport in general. [Standardised by the *Friendly Public Transport Format* `1.0.1`](https://github.com/public-transport/friendly-public-transport-format/blob/1.0.1/spec/readme.md#modes), it is on purpose limited to a very small number of possible values, e.g. `train` or `bus`.
- The value for `product` relates to how a means of transport "works" *in local context*. Example: Even though [*S-Bahn*](https://en.wikipedia.org/wiki/Berlin_S-Bahn) and [*U-Bahn*](https://en.wikipedia.org/wiki/Berlin_U-Bahn) in Berlin are both `train`s, they have different operators, service patterns, stations and look different. Therefore, they are two distinct `product`s `subway` and `suburban`.
**Specify `product`s that appear in the app** you recorded requests of. For a fictional transit network, this may look like this:
```js
const products = {
commuterTrain: {
product: 'commuterTrain',
mode: 'train',
bitmask: 1,
name: 'ACME Commuter Rail',
short: 'CR'
},
metro: {
product: 'metro',
mode: 'train',
bitmask: 2,
name: 'Foo Bar Metro',
short: 'M'
}
}
```
Let's break this down:
- `product`: A sensible, [camelCased](https://en.wikipedia.org/wiki/Camel_case#Variations_and_synonyms), alphanumeric identifier. Use it for the key in the `products` object as well.
- `mode`: A [valid *Friendly Public Transport Format* `1.0.1` mode](https://github.com/public-transport/friendly-public-transport-format/blob/1.0.1/spec/readme.md#modes).
- `bitmask`: HAFAS endpoints work with a [bitmask](https://en.wikipedia.org/wiki/Mask_(computing)#Arguments_to_functions) that toggles the individual products. the value should toggle the appropriate bit(s) in the bitmask (see below).
- `name`: A short, but distinct name for the means of transport, *just precise enough in local context*, and in the local language. In Berlin, `S-Bahn-Schnellzug` would be too much, because everyone knows what `S-Bahn` means.
- `short`: The shortest possible symbol that identifies the product.
todo: `defaultProducts`, `allProducts`, `bitmasks`, add to profile
If you want, you can now **verify that the profile works**; We've prepared [a script](https://runkit.com/derhuerst/hafas-client-profile-example) for that. Alternatively, [submit a Pull Request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) and we will help you out with testing and improvements.
### Finding the right values for the `bitmask` field
As shown in [the video](https://stuff.jannisr.de/how-to-record-hafas-requests.mp4), search for a journey and toggle off one product at a time, recording the requests. After extracting the products bitmask ([example](https://gist.github.com/derhuerst/193ef489f8aa50c2343f8bf1f2a22069#file-via-http-L34)) you will end up with values looking like these:
```
toggles value binary subtraction bit(s)
all products 31 11111 31 - 0
all but ACME Commuter Rail 15 01111 31 - 2^4 2^4
all but Foo Bar Metro 23 10111 31 - 2^3 2^3
all but product E 30 11001 31 - 2^2 - 2^1 2^2, 2^1
all but product F 253 11110 31 - 2^1 2^0
```
## 4. Additional info
We consider these improvements to be *optional*:
- **Check if the endpoint supports the journey legs call.**
- In the app, check if you can query details for the status of a single journey leg. It should load realtime delays and the current progress.
- If this feature is supported, add `journeyLeg: true` to the profile.
- **Check if the endpoint supports the live map call.** Does the app have a "live map" showing all vehicles within an area? If so, add `radar: true` to the profile.
- **Consider transforming station & line names** into the formats that's most suitable for *local users*. Some examples:
- `M13 (Tram)` -> `M13`. With Berlin context, it is obvious that `M13` is a tram.
- `Berlin Jungfernheide Bhf` -> `Berlin Jungfernheide`. With local context, it's obvious that *Jungfernheide* is a train station.
- **Check if the endpoint has non-obvious limitations** and let use know about these. Examples:
- Some endpoints have a time limit, after which they won't return more departures, but silently discard them.
---
## Appendix A: `checksum`, `mic`, `mac`
As far as we know, there are three different types of authentication used among HAFAS deployments.
### unprotected endpoints
You can just query these, as long as you send a formally correct request.
### endpoints using the `checksum` query parameter
`checksum` is a [message authentication code](https://en.wikipedia.org/wiki/Message_authentication_code): `hafas-client` will compute it by [hashing](https://en.wikipedia.org/wiki/Hash_function) the request body and a secret *salt*. **This secret can be read from the config file inside the app bundle.** There is no guide for this yet, so please [open an issue](https://github.com/derhuerst/hafas-client/issues/new) instead.
### endpoints using the `mic` & `mac` query parameters
`mic` is a [message integrity code](https://en.wikipedia.org/wiki/Message_authentication_code), the [hash](https://en.wikipedia.org/wiki/Hash_function) of the request body.
`mac` is a [message authentication code](https://en.wikipedia.org/wiki/Message_authentication_code), the hash of `mic` and a secret *salt*. **This secret can be read from the config file inside the app bundle.** There is no guide for this yet, so please [open an issue](https://github.com/derhuerst/hafas-client/issues/new) instead.

62
eslint.config.js Normal file
View file

@ -0,0 +1,62 @@
import eslintPluginJs from '@eslint/js';
import eslintPluginStylistic from '@stylistic/eslint-plugin';
import globals from 'globals';
const config = [
eslintPluginJs.configs.recommended,
eslintPluginStylistic.configs['all-flat'],
{
files: ['**/*.js'],
languageOptions: {
ecmaVersion: 'latest',
globals: {
...globals.node,
},
sourceType: 'module',
},
rules: {
'@stylistic/array-bracket-newline': ['error', 'consistent'],
'@stylistic/array-element-newline': ['error', 'consistent'],
'@stylistic/arrow-parens': 'off',
'@stylistic/comma-dangle': ['error', 'always-multiline'],
'@stylistic/dot-location': ['error', 'property'],
'@stylistic/function-call-argument-newline': ['error', 'consistent'],
'@stylistic/function-paren-newline': 'off',
'@stylistic/indent': ['error', 'tab'],
'@stylistic/indent-binary-ops': ['error', 'tab'],
'@stylistic/max-len': 'off',
'@stylistic/multiline-comment-style': 'off',
'@stylistic/multiline-ternary': ['error', 'always-multiline'],
'@stylistic/newline-per-chained-call': ['error', {ignoreChainWithDepth: 1}],
'@stylistic/no-extra-parens': 'off',
'@stylistic/no-mixed-operators': 'off',
'@stylistic/no-tabs': 'off',
'@stylistic/object-property-newline': 'off',
'@stylistic/one-var-declaration-per-line': 'off',
'@stylistic/operator-linebreak': ['error', 'before'],
'@stylistic/padded-blocks': 'off',
'@stylistic/quote-props': ['error', 'consistent-as-needed'],
'@stylistic/quotes': ['error', 'single'],
'curly': 'error',
'no-implicit-coercion': 'error',
'no-unused-vars': [
'error',
{
vars: 'all',
args: 'none',
ignoreRestSiblings: false,
},
],
},
},
{
files: ['test/**', '**/example.js'],
rules: {
'no-unused-vars': 'off',
'@stylistic/semi': 'off',
},
},
];
export default config;

View file

@ -1,24 +1,27 @@
'use strict'
const formatLocationIdentifier = require('./location-identifier')
const formatCoord = require('./coord')
import {formatLocationIdentifier} from './location-identifier.js';
import {formatCoord} from './coord.js';
const formatAddress = (a) => {
if (a.type !== 'location' || !a.latitude || !a.longitude || !a.address) {
throw new Error('invalid address')
throw new TypeError('invalid address');
}
const data = {
A: '2', // address
A: '2', // address?
O: a.address,
X: formatCoord(a.longitude),
Y: formatCoord(a.latitude)
Y: formatCoord(a.latitude),
};
if (a.id) {
data.L = a.id;
}
if (a.id) data.L = a.id
return {
type: 'A', // address
name: a.address,
lid: formatLocationIdentifier(data)
}
}
lid: formatLocationIdentifier(data),
};
};
module.exports = formatAddress
export {
formatAddress,
};

View file

@ -1,5 +1,5 @@
'use strict'
const formatCoord = x => Math.round(x * 1000000);
const formatCoord = x => Math.round(x * 1000000)
module.exports = formatCoord
export {
formatCoord,
};

View file

@ -1,12 +1,24 @@
'use strict'
const {DateTime} = require('luxon')
import {DateTime, IANAZone} from 'luxon';
import {luxonIANAZonesByProfile as timezones} from '../lib/luxon-timezones.js';
// todo: change to `(profile) => (when) => {}`
const formatDate = (profile, when) => {
return DateTime.fromMillis(+when, {
locale: profile.locale,
zone: profile.timezone
}).toFormat('yyyyMMdd')
}
let timezone;
if (timezones.has(profile)) {
timezone = timezones.get(profile);
} else {
timezone = new IANAZone(profile.timezone);
timezones.set(profile, timezone);
}
module.exports = formatDate
return DateTime
.fromMillis(Number(when), {
locale: profile.locale,
zone: timezone,
})
.toFormat('yyyy-MM-dd');
};
export {
formatDate,
};

View file

@ -1,11 +0,0 @@
'use strict'
const bike = {type: 'BC', mode: 'INC'}
const accessibility = {
none: {type: 'META', mode: 'INC', meta: 'notBarrierfree'},
partial: {type: 'META', mode: 'INC', meta: 'limitedBarrierfree'},
complete: {type: 'META', mode: 'INC', meta: 'completeBarrierfree'}
}
module.exports = {bike, accessibility}

View file

@ -1,13 +0,0 @@
'use strict'
module.exports = {
date: require('./date'),
time: require('./time'),
filters: require('./filters'),
station: require('./station'),
address: require('./address'),
poi: require('./poi'),
location: require('./location'),
locationFilter: require('./location-filter'),
rectangle: require('./rectangle')
}

View file

@ -1,8 +0,0 @@
'use strict'
const formatLocationFilter = (stations, addresses, poi) => {
if (stations && addresses && poi) return 'ALL'
return (stations ? 'S' : '') + (addresses ? 'A' : '') + (poi ? 'P' : '')
}
module.exports = formatLocationFilter

View file

@ -1,16 +1,18 @@
'use strict'
const sep = '@'
const sep = '@';
const formatLocationIdentifier = (data) => {
let str = ''
let str = '';
for (let key in data) {
if (!Object.prototype.hasOwnProperty.call(data, key)) continue
if (!Object.prototype.hasOwnProperty.call(data, key)) {
continue;
}
str += key + '=' + data[key] + sep // todo: escape, but how?
str += key + '=' + data[key] + sep; // todo: escape, but how?
}
return str
}
return str;
};
module.exports = formatLocationIdentifier
export {
formatLocationIdentifier,
};

View file

@ -1,14 +1,25 @@
'use strict'
const formatLocation = (profile, l) => {
if ('string' === typeof l) return profile.formatStation(l)
if ('object' === typeof l && !Array.isArray(l)) {
if (l.type === 'station') return profile.formatStation(l.id)
if ('string' === typeof l.id) return profile.formatPoi(l)
if ('string' === typeof l.address) return profile.formatAddress(l)
throw new Error('invalid location type: ' + l.type)
const formatLocation = (profile, l, name = 'location') => {
if ('string' === typeof l) {
return profile.formatStation(l);
}
throw new Error('valid station, address or poi required.')
}
if ('object' === typeof l && !Array.isArray(l)) {
if (l.type === 'station' || l.type === 'stop') {
return profile.formatStation(l.id);
}
if (l.poi) {
return profile.formatPoi(l);
}
if ('string' === typeof l.address) {
return profile.formatAddress(l);
}
if (!l.type) {
throw new TypeError(`missing ${name}.type`);
}
throw new TypeError(`invalid ${name}.type: ${l.type}`);
}
throw new TypeError(name + ': valid station, address or poi required.');
};
module.exports = formatLocation
export {
formatLocation,
};

65
format/loyalty-cards.js Normal file
View file

@ -0,0 +1,65 @@
const c = {
NONE: Symbol('no loyalty card'),
BAHNCARD: Symbol('Bahncard'),
VORTEILSCARD: Symbol('VorteilsCard'),
HALBTAXABO: Symbol('HalbtaxAbo'),
VOORDEELURENABO: Symbol('Voordeelurenabo'),
SHCARD: Symbol('SH-Card'),
GENERALABONNEMENT: Symbol('General-Abonnement'),
NL_40: Symbol('NL-40%'),
AT_KLIMATICKET: Symbol('AT-KlimaTicket'),
};
const formatLoyaltyCard = (data) => {
if (!data) {
return {
art: 'KEINE_ERMAESSIGUNG',
klasse: 'KLASSENLOS',
};
}
const cls = data.class === 1 ? 'KLASSE_1' : 'KLASSE_2';
if (data.type.toString() === c.BAHNCARD.toString()) {
return {
art: 'BAHNCARD' + (data.business ? 'BUSINESS' : '') + data.discount,
klasse: cls,
};
}
if (data.type.toString() === c.VORTEILSCARD.toString()) {
return {
art: 'A-VORTEILSCARD',
klasse: 'KLASSENLOS',
};
}
if (data.type.toString() === c.HALBTAXABO.toString()) {
return {
art: 'CH-HALBTAXABO_OHNE_RAILPLUS',
klasse: 'KLASSENLOS',
};
}
if (data.type.toString() === c.GENERALABONNEMENT.toString()) {
return {
art: 'CH-GENERAL-ABONNEMENT',
klasse: cls,
};
}
if (data.type.toString() === c.NL_40.toString()) {
return {
art: 'NL-40_OHNE_RAILPLUS',
klasse: 'KLASSENLOS',
};
}
if (data.type.toString() === c.AT_KLIMATICKET.toString()) {
return {
art: 'KLIMATICKET_OE',
klasse: 'KLASSENLOS',
};
}
return {
art: 'KEINE_ERMAESSIGUNG',
klasse: 'KLASSENLOS',
};
};
export {
c as data,
formatLoyaltyCard,
};

View file

@ -1,23 +1,25 @@
'use strict'
const formatLocationIdentifier = require('./location-identifier')
const formatCoord = require('./coord')
import {formatLocationIdentifier} from './location-identifier.js';
import {formatCoord} from './coord.js';
const formatPoi = (p) => {
// todo: use Number.isFinite()!
if (p.type !== 'location' || !p.latitude || !p.longitude || !p.id || !p.name) {
throw new Error('invalid POI')
throw new TypeError('invalid POI');
}
return {
type: 'P', // POI
name: p.name,
lid: formatLocationIdentifier({
A: '4', // POI
A: '4', // POI?
O: p.name,
L: p.id,
X: formatCoord(p.longitude),
Y: formatCoord(p.latitude)
})
}
}
Y: formatCoord(p.latitude),
}),
};
};
module.exports = formatPoi
export {
formatPoi,
};

View file

@ -1,16 +0,0 @@
'use strict'
const createFormatBitmask = (allProducts) => {
const formatBitmask = (products) => {
if(Object.keys(products).length === 0) throw new Error('products filter must not be empty')
let bitmask = 0
for (let product in products) {
if (!allProducts[product]) throw new Error('unknown product ' + product)
if (products[product] === true) bitmask += allProducts[product].bitmask
}
return bitmask
}
return formatBitmask
}
module.exports = createFormatBitmask

46
format/products-filter.js Normal file
View file

@ -0,0 +1,46 @@
const isObj = element => element !== null && 'object' === typeof element && !Array.isArray(element);
const hasProp = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
const formatProductsFilter = (ctx, filter, key = 'vendo') => {
if (!isObj(filter)) {
throw new TypeError('products filter must be an object');
}
const {profile} = ctx;
const byProduct = {};
const defaultProducts = {};
for (let product of profile.products) {
byProduct[product.id] = product;
defaultProducts[product.id] = product.default;
}
filter = Object.assign({}, defaultProducts, filter);
let products = [];
let foundDeselected = false;
for (let product in filter) {
if (!hasProp(filter, product) || filter[product] !== true) {
foundDeselected = true;
continue;
}
if (!byProduct[product]) {
throw new TypeError('unknown product ' + product);
}
products.push(byProduct[product][key]);
}
if (products.length === 0) {
throw new Error('no products used');
}
if (!foundDeselected && key == 'ris') {
return undefined;
}
if (!foundDeselected && key == 'dbnav') {
return ['ALL'];
}
return products;
};
export {
formatProductsFilter,
};

View file

@ -1,16 +0,0 @@
'use strict'
const formatRectangle = (profile, north, west, south, east) => {
return {
llCrd: {
x: profile.formatCoord(west),
y: profile.formatCoord(south)
},
urCrd: {
x: profile.formatCoord(east),
y: profile.formatCoord(north)
}
}
}
module.exports = formatRectangle

View file

@ -1,15 +1,22 @@
'use strict'
import {formatLocationIdentifier} from './location-identifier.js';
const formatLocationIdentifier = require('./location-identifier')
const isIBNR = /^\d{6,}$/;
const formatStation = (id) => {
if (!isIBNR.test(id)) {
throw new Error('station ID must be an IBNR.');
}
return {
type: 'S', // station
// todo: name necessary?
lid: formatLocationIdentifier({
A: '1', // station
L: id
})
}
}
A: '1', // station?
L: id,
// todo: `p` timestamp of when the ID was obtained
}),
};
};
module.exports = formatStation
export {
formatStation,
};

View file

@ -1,12 +1,43 @@
'use strict'
import {DateTime, IANAZone} from 'luxon';
import {luxonIANAZonesByProfile as timezones} from '../lib/luxon-timezones.js';
const {DateTime} = require('luxon')
const getTimezone = (profile) => {
let timezone;
if (timezones.has(profile)) {
timezone = timezones.get(profile);
} else {
timezone = new IANAZone(profile.timezone);
timezones.set(profile, timezone);
}
return timezone;
};
const formatTime = (profile, when, includeOffset = false) => {
const timezone = getTimezone(profile);
return DateTime
.fromMillis(Number(when), {
locale: profile.locale,
zone: timezone,
})
.startOf('second')
.toISO({includeOffset: includeOffset, suppressMilliseconds: true});
};
const formatTimeOfDay = (profile, when) => {
const timezone = getTimezone(profile);
return DateTime
.fromMillis(Number(when), {
locale: profile.locale,
zone: timezone,
})
.toFormat('HH:mm');
};
export {
formatTime,
formatTimeOfDay,
};
const formatTime = (profile, when) => {
return DateTime.fromMillis(+when, {
locale: profile.locale,
zone: profile.timezone
}).toFormat('HHmmss')
}
module.exports = formatTime

10
format/transfers.js Normal file
View file

@ -0,0 +1,10 @@
const formatTransfers = (transfers) => {
if (transfers === -1) { // profiles may not accept -1: https://github.com/public-transport/db-vendo-client/issues/5
return undefined;
}
return transfers;
};
export {
formatTransfers,
};

48
format/travellers.js Normal file
View file

@ -0,0 +1,48 @@
const formatTraveller = ({profile}, ageGroup, age, loyaltyCard) => {
const tvlrAgeGroup = age
? profile.ageGroupFromAge(age)
: ageGroup;
let r = {
typ: profile.ageGroupLabel[tvlrAgeGroup || profile.ageGroup.ADULT],
anzahl: 1,
alter: age
? [String(age)]
: [],
ermaessigungen: [profile.formatLoyaltyCard(loyaltyCard)],
};
return r;
};
const validateArr = (field, length) => {
return !field || Array.isArray(field) && field.length == length;
};
const formatTravellers = ({profile, opt}) => {
if ('age' in opt && 'ageGroup' in opt) {
throw new TypeError(`\
opt.age and opt.ageGroup are mutually exclusive.
Pass in just opt.age, and the age group will calculated automatically.`);
}
let travellers = [];
if (Array.isArray(opt.loyaltyCard) || Array.isArray(opt.age) || Array.isArray(opt.ageGroup)) {
const len = opt.loyaltyCard?.length || opt.age?.length || opt.ageGroup?.length;
if (!validateArr(opt.loyaltyCard, len) || !validateArr(opt.age, len) || !validateArr(opt.ageGroup, len)) {
throw new TypeError('If any of loyaltyCard, age or ageGroup are an array, all given must be an array of the same length.');
}
for (let i = 0; i < len; i++) {
travellers.push(formatTraveller({profile}, opt.ageGroup && opt.ageGroup[i], opt.age && opt.age[i], opt.loyaltyCard && opt.loyaltyCard[i]));
}
} else {
travellers.push(formatTraveller({profile}, opt.ageGroup, opt.age, opt.loyaltyCard));
}
const basicCtrfReq = {
klasse: opt.firstClass === true ? 'KLASSE_1' : 'KLASSE_2',
reisende: travellers,
};
return basicCtrfReq;
};
export {
formatTravellers,
};

621
index.js
View file

@ -1,340 +1,401 @@
'use strict'
import distance from 'gps-distance';
const minBy = require('lodash/minBy')
const maxBy = require('lodash/maxBy')
import {defaultProfile} from './lib/default-profile.js';
import {validateProfile} from './lib/validate-profile.js';
const validateProfile = require('./lib/validate-profile')
const defaultProfile = require('./lib/default-profile')
const _request = require('./lib/request')
const isObj = element => element !== null && 'object' === typeof element && !Array.isArray(element);
const isObj = o => o !== null && 'object' === typeof o && !Array.isArray(o)
const isNonEmptyString = str => 'string' === typeof str && str.length > 0
// background info: https://github.com/public-transport/hafas-client/issues/286
const FORBIDDEN_USER_AGENTS = [
'my-awesome-program', // previously used in readme.md, p/*/readme.md & docs/*.md
'hafas-client-example', // previously used in p/*/example.js
'link-to-your-project-or-email', // now used throughout
'db-vendo-client',
];
const createClient = (profile, request = _request) => {
profile = Object.assign({}, defaultProfile, profile)
validateProfile(profile)
const isNonEmptyString = str => 'string' === typeof str && str.length > 0;
const departures = (station, opt = {}) => {
if (isObj(station)) station = profile.formatStation(station.id)
else if ('string' === typeof station) station = profile.formatStation(station)
else throw new Error('station must be an object or a string.')
const validateLocation = (loc, name = 'location') => {
if (!isObj(loc)) {
throw new TypeError(name + ' must be an object.');
} else if (loc.type !== 'location') {
throw new TypeError('invalid location object.');
} else if ('number' !== typeof loc.latitude) {
throw new TypeError(name + '.latitude must be a number.');
} else if ('number' !== typeof loc.longitude) {
throw new TypeError(name + '.longitude must be a number.');
}
};
opt = Object.assign({
direction: null, // only show departures heading to this station
duration: 10 // show departures for the next n minutes
}, opt)
opt.when = opt.when || new Date()
const products = profile.formatProducts(opt.products || {})
const loadEnrichedStationData = async (profile) => {
const dbHafasStations = await import('db-hafas-stations');
const items = {};
for await (const station of dbHafasStations.readFullStations()) {
items[station.id] = station;
items[station.name] = station;
}
if (profile.DEBUG) {
console.log('Loaded station index.');
}
return items;
};
const dir = opt.direction ? profile.formatStation(opt.direction) : null
return request(profile, {
meth: 'StationBoard',
req: {
type: 'DEP',
date: profile.formatDate(profile, opt.when),
time: profile.formatTime(profile, opt.when),
stbLoc: station,
dirLoc: dir,
jnyFltrL: [products],
dur: opt.duration,
getPasslist: false
}
})
.then((d) => {
if (!Array.isArray(d.jnyL)) return [] // todo: throw err?
const parse = profile.parseDeparture(profile, d.locations, d.lines, d.remarks)
return d.jnyL.map(parse)
.sort((a, b) => new Date(a.when) - new Date(b.when))
})
const applyEnrichedStationData = async (ctx, shouldLoadEnrichedStationData) => {
const {profile, common} = ctx;
if (shouldLoadEnrichedStationData && !common.locations) {
const locations = await loadEnrichedStationData(profile);
common.locations = locations;
}
};
const createClient = (profile, userAgent, opt = {}) => {
profile = Object.assign({}, defaultProfile, profile);
validateProfile(profile);
const common = {};
let shouldLoadEnrichedStationData = false;
if (typeof opt.enrichStations === 'function') {
profile.enrichStation = opt.enrichStations;
} else if (opt.enrichStations !== false) {
shouldLoadEnrichedStationData = true;
}
const journeys = (from, to, opt = {}) => {
from = profile.formatLocation(profile, from)
to = profile.formatLocation(profile, to)
if ('string' !== typeof userAgent) {
throw new TypeError('userAgent must be a string');
}
if (FORBIDDEN_USER_AGENTS.includes(userAgent.toLowerCase())) {
throw new TypeError(`userAgent should tell the API operators how to contact you. If you have copied "${userAgent}" value from the documentation, please adapt it.`);
}
if (('earlierThan' in opt) && ('laterThan' in opt)) {
throw new Error('opt.laterThan and opt.laterThan are mutually exclusive.')
const _stationBoard = async (station, type, resultsField, parse, opt = {}) => {
await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData);
if (isObj(station) && station.id) {
station = station.id;
} else if ('string' !== typeof station) {
throw new TypeError('station must be an object or a string.');
}
let journeysRef = null
if ('string' !== typeof type || !type) {
throw new TypeError('type must be a non-empty string.');
}
if (!profile.departuresGetPasslist && opt.stopovers) {
throw new Error('opt.stopovers is not supported by this endpoint');
}
if (!profile.departuresStbFltrEquiv && 'includeRelatedStations' in opt) {
throw new Error('opt.includeRelatedStations is not supported by this endpoint');
}
opt = Object.assign({
// todo: for arrivals(), this is actually a station it *has already* stopped by
direction: null, // only show departures stopping by this station
line: null, // filter by line ID
duration: 10, // show departures for the next n minutes
results: null, // max. number of results; `null` means "whatever HAFAS wants"
subStops: true, // parse & expose sub-stops of stations?
entrances: true, // parse & expose entrances of stops/stations?
linesOfStops: false, // parse & expose lines at the stop/station?
remarks: true, // parse & expose hints & warnings?
stopovers: false, // fetch & parse previous/next stopovers?
// departures at related stations
// e.g. those that belong together on the metro map.
includeRelatedStations: true,
moreStops: null, // also include departures/arrivals for array of up to nine additional station evaNumbers (not supported with dbnav and dbweb)
}, opt);
opt.when = new Date(opt.when || Date.now());
if (Number.isNaN(Number(opt.when))) {
throw new Error('opt.when is invalid');
}
const req = profile.formatStationBoardReq({profile, opt}, station, resultsField);
const {res} = await profile.request({profile, opt}, userAgent, req);
const ctx = {profile, opt, common, res};
let results = (res[resultsField] || res.items || res.bahnhofstafelAbfahrtPositionen || res.bahnhofstafelAnkunftPositionen || res.entries.flat())
.map(res => parse(ctx, res)); // TODO sort?, slice
if (!opt.includeRelatedStations) {
results = results.filter(r => !r.stop?.id || r.stop.id == station);
}
if (opt.direction) {
results = results.filter(r => !r.nextStopovers || r.nextStopovers.find(s => s.stop?.id == opt.direction || s.stop?.name == opt.direction));
}
return {
[resultsField]: results,
realtimeDataUpdatedAt: null, // TODO
};
};
const departures = async (station, opt = {}) => {
return await _stationBoard(station, 'DEP', 'departures', profile.parseDeparture, opt);
};
const arrivals = async (station, opt = {}) => {
return await _stationBoard(station, 'ARR', 'arrivals', profile.parseArrival, opt);
};
const journeys = async (from, to, opt = {}) => {
await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData);
if ('earlierThan' in opt && 'laterThan' in opt) {
throw new TypeError('opt.earlierThan and opt.laterThan are mutually exclusive.');
}
if ('departure' in opt && 'arrival' in opt) {
throw new TypeError('opt.departure and opt.arrival are mutually exclusive.');
}
let journeysRef = null;
if ('earlierThan' in opt) {
if (!isNonEmptyString(opt.earlierThan)) {
throw new Error('opt.earlierThan must be a non-empty string.')
throw new TypeError('opt.earlierThan must be a non-empty string.');
}
if ('when' in opt) {
throw new Error('opt.earlierThan and opt.when are mutually exclusive.')
if ('departure' in opt || 'arrival' in opt) {
throw new TypeError('opt.earlierThan and opt.departure/opt.arrival are mutually exclusive.');
}
journeysRef = opt.earlierThan
journeysRef = opt.earlierThan;
}
if ('laterThan' in opt) {
if (!isNonEmptyString(opt.laterThan)) {
throw new Error('opt.laterThan must be a non-empty string.')
throw new TypeError('opt.laterThan must be a non-empty string.');
}
if ('when' in opt) {
throw new Error('opt.laterThan and opt.when are mutually exclusive.')
if ('departure' in opt || 'arrival' in opt) {
throw new TypeError('opt.laterThan and opt.departure/opt.arrival are mutually exclusive.');
}
journeysRef = opt.laterThan
journeysRef = opt.laterThan;
}
opt = Object.assign({
results: 5, // how many journeys?
results: null, // number of journeys `null` means "whatever HAFAS returns"
via: null, // let journeys pass this station?
passedStations: false, // return stations on the way?
transfers: 5, // maximum of 5 transfers
stopovers: false, // return stations on the way?
transfers: null, // maximum nr of transfers
transferTime: 0, // minimum time for a single transfer in minutes
// todo: does this work with every endpoint?
accessibility: 'none', // 'none', 'partial' or 'complete'
bike: false, // only bike-friendly journeys
walkingSpeed: 'normal', // 'slow', 'normal', 'fast'
// Consider walking to nearby stations at the beginning of a journey?
startWithWalking: true,
tickets: false, // return tickets?
}, opt)
if (opt.via) opt.via = profile.formatLocation(profile, opt.via)
opt.when = opt.when || new Date()
polylines: false, // return leg shapes?
subStops: true, // parse & expose sub-stops of stations?
entrances: true, // parse & expose entrances of stops/stations?
remarks: true, // parse & expose hints & warnings?
scheduledDays: false, // parse & expose dates each journey is valid on?
notOnlyFastRoutes: false, // if true, also show routes that are mathematically non-optimal
bestprice: false, // search for lowest prices across the entire day
deutschlandTicketDiscount: false,
deutschlandTicketConnectionsOnly: false,
}, opt);
const filters = [
profile.formatProducts(opt.products || {})
]
if (
opt.accessibility &&
profile.filters &&
profile.filters.accessibility &&
profile.filters.accessibility[opt.accessibility]
) {
filters.push(profile.filters.accessibility[opt.accessibility])
if (opt.when !== undefined) {
throw new Error('opt.when is not supported anymore. Use opt.departure/opt.arrival.');
}
// With protocol version `1.16`, the VBB endpoint fails with
// `CGI_READ_FAILED` if you pass `numF`, the parameter for the number
// of results. To circumvent this, we loop here, collecting journeys
// until we have enough.
// see https://github.com/derhuerst/hafas-client/pull/23#issuecomment-370246163
// todo: check if `numF` is supported again, revert this change
const journeys = []
const more = (when, journeysRef) => {
const query = {
outDate: profile.formatDate(profile, when),
outTime: profile.formatTime(profile, when),
ctxScr: journeysRef,
getPasslist: !!opt.passedStations,
maxChg: opt.transfers,
minChgTime: opt.transferTime,
depLocL: [from],
viaLocL: opt.via ? [{loc: opt.via}] : null,
arrLocL: [to],
jnyFltrL: filters,
getTariff: !!opt.tickets,
// todo: what is req.gisFltrL?
getPT: true, // todo: what is this?
outFrwd: true, // todo: what is this?
getIV: false, // todo: walk & bike as alternatives?
getPolyline: false // todo: shape for displaying on a map?
let when = new Date(), outFrwd = true;
if (opt.departure !== undefined && opt.departure !== null) {
when = new Date(opt.departure);
if (Number.isNaN(Number(when))) {
throw new TypeError('opt.departure is invalid');
}
if (profile.journeysNumF) query.numF = opt.results
return request(profile, {
cfg: {polyEnc: 'GPA'},
meth: 'TripSearch',
req: profile.transformJourneysQuery(query, opt)
})
.then((d) => {
if (!Array.isArray(d.outConL)) return []
const parse = profile.parseJourney(profile, d.locations, d.lines, d.remarks)
if (!journeys.earlierRef) journeys.earlierRef = d.outCtxScrB
let latestDep = -Infinity
for (let j of d.outConL) {
j = parse(j)
journeys.push(j)
if (journeys.length === opt.results) { // collected enough
journeys.laterRef = d.outCtxScrF
return journeys
}
const dep = +new Date(j.departure)
if (dep > latestDep) latestDep = dep
}
const when = new Date(latestDep)
return more(when, d.outCtxScrF) // otherwise continue
})
} else if (opt.arrival !== undefined && opt.arrival !== null) {
if (!profile.journeysOutFrwd) {
throw new Error('opt.arrival is unsupported');
}
when = new Date(opt.arrival);
if (Number.isNaN(Number(when))) {
throw new TypeError('opt.arrival is invalid');
}
outFrwd = false;
}
return more(opt.when, journeysRef)
}
const req = profile.formatJourneysReq({profile, opt}, from, to, when, outFrwd, journeysRef);
const {res} = await profile.request({profile, opt}, userAgent, req);
const ctx = {profile, opt, common, res};
if (opt.bestprice) {
res.verbindungen = (res.intervalle || res.tagesbestPreisIntervalle).flatMap(i => i.verbindungen.map(v => ({...v, ...v.verbindung})));
}
const verbindungen = Number.isInteger(opt.results) && opt.results != 3 ? res.verbindungen.slice(0, opt.results) : res.verbindungen; // TODO remove default from hafas-rest-api
const journeys = verbindungen
.map(j => profile.parseJourney(ctx, j));
if (opt.bestprice) {
journeys.sort((a, b) => a.price?.amount - b.price?.amount);
}
return {
earlierRef: res.verbindungReference?.earlier || res.frueherContext || null,
laterRef: res.verbindungReference?.later || res.spaeterContext || null,
journeys,
realtimeDataUpdatedAt: null, // TODO
};
};
const refreshJourney = async (refreshToken, opt = {}) => {
await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData);
if ('string' !== typeof refreshToken || !refreshToken) {
throw new TypeError('refreshToken must be a non-empty string.');
}
opt = Object.assign({
stopovers: false, // return stations on the way?
tickets: false, // return tickets?
polylines: false, // return leg shapes? (not supported by all endpoints)
subStops: true, // parse & expose sub-stops of stations?
entrances: true, // parse & expose entrances of stops/stations?
remarks: true, // parse & expose hints & warnings?
scheduledDays: false, // parse & expose dates the journey is valid on?
deutschlandTicketDiscount: false,
deutschlandTicketConnectionsOnly: false,
}, opt);
const req = profile.formatRefreshJourneyReq({profile, opt}, refreshToken);
const {res} = await profile.request({profile, opt}, userAgent, req);
const ctx = {profile, opt, common, res};
return {
journey: profile.parseJourney(ctx, res.verbindungen && res.verbindungen[0] || res),
realtimeDataUpdatedAt: null, // TODO
};
};
const locations = async (query, opt = {}) => {
await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData);
const locations = (query, opt = {}) => {
if (!isNonEmptyString(query)) {
throw new Error('query must be a non-empty string.')
throw new TypeError('query must be a non-empty string.');
}
opt = Object.assign({
fuzzy: true, // find only exact matches?
results: 10, // how many search results?
stations: true,
results: 5, // how many search results?
stops: true, // return stops/stations?
addresses: true,
poi: true // points of interest
}, opt)
poi: true, // points of interest
subStops: true, // parse & expose sub-stops of stations?
entrances: true, // parse & expose entrances of stops/stations?
linesOfStops: false, // parse & expose lines at each stop/station?
}, opt);
const req = profile.formatLocationsReq({profile, opt}, query);
const f = profile.formatLocationFilter(opt.stations, opt.addresses, opt.poi)
return request(profile, {
cfg: {polyEnc: 'GPA'},
meth: 'LocMatch',
req: {input: {
loc: {
type: f,
name: opt.fuzzy ? query + '?' : query
},
maxLoc: opt.results,
field: 'S' // todo: what is this?
}}
})
.then((d) => {
if (!d.match || !Array.isArray(d.match.locL)) return []
const parse = profile.parseLocation
return d.match.locL.map(loc => parse(profile, loc, d.lines))
})
}
const {res} = await profile.request({profile, opt}, userAgent, req);
const location = (station) => {
if ('object' === typeof station) station = profile.formatStation(station.id)
else if ('string' === typeof station) station = profile.formatStation(station)
else throw new Error('station must be an object or a string.')
const ctx = {profile, opt, common, res};
const results = res.map(loc => profile.parseLocation(ctx, loc));
return request(profile, {
meth: 'LocDetails',
req: {
locL: [station]
}
})
.then((d) => {
if (!d || !Array.isArray(d.locL) || !d.locL[0]) {
// todo: proper stack trace?
throw new Error('invalid response')
}
return profile.parseLocation(profile, d.locL[0], d.lines)
})
}
return Number.isInteger(opt.results)
? results.slice(0, opt.results)
: results;
};
const nearby = (location, opt = {}) => {
if (!isObj(location)) {
throw new Error('location must be an object.')
} else if (location.type !== 'location') {
throw new Error('invalid location object.')
} else if ('number' !== typeof location.latitude) {
throw new Error('location.latitude must be a number.')
} else if ('number' !== typeof location.longitude) {
throw new Error('location.longitude must be a number.')
const stop = async (stop, opt = {}) => {
await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData);
if (isObj(stop) && stop.id) {
stop = stop.id;
} else if ('string' !== typeof stop) {
throw new TypeError('stop must be an object or a string.');
}
opt = Object.assign({
linesOfStops: false, // parse & expose lines at the stop/station?
subStops: true, // parse & expose sub-stops of stations?
entrances: true, // parse & expose entrances of stops/stations?
remarks: true, // parse & expose hints & warnings?
}, opt);
const req = profile.formatStopReq({profile, opt}, stop);
const {res} = await profile.request({profile, opt}, userAgent, req);
const ctx = {profile, opt, res, common};
return profile.parseStop(ctx, res, stop);
};
const nearby = async (location, opt = {}) => {
await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData);
validateLocation(location, 'location');
opt = Object.assign({
results: 8, // maximum number of results
distance: null, // maximum walking distance in meters
poi: false, // return points of interest?
stations: true, // return stations?
}, opt)
stops: true, // return stops/stations?
subStops: true, // parse & expose sub-stops of stations?
entrances: true, // parse & expose entrances of stops/stations?
linesOfStops: false, // parse & expose lines at each stop/station?
}, opt);
return request(profile, {
cfg: {polyEnc: 'GPA'},
meth: 'LocGeoPos',
req: {
ring: {
cCrd: {
x: profile.formatCoord(location.longitude),
y: profile.formatCoord(location.latitude)
},
maxDist: opt.distance || -1,
minDist: 0
},
getPOIs: !!opt.poi,
getStops: !!opt.stations,
maxLoc: opt.results
const req = profile.formatNearbyReq({profile, opt}, location);
const {res} = await profile.request({profile, opt}, userAgent, req);
const ctx = {profile, opt, common, res};
const results = res.map(loc => {
const res = profile.parseLocation(ctx, loc);
if (res.latitude || res.location?.latitude) {
res.distance = Math.round(distance(location.latitude, location.longitude, res.latitude || res.location?.latitude, res.longitude || res.location?.longitude) * 1000);
}
})
.then((d) => {
if (!Array.isArray(d.locL)) return []
const parse = profile.parseNearby
return d.locL.map(loc => parse(profile, loc))
})
}
return res;
});
const journeyLeg = (ref, lineName, opt = {}) => {
if (!isNonEmptyString(ref)) {
throw new Error('ref must be a non-empty string.')
}
if (!isNonEmptyString(lineName)) {
throw new Error('lineName must be a non-empty string.')
return Number.isInteger(opt.results)
? results.slice(0, opt.results)
: results;
};
const trip = async (id, opt = {}) => {
await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData);
if (!isNonEmptyString(id)) {
throw new TypeError('id must be a non-empty string.');
}
opt = Object.assign({
passedStations: true // return stations on the way?
}, opt)
opt.when = opt.when || new Date()
stopovers: true, // return stations on the way?
polyline: false, // return a track shape?
subStops: true, // parse & expose sub-stops of stations?
entrances: true, // parse & expose entrances of stops/stations?
remarks: true, // parse & expose hints & warnings?
scheduledDays: false, // parse & expose dates trip is valid on?
}, opt);
return request(profile, {
cfg: {polyEnc: 'GPA'},
meth: 'JourneyDetails',
req: {
jid: ref,
name: lineName,
date: profile.formatDate(profile, opt.when)
}
})
.then((d) => {
const parse = profile.parseJourneyLeg(profile, d.locations, d.lines, d.remarks)
const req = profile.formatTripReq({profile, opt}, id);
const leg = { // pretend the leg is contained in a journey
type: 'JNY',
dep: minBy(d.journey.stopL, 'idx'),
arr: maxBy(d.journey.stopL, 'idx'),
jny: d.journey
}
return parse(d.journey, leg, !!opt.passedStations)
})
const {res} = await profile.request({profile, opt}, userAgent, req);
const ctx = {profile, opt, common, res};
const trip = profile.parseTrip(ctx, res, id);
return {
trip,
realtimeDataUpdatedAt: null, // TODO
};
};
// todo [breaking]: rename to trips()?
const tripsByName = async (_lineNameOrFahrtNr = '*', _opt = {}) => {
await applyEnrichedStationData({profile, common}, shouldLoadEnrichedStationData);
throw new Error('not implemented');
};
const client = {
departures,
arrivals,
journeys,
locations,
stop,
nearby,
};
if (profile.trip) {
client.trip = trip;
}
const radar = (north, west, south, east, opt) => {
if ('number' !== typeof north) throw new Error('north must be a number.')
if ('number' !== typeof west) throw new Error('west must be a number.')
if ('number' !== typeof south) throw new Error('south must be a number.')
if ('number' !== typeof east) throw new Error('east must be a number.')
opt = Object.assign({
results: 256, // maximum number of vehicles
duration: 30, // compute frames for the next n seconds
frames: 3, // nr of frames to compute
products: null // optionally an object of booleans
}, opt || {})
opt.when = opt.when || new Date()
const durationPerStep = opt.duration / Math.max(opt.frames, 1) * 1000
return request(profile, {
meth: 'JourneyGeoPos',
req: {
maxJny: opt.results,
onlyRT: false, // todo: does this mean "only realtime"?
date: profile.formatDate(profile, opt.when),
time: profile.formatTime(profile, opt.when),
// todo: would a ring work here as well?
rect: profile.formatRectangle(profile, north, west, south, east),
perSize: opt.duration * 1000,
perStep: Math.round(durationPerStep),
ageOfReport: true, // todo: what is this?
jnyFltrL: [
profile.formatProducts(opt.products || {})
],
trainPosMode: 'CALC' // todo: what is this? what about realtime?
}
})
.then((d) => {
if (!Array.isArray(d.jnyL)) return []
const parse = profile.parseMovement(profile, d.locations, d.lines, d.remarks)
return d.jnyL.map(parse)
})
if (profile.refreshJourney) {
client.refreshJourney = refreshJourney;
}
if (profile.tripsByName) {
client.tripsByName = tripsByName;
}
Object.defineProperty(client, 'profile', {value: profile});
return client;
};
const client = {departures, journeys, locations, location, nearby}
if (profile.journeyLeg) client.journeyLeg = journeyLeg
if (profile.radar) client.radar = radar
Object.defineProperty(client, 'profile', {value: profile})
return client
}
module.exports = createClient
export {
createClient,
loadEnrichedStationData,
};

48
lib/age-group.js Normal file
View file

@ -0,0 +1,48 @@
const ageGroup = {
BABY: 'B',
CHILD: 'K',
YOUNG: 'Y',
ADULT: 'E',
SENIOR: 'S',
upperBoundOf: {
BABY: 6,
CHILD: 15,
YOUNG: 27,
ADULT: 65,
SENIOR: Infinity,
},
};
const ageGroupLabel = {
B: 'KLEINKIND',
K: 'FAMILIENKIND',
Y: 'JUGENDLICHER',
E: 'ERWACHSENER',
S: 'SENIOR',
};
const ageGroupFromAge = (age) => {
const {upperBoundOf} = ageGroup;
if (age < upperBoundOf.BABY) {
return ageGroup.BABY;
}
if (age < upperBoundOf.CHILD) {
return ageGroup.CHILD;
}
if (age < upperBoundOf.YOUNG) {
return ageGroup.YOUNG;
}
if (age < upperBoundOf.ADULT) {
return ageGroup.ADULT;
}
if (age < upperBoundOf.SENIOR) {
return ageGroup.SENIOR;
}
throw new TypeError(`Invalid age '${age}'`);
};
export {
ageGroup,
ageGroupLabel,
ageGroupFromAge,
};

109
lib/api-parsers.js Normal file
View file

@ -0,0 +1,109 @@
import {data as cards} from '../format/loyalty-cards.js';
import {parseBoolean, parseInteger, parseArrayOfStrings} from 'hafas-rest-api/lib/parse.js';
const typesByName = new Map([
['bahncard-1st-25', {type: cards.BAHNCARD, discount: 25, class: 1}],
['bahncard-2nd-25', {type: cards.BAHNCARD, discount: 25, class: 2}],
['bahncard-1st-50', {type: cards.BAHNCARD, discount: 50, class: 1}],
['bahncard-2nd-50', {type: cards.BAHNCARD, discount: 50, class: 2}],
['bahncard-1st-100', {type: cards.BAHNCARD, discount: 100, class: 1}],
['bahncard-2nd-100', {type: cards.BAHNCARD, discount: 100, class: 2}],
['vorteilscard', {type: cards.VORTEILSCARD}],
['halbtaxabo-railplus', {type: cards.HALBTAXABO}],
['halbtaxabo', {type: cards.HALBTAXABO}],
['voordeelurenabo-railplus', {type: cards.VOORDEELURENABO}],
['voordeelurenabo', {type: cards.VOORDEELURENABO}],
['shcard', {type: cards.SHCARD}],
['generalabonnement-1st', {type: cards.GENERALABONNEMENT, class: 1}],
['generalabonnement-2nd', {type: cards.GENERALABONNEMENT, class: 2}],
['generalabonnement', {type: cards.GENERALABONNEMENT}],
['nl-40', {type: cards.NL_40}],
['at-klimaticket', {type: cards.AT_KLIMATICKET}],
]);
const types = Array.from(typesByName.keys());
const parseLoyaltyCard = (key, val) => {
if (typesByName.has(val)) {
return typesByName.get(val);
}
if (!val) {
return null;
}
throw new Error(key + ' must be one of ' + types.join(', '));
};
const parseArrayOr = (parseEntry) => {
return (key, val) => {
if (Array.isArray(val)) {
return val.map(e => parseEntry(key, e));
}
return parseEntry(key, val);
};
};
const mapRouteParsers = (route, parsers) => {
if (route.includes('journey')) {
return {
...parsers,
firstClass: {
description: 'Search for first-class options?',
type: 'boolean',
default: false,
parse: parseBoolean,
},
loyaltyCard: {
description: 'Type of loyalty card in use.',
type: 'string',
enum: types,
defaultStr: '*none*',
parse: parseArrayOr(parseLoyaltyCard),
},
age: {
description: 'Age of traveller',
type: 'integer',
defaultStr: '*adult*',
parse: parseArrayOr(parseInteger),
},
notOnlyFastRoutes: {
description: 'If true, also show routes that are mathematically non-optimal',
type: 'boolean',
default: false,
parse: parseBoolean,
},
bestprice: {
description: 'Search for lowest prices across the entire day',
type: 'boolean',
default: false,
parse: parseBoolean,
},
deutschlandTicketDiscount: {
description: 'Calculate ticket prices assuming Deutschlandticket is present',
type: 'boolean',
default: false,
parse: parseBoolean,
},
deutschlandTicketConnectionsOnly: {
description: 'Only return journeys that can be used with the Deutschlandticket',
type: 'boolean',
default: false,
parse: parseBoolean,
},
};
}
if (route.includes('departures') || route.includes('arrivals')) {
return {
...parsers,
moreStops: {
description: 'Also include departures/arrivals for up to nine comma-separated station evaNumbers (not supported with dbnav and dbweb)',
type: 'string',
default: '',
parse: parseArrayOfStrings,
},
};
}
return parsers;
};
export {
mapRouteParsers,
};

View file

@ -1,67 +1,126 @@
'use strict'
import {request} from '../lib/request.js';
import {products} from '../lib/products.js';
import {ageGroup, ageGroupFromAge, ageGroupLabel} from './age-group.js';
const parseDateTime = require('../parse/date-time')
const parseDeparture = require('../parse/departure')
const parseJourneyLeg = require('../parse/journey-leg')
const parseJourney = require('../parse/journey')
const parseLine = require('../parse/line')
const parseLocation = require('../parse/location')
const parseMovement = require('../parse/movement')
const parseNearby = require('../parse/nearby')
const parseOperator = require('../parse/operator')
const parseRemark = require('../parse/remark')
const parseStopover = require('../parse/stopover')
import {parseDateTime} from '../parse/date-time.js';
import {parsePlatform} from '../parse/platform.js';
import {parseProducts} from '../parse/products.js';
import {parseWhen} from '../parse/when.js';
import {parseDeparture} from '../parse/departure.js';
import {parseArrival} from '../parse/arrival.js';
import {parseTrip} from '../parse/trip.js';
import {parseJourneyLeg} from '../parse/journey-leg.js';
import {parseJourney} from '../parse/journey.js';
import {parseLine} from '../parse/line.js';
import {parseLocation, enrichStation} from '../parse/location.js';
import {parsePolyline} from '../parse/polyline.js';
import {parseOperator} from '../parse/operator.js';
import {parseRemarks, parseCancelled} from '../parse/remarks.js';
import {parseStopover} from '../parse/stopover.js';
import {parseLoadFactor, parseArrOrDepWithLoadFactor} from '../parse/load-factor.js';
import {parseHintByCode} from '../parse/hints-by-code.js';
import {parseTickets, parsePrice} from '../parse/tickets.js';
const formatAddress = require('../format/address')
const formatCoord = require('../format/coord')
const formatDate = require('../format/date')
const formatLocationFilter = require('../format/location-filter')
const formatPoi = require('../format/poi')
const formatStation = require('../format/station')
const formatTime = require('../format/time')
const formatLocation = require('../format/location')
const formatRectangle = require('../format/rectangle')
const filters = require('../format/filters')
import {formatAddress} from '../format/address.js';
import {formatCoord} from '../format/coord.js';
import {formatDate} from '../format/date.js';
import {formatProductsFilter} from '../format/products-filter.js';
import {formatPoi} from '../format/poi.js';
import {formatStation} from '../format/station.js';
import {formatTime, formatTimeOfDay} from '../format/time.js';
import {formatLocation} from '../format/location.js';
import {formatTravellers} from '../format/travellers.js';
import {formatLoyaltyCard} from '../format/loyalty-cards.js';
import {formatTransfers} from '../format/transfers.js';
const id = x => x
const DEBUG = (/(^|,)hafas-client(,|$)/).test(typeof process !== 'undefined' ? process.env.DEBUG || '' : '');
const logRequest = DEBUG
? (_, req, reqId) => console.error(String(req.body))
: () => { };
const logResponse = DEBUG
? (_, res, body, reqId) => console.error(body)
: () => { };
const id = (_ctx, x) => x;
const notImplemented = (_ctx, _x) => {
throw new Error('NotImplemented');
};
const defaultProfile = {
salt: null,
addChecksum: false,
addMicMac: false,
DEBUG,
request,
products,
ageGroup, ageGroupFromAge, ageGroupLabel,
transformReqBody: id,
transformReq: id,
randomizeUserAgent: false,
logRequest,
logResponse,
formatJourneysReq: notImplemented,
formatRefreshJourneyReq: notImplemented,
formatTripReq: notImplemented,
formatNearbyReq: notImplemented,
formatLocationsReq: notImplemented,
formatStopReq: notImplemented,
formatStationBoardReq: notImplemented,
transformJourneysQuery: id,
parseDateTime,
parsePlatform,
parseProducts,
parseWhen,
parseDeparture,
parseArrival,
parseTrip,
parseJourneyLeg,
parseJourney,
parseLine,
parseStationName: id,
parseLocation,
parseMovement,
parseNearby,
enrichStation,
parsePolyline,
parseOperator,
parseRemark,
parseRemarks,
parseCancelled,
parseStopover,
parseLoadFactor,
parseArrOrDepWithLoadFactor,
parseHintByCode,
parsePrice,
parseTickets,
parseStop: notImplemented,
formatAddress,
formatCoord,
formatDate,
formatLocationFilter,
formatLocation,
formatLocationFilter: notImplemented,
formatLoyaltyCard,
formatPoi,
formatProductsFilter,
formatStation,
formatTime,
formatLocation,
formatRectangle,
filters,
formatTimeOfDay,
formatTransfers,
formatTravellers,
formatRectangle: id,
journeysNumF: true, // `journeys()` method: support for `numF` field?
journeyLeg: false,
radar: false
}
journeysOutFrwd: true,
departuresGetPasslist: false,
departuresStbFltrEquiv: true,
trip: true,
radar: false,
refreshJourney: true,
journeysFromTrip: false,
refreshJourneyUseOutReconL: false,
tripsByName: false,
remarks: false,
remarksGetPolyline: false,
reachableFrom: false,
lines: false,
};
module.exports = defaultProfile
export {
defaultProfile,
};

302
lib/errors.js Normal file
View file

@ -0,0 +1,302 @@
const ACCESS_DENIED = 'ACCESS_DENIED';
const INVALID_REQUEST = 'INVALID_REQUEST';
const NOT_FOUND = 'NOT_FOUND';
const SERVER_ERROR = 'SERVER_ERROR';
class HafasError extends Error {
constructor (cleanMessage, hafasCode, props) {
const msg = hafasCode
? hafasCode + ': ' + cleanMessage
: cleanMessage;
super(msg);
// generic props
this.isHafasError = true;
// error-specific props
this.code = null;
// By default, we take the blame, unless we know for sure.
this.isCausedByServer = false;
this.hafasCode = hafasCode;
Object.assign(this, props);
return this;
}
}
class HafasAccessDeniedError extends HafasError {
constructor (cleanMessage, hafasCode, props) {
super(cleanMessage, hafasCode, props);
this.code = ACCESS_DENIED;
return this;
}
}
class HafasInvalidRequestError extends HafasError {
constructor (cleanMessage, hafasCode, props) {
super(cleanMessage, hafasCode, props);
this.code = INVALID_REQUEST;
return this;
}
}
class HafasNotFoundError extends HafasError {
constructor (cleanMessage, hafasCode, props) {
super(cleanMessage, hafasCode, props);
this.code = NOT_FOUND;
return this;
}
}
class HafasServerError extends HafasError {
constructor (cleanMessage, hafasCode, props) {
super(cleanMessage, hafasCode, props);
this.code = SERVER_ERROR;
this.isCausedByServer = true;
return this;
}
}
const byErrorCode = Object.assign(Object.create(null), {
H_UNKNOWN: {
Error: HafasError,
message: 'unknown internal error',
props: {
shouldRetry: true,
},
},
AUTH: {
Error: HafasAccessDeniedError,
message: 'invalid or missing authentication data',
props: {
},
},
METHOD_NA: {
Error: HafasServerError,
message: 'method is not enabled',
props: {
},
},
R0001: {
Error: HafasInvalidRequestError,
message: 'unknown method',
props: {
},
},
R0002: {
Error: HafasInvalidRequestError,
message: 'invalid or missing request parameters',
props: {
},
},
R0007: {
Error: HafasServerError,
message: 'internal communication error',
props: {
shouldRetry: true,
},
},
R5000: {
Error: HafasAccessDeniedError,
message: 'access denied',
props: {
},
},
S1: {
Error: HafasServerError,
message: 'journeys search: a connection to the backend server couldn\'t be established',
props: {
shouldRetry: true,
},
},
PROBLEMS: {
Error: HafasServerError,
message: 'an unknown problem occurred during search',
props: {
shouldRetry: true,
},
},
LOCATION: {
Error: HafasNotFoundError,
message: 'location/stop not found',
props: {
},
},
NO_MATCH: {
Error: HafasNotFoundError,
message: 'no results found',
props: {
},
},
PARAMETER: {
Error: HafasInvalidRequestError,
message: 'invalid parameter',
props: {
},
},
H390: {
Error: HafasInvalidRequestError,
message: 'journeys search: departure/arrival station replaced',
props: {
},
},
H410: {
// todo: or is it a client error?
Error: HafasServerError,
message: 'journeys search: incomplete response due to timetable change',
props: {
},
},
H455: {
Error: HafasInvalidRequestError,
message: 'journeys search: prolonged stop',
props: {
},
},
H460: {
Error: HafasInvalidRequestError,
message: 'journeys search: stop(s) passed multiple times',
props: {
},
},
H500: {
Error: HafasInvalidRequestError,
message: 'journeys search: too many trains, connection is not complete',
props: {
},
},
H890: {
Error: HafasNotFoundError,
message: 'journeys search unsuccessful',
props: {
shouldRetry: true,
},
},
H891: {
Error: HafasNotFoundError,
message: 'journeys search: no route found, try with an intermediate stations',
props: {
},
},
H892: {
Error: HafasInvalidRequestError,
message: 'journeys search: query too complex, try less intermediate stations',
props: {
},
},
H895: {
Error: HafasInvalidRequestError,
message: 'journeys search: departure & arrival are too near',
props: {
},
},
H899: {
// todo: or is it a client error?
Error: HafasServerError,
message: 'journeys search unsuccessful or incomplete due to timetable change',
props: {
},
},
H900: {
// todo: or is it a client error?
Error: HafasServerError,
message: 'journeys search unsuccessful or incomplete due to timetable change',
props: {
},
},
H9220: {
Error: HafasNotFoundError,
message: 'journeys search: no stations found close to the address',
props: {
},
},
H9230: {
Error: HafasServerError,
message: 'journeys search: an internal error occurred',
props: {
shouldRetry: true,
},
},
H9240: {
Error: HafasNotFoundError,
message: 'journeys search unsuccessful',
props: {
shouldRetry: true,
},
},
H9250: {
Error: HafasServerError,
message: 'journeys search: leg query interrupted',
props: {
shouldRetry: true,
},
},
H9260: {
Error: HafasInvalidRequestError,
message: 'journeys search: unknown departure station',
props: {
},
},
H9280: {
Error: HafasInvalidRequestError,
message: 'journeys search: unknown intermediate station',
props: {
},
},
H9300: {
Error: HafasInvalidRequestError,
message: 'journeys search: unknown arrival station',
props: {
},
},
H9320: {
Error: HafasInvalidRequestError,
message: 'journeys search: the input is incorrect or incomplete',
props: {
},
},
H9360: {
Error: HafasInvalidRequestError,
message: 'journeys search: invalid date/time',
props: {
},
},
H9380: {
Error: HafasInvalidRequestError,
message: 'journeys search: departure/arrival/intermediate station defined more than once',
props: {
},
},
SQ001: {
Error: HafasServerError,
message: 'no departures/arrivals data available',
props: {
},
},
SQ005: {
Error: HafasNotFoundError,
message: 'no trips found',
props: {
},
},
TI001: {
Error: HafasServerError,
message: 'no trip info available',
props: {
shouldRetry: true,
},
},
});
export {
ACCESS_DENIED,
INVALID_REQUEST,
NOT_FOUND,
SERVER_ERROR,
HafasError,
HafasAccessDeniedError,
HafasInvalidRequestError,
HafasNotFoundError,
HafasServerError,
byErrorCode,
};

6
lib/luxon-timezones.js Normal file
View file

@ -0,0 +1,6 @@
// hafas-client profile -> luxon.IANAZone
const luxonIANAZonesByProfile = new WeakMap();
export {
luxonIANAZonesByProfile,
};

136
lib/products.js Normal file
View file

@ -0,0 +1,136 @@
const products = [
{
id: 'nationalExpress',
mode: 'train',
bitmasks: [1],
name: 'InterCityExpress',
short: 'ICE',
vendo: 'ICE',
ris: 'HIGH_SPEED_TRAIN',
ris_alt: 'HIGH_SPEED_TRAIN',
dbnav: 'HOCHGESCHWINDIGKEITSZUEGE',
dbnav_short: 'ICE',
default: true,
},
{
id: 'national',
mode: 'train',
bitmasks: [2],
name: 'InterCity & EuroCity',
short: 'IC/EC',
vendo: 'EC_IC',
ris: 'INTERCITY_TRAIN',
ris_alt: 'INTERCITY_TRAIN',
dbnav: 'INTERCITYUNDEUROCITYZUEGE',
dbnav_short: 'IC_EC',
default: true,
},
{
id: 'regionalExpress',
mode: 'train',
bitmasks: [4],
name: 'RegionalExpress & InterRegio', // FlixTrain??
short: 'RE/IR',
vendo: 'IR',
ris: 'INTER_REGIONAL_TRAIN',
ris_alt: 'INTER_REGIONAL_TRAIN',
dbnav: 'INTERREGIOUNDSCHNELLZUEGE',
dbnav_short: 'IR',
default: true,
},
{
id: 'regional',
mode: 'train',
bitmasks: [8],
name: 'Regio',
short: 'RB',
vendo: 'REGIONAL',
ris: 'REGIONAL_TRAIN',
ris_alt: 'REGIONAL_TRAIN',
dbnav: 'NAHVERKEHRSONSTIGEZUEGE',
dbnav_short: 'RB',
default: true,
},
{
id: 'suburban',
mode: 'train',
bitmasks: [16],
name: 'S-Bahn',
short: 'S',
vendo: 'SBAHN',
ris: 'CITY_TRAIN',
ris_alt: 'CITY_TRAIN',
dbnav: 'SBAHNEN',
dbnav_short: 'SBAHN',
default: true,
},
{
id: 'bus',
mode: 'bus',
bitmasks: [32],
name: 'Bus',
short: 'B',
vendo: 'BUS',
ris: 'BUS',
ris_alt: 'BUS',
dbnav: 'BUSSE',
dbnav_short: 'BUS',
default: true,
},
{
id: 'ferry',
mode: 'watercraft',
bitmasks: [64],
name: 'Ferry',
short: 'F',
vendo: 'SCHIFF',
ris: 'FERRY',
ris_alt: 'FERRY',
dbnav: 'SCHIFFE',
dbnav_short: 'SCHIFF',
default: true,
},
{
id: 'subway',
mode: 'train',
bitmasks: [128],
name: 'U-Bahn',
short: 'U',
vendo: 'UBAHN',
ris: 'SUBWAY',
ris_alt: 'SUBWAY',
dbnav: 'UBAHN',
dbnav_short: 'UBAHN',
default: true,
},
{
id: 'tram',
mode: 'train',
bitmasks: [256],
name: 'Tram',
short: 'T',
vendo: 'TRAM',
ris: 'TRAM',
ris_alt: 'TRAM',
dbnav: 'STRASSENBAHN',
dbnav_short: 'STR',
default: true,
},
{
id: 'taxi',
mode: 'taxi',
bitmasks: [512],
name: 'Group Taxi',
short: 'Taxi',
vendo: 'ANRUFPFLICHTIG',
ris: 'TAXI',
ris_alt: 'SHUTTLE',
dbnav: 'ANRUFPFLICHTIGEVERKEHRE',
dbnav_short: 'ANRUFPFLICHTIGEVERKEHRE',
default: true,
},
];
export {
products,
};

View file

@ -1,101 +1,155 @@
'use strict'
import {stringify} from 'qs';
import {Request, fetch} from 'cross-fetch';
import {parse as parseContentType} from 'content-type';
import {HafasError} from './errors.js';
const crypto = require('crypto')
let captureStackTrace = () => {}
if (process.env.NODE_ENV === 'dev') {
captureStackTrace = require('capture-stack-trace')
}
const {stringify} = require('query-string')
const Promise = require('pinkie-promise')
const {fetch} = require('fetch-ponyfill')({Promise})
const proxyAddress = typeof process !== 'undefined' && (process.env.HTTPS_PROXY || process.env.HTTP_PROXY) || null;
const md5 = input => crypto.createHash('md5').update(input).digest()
let getAgent = () => undefined;
const request = (profile, data) => {
const body = profile.transformReqBody({lang: 'en', svcReqL: [data]})
const req = profile.transformReq({
method: 'post',
const setupProxy = async () => {
if (proxyAddress && !getAgent()) {
const a = await import('https-proxy-agent');
const agent = new a.default.HttpsProxyAgent(proxyAddress, {
keepAlive: true,
keepAliveMsecs: 10 * 1000, // 10s
});
getAgent = () => agent;
}
};
const randomBytesHexString = length => [...Array(length)].map(() => Math.floor(Math.random() * 16)
.toString(16))
.join('');
const id = randomBytesHexString(6)
.toString('hex');
const randomizeUserAgent = (userAgent) => {
let ua = userAgent;
for (
let i = Math.round(5 + Math.random() * 5);
i < ua.length;
i += Math.round(5 + Math.random() * 5)
) {
ua = ua.slice(0, i) + id + ua.slice(i);
i += id.length;
}
return ua;
};
const checkIfResponseIsOk = (_) => {
const {
body,
errProps: baseErrProps,
} = _;
const errProps = {
...baseErrProps,
};
if (body.id) {
errProps.hafasResponseId = body.id;
}
// Because we want more accurate stack traces, we don't construct the error here,
// but only return the constructor & error message.
const getError = (_) => {
// mutating here is ugly but pragmatic
if (_.fehlerNachricht.ueberschrift) {
errProps.hafasMessage = _.fehlerNachricht.ueberschrift;
}
if (_.fehlerNachricht.text) {
errProps.hafasDescription = _.fehlerNachricht.text;
}
return {
Error: HafasError,
message: errProps.hafasMessage || 'unknown error',
props: {code: _.fehlerNachricht.code},
};
};
if (body.fehlerNachricht || body.errors) { // TODO better handling
const {Error: HafasError, message, props} = getError(body);
throw new HafasError(message, body.err || body.errors, {...errProps, ...props});
}
};
const request = async (ctx, userAgent, reqData) => {
const {profile, opt} = ctx;
await setupProxy();
const endpoint = reqData.endpoint;
delete reqData.endpoint;
const rawReqBody = profile.transformReqBody(ctx, reqData.body);
const reqOptions = profile.transformReq(ctx, {
agent: getAgent(),
keepalive: true,
method: reqData.method,
// todo: CORS? referrer policy?
body: JSON.stringify(body),
body: JSON.stringify(rawReqBody),
headers: {
'Content-Type': 'application/json',
'Accept-Encoding': 'gzip, deflate',
'user-agent': 'https://github.com/derhuerst/hafas-client'
'Accept-Encoding': 'gzip, br, deflate',
'Accept': 'application/json',
'Accept-Language': opt.language || profile.defaultLanguage || 'en',
'user-agent': profile.randomizeUserAgent
? randomizeUserAgent(userAgent)
: userAgent,
...reqData.headers,
},
query: {}
})
redirect: 'follow',
query: reqData.query,
});
if (profile.addChecksum || profile.addMicMac) {
if (!Buffer.isBuffer(profile.salt)) {
throw new Error('profile.salt must be a Buffer.')
}
if (profile.addChecksum) {
const checksum = md5(Buffer.concat([
Buffer.from(req.body, 'utf8'),
profile.salt
]))
req.query.checksum = checksum.toString('hex')
}
if (profile.addMicMac) {
const mic = md5(Buffer.from(req.body, 'utf8'))
req.query.mic = mic.toString('hex')
let url = endpoint + (reqData.path || '');
if (reqOptions.query) {
url += '?' + stringify(reqOptions.query, {arrayFormat: 'brackets', encodeValuesOnly: true});
}
const reqId = randomBytesHexString(6);
const fetchReq = new Request(url, reqOptions);
profile.logRequest(ctx, fetchReq, reqId);
const micAsHex = Buffer.from(mic.toString('hex'), 'utf8')
const mac = md5(Buffer.concat([micAsHex, profile.salt]))
req.query.mac = mac.toString('hex')
const res = await fetch(url, reqOptions);
const errProps = {
// todo [breaking]: assign as non-enumerable property
request: fetchReq,
// todo [breaking]: assign as non-enumerable property
response: res,
url,
};
if (!res.ok) {
// todo [breaking]: make this a FetchError or a HafasClientError?
console.log(JSON.stringify(res), await res.text());
const err = new Error(res.statusText);
Object.assign(err, errProps);
throw err;
}
let cType = res.headers.get('content-type');
if (cType) {
const {type} = parseContentType(cType);
if (type !== reqOptions.headers['Accept']) {
throw new HafasError('invalid/unsupported response content-type: ' + cType, null, errProps);
}
}
const url = profile.endpoint + '?' + stringify(req.query)
const body = await res.text();
profile.logResponse(ctx, res, body, reqId);
// Async stack traces are not supported everywhere yet, so we create our own.
const err = new Error()
err.isHafasError = true
err.request = body
err.url = url
captureStackTrace(err)
const b = JSON.parse(body);
checkIfResponseIsOk({
body: b,
errProps,
});
return {
res: b,
common: {},
};
};
return fetch(url, req)
.then((res) => {
err.statusCode = res.status
if (!res.ok) {
err.message = res.statusText
throw err
}
return res.json()
})
.then((b) => {
if (b.err) {
err.message = b.err
throw err
}
if (!b.svcResL || !b.svcResL[0]) {
err.message = 'invalid response'
throw err
}
if (b.svcResL[0].err !== 'OK') {
err.message = b.svcResL[0].errTxt || b.svcResL[0].err
throw err
}
const d = b.svcResL[0].res
const c = d.common || {}
if (Array.isArray(c.remL)) {
d.remarks = c.remL.map(rem => profile.parseRemark(profile, rem))
}
if (Array.isArray(c.opL)) {
d.operators = c.opL.map(op => profile.parseOperator(profile, op))
}
if (Array.isArray(c.prodL)) {
const parse = profile.parseLine(profile, d.operators)
d.lines = c.prodL.map(parse)
}
if (Array.isArray(c.locL)) {
const parse = loc => profile.parseLocation(profile, loc, d.lines)
d.locations = c.locL.map(parse)
}
return d
})
}
module.exports = request
export {
checkIfResponseIsOk,
request,
};

Some files were not shown because too many files have changed in this diff Show more