├── .editorconfig ├── .eslintrc.json ├── .github └── workflows │ └── test.yml ├── .gitignore ├── example.js ├── index.js ├── license.md ├── package.json ├── readme.md ├── retry.js └── throttle.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | # Use tabs in JavaScript and JSON. 11 | [**.{js, json}] 12 | indent_style = tab 13 | indent_size = 4 14 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "es2022": true, 5 | "node": true 6 | }, 7 | "parserOptions": { 8 | "sourceType": "module" 9 | }, 10 | "ignorePatterns": [ 11 | "node_modules" 12 | ], 13 | "rules": { 14 | "no-unused-vars": [ 15 | "error", 16 | { 17 | "vars": "all", 18 | "args": "none", 19 | "ignoreRestSiblings": false 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: lint & test 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | pull_request: 8 | branches: 9 | - '*' 10 | 11 | jobs: 12 | lint-test: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | node-version: ['18'] 17 | 18 | steps: 19 | - name: checkout 20 | uses: actions/checkout@v3 21 | - name: setup Node v${{ matrix.node-version }} 22 | uses: actions/setup-node@v3 23 | with: 24 | node-version: ${{ matrix.node-version }} 25 | - run: npm install 26 | 27 | - run: npm run lint 28 | - run: npm test 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Thumbs.db 3 | 4 | .nvm-version 5 | node_modules 6 | npm-debug.log 7 | pnpm-debug.log 8 | 9 | /package-lock.json 10 | /shrinkwrap.yaml 11 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | import {inspect} from 'node:util' 2 | import {createBvgHafas as createHafas} from './index.js' 3 | // import {createThrottledHafas} from './throttle.js' 4 | // import {createRetryingClient} from './retry.js' 5 | 6 | const hafas = createHafas('bvg-hafas-example') 7 | // const hafas = createThrottledHafas('bvg-hafas-example', { 8 | // throttlingLimit: 5, 9 | // throttlingInterval: 10000 // 10s 10 | // }) 11 | // const hafas = createRetryingClient('bvg-hafas-example', { 12 | // retryOpts: {retries: 2} 13 | // }) 14 | 15 | const spichernstr = '900042101' 16 | const bismarckstr = '900024201' 17 | 18 | // let data = await hafas.locations('Alexanderplatz', {results: 2}) 19 | // let data = await hafas.nearby(52.5137344, 13.4744798, {distance: 60}) 20 | // let data = await hafas.stop(bismarckstr) 21 | // let data = await hafas.departures(spichernstr, {duration: 1}) 22 | 23 | let data = await hafas.journeys(spichernstr, bismarckstr, { 24 | results: 1, 25 | tickets: true, 26 | stopovers: true, 27 | transferInfo: true 28 | }) 29 | // let data = await hafas.journeys({ 30 | // type: 'location', 31 | // id: '900981377', 32 | // name: 'Berlin, HTW-Berlin Campus Wilhelminenhof', 33 | // latitude: 52.458359, 34 | // longitude: 13.526635 35 | // }, '900000192001', {results: 1}) 36 | // { 37 | // const [journey] = data.journeys 38 | // data = await hafas.refreshJourney(journey.refreshToken, { 39 | // stopovers: true, 40 | // transferInfo: true, 41 | // }) 42 | // } 43 | // { 44 | // const [journey] = data.journeys 45 | // const leg = journey.legs[0] 46 | // data = await hafas.trip(leg.tripId, leg.line.name, {polyline: true}) 47 | // } 48 | 49 | // let data = await hafas.radar({ 50 | // north: 52.52411, 51 | // west: 13.41002, 52 | // south: 52.51942, 53 | // east: 13.41709 54 | // }, {results: 10}) 55 | 56 | console.log(inspect(data, {depth: null, colors: true})) 57 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import {createClient} from 'hafas-client' 2 | import {profile as bvgProfile} from 'hafas-client/p/bvg/index.js' 3 | 4 | const defaults = { 5 | profile: bvgProfile 6 | } 7 | 8 | const createBvgHafas = (userAgent, opt = {}) => { 9 | const { 10 | profile, 11 | } = {...defaults, ...opt} 12 | 13 | return createClient(profile, userAgent) 14 | } 15 | 16 | export { 17 | defaults, 18 | createBvgHafas, 19 | } 20 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022, Jannis R 2 | 3 | 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. 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bvg-hafas", 3 | "description": "JavaScript client for the BVG HAFAS API.", 4 | "version": "4.0.0", 5 | "type": "module", 6 | "main": "index.js", 7 | "files": [ 8 | "index.js", 9 | "throttle.js", 10 | "retry.js" 11 | ], 12 | "keywords": [ 13 | "bvg", 14 | "vbb", 15 | "berliner verkehrsbetriebe", 16 | "berlin", 17 | "germany", 18 | "public transport", 19 | "transit", 20 | "hafas", 21 | "hafas-client" 22 | ], 23 | "author": "Jannis R ", 24 | "homepage": "https://github.com/public-transport/bvg-hafas/tree/4", 25 | "repository": "public-transport/bvg-hafas", 26 | "bugs": "https://github.com/public-transport/bvg-hafas/issues", 27 | "license": "ISC", 28 | "engines": { 29 | "node": ">=18" 30 | }, 31 | "dependencies": { 32 | "hafas-client": "^6.0.1" 33 | }, 34 | "devDependencies": { 35 | "eslint": "^8.30.0" 36 | }, 37 | "scripts": { 38 | "lint": "eslint .", 39 | "smoke-test": "node example.js >/dev/null", 40 | "prepublishOnly": "npm run lint && npm run smoke-test" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # bvg-hafas 2 | 3 | **A client for the [HAFAS](https://de.wikipedia.org/wiki/HAFAS) endpoint of [*Berliner Verkehrsbetriebe* (BVG)](https://en.wikipedia.org/wiki/Berliner_Verkehrsbetriebe), the largest public transport provider in Berlin.** It acts as a consistent and straightforward interface on top of their verbose API. 4 | 5 | This project is actually a thin wrapper around [`hafas-client@6`](https://github.com/public-transport/hafas-client/tree/6#hafas-client). [Its docs](https://github.com/public-transport/hafas-client/tree/6/docs) document the API in general. 6 | 7 | *Note*: The BVG HAFAS endpoint covers Brandenburg as well. 8 | 9 | [![npm version](https://img.shields.io/npm/v/bvg-hafas.svg)](https://www.npmjs.com/package/bvg-hafas) 10 | ![ISC-licensed](https://img.shields.io/github/license/public-transport/bvg-hafas.svg) 11 | [![support Jannis via GitHub Sponsors](https://img.shields.io/badge/support%20Jannis-donate-fa7664.svg)](https://github.com/sponsors/derhuerst) 12 | [![chat with Jannis on Twitter](https://img.shields.io/badge/chat%20with%20Jannis-on%20Twitter-1da1f2.svg)](https://twitter.com/derhuerst) 13 | 14 | 15 | ## Installing 16 | 17 | ```shell 18 | npm install bvg-hafas 19 | ``` 20 | 21 | 22 | ## API 23 | 24 | Check [the docs for `hafas-client@6`](https://github.com/public-transport/hafas-client/tree/6/docs) as well as [its BVG-specific customisations](https://github.com/public-transport/hafas-client/tree/6/p/bvg). 25 | 26 | 27 | ## Usage 28 | 29 | ```javascript 30 | import {createBvgHafas} from 'bvg-hafas' 31 | 32 | const client = createBvgHafas('my-awesome-program') 33 | ``` 34 | 35 | As an example, we will search for a route from *Berlin Jungfernheide* to *Tempelhof*. To get the station IDs, use [`locations(query, [opt])`](https://github.com/public-transport/hafas-client/blob/6/docs/locations.md). 36 | 37 | ```javascript 38 | const journeys = await client.journeys('900020201', '900068201', { 39 | results: 1, 40 | }) 41 | console.log(journeys[0]) 42 | ``` 43 | 44 | The output will be an array of [`journey` objects in the *Friendly Public Transport Format* `1.2.1` format](https://github.com/public-transport/friendly-public-transport-format/tree/1.2.1/spec#journey): 45 | 46 | ```javascript 47 | { 48 | type: 'journey', 49 | legs: [ { 50 | id: '1|62072|0|86|14082018', 51 | origin: { 52 | type: 'stop', 53 | id: '900020201', 54 | name: 'S+U Jungfernheide', 55 | location: { 56 | type: 'location', 57 | latitude: 52.530273, 58 | longitude: 13.299064 59 | }, 60 | products: { 61 | suburban: true, 62 | subway: true, 63 | tram: false, 64 | bus: true, 65 | ferry: false, 66 | express: false, 67 | regional: true 68 | } 69 | }, 70 | departure: '2018-08-14T15:05:00.000+02:00', 71 | departurePlatform: '6', 72 | departureDelay: 0, 73 | destination: { 74 | type: 'stop', 75 | id: '900068201', 76 | name: 'S+U Tempelhof', 77 | location: { 78 | type: 'location', 79 | latitude: 52.470692, 80 | longitude: 13.385756 81 | }, 82 | products: { /* … */ } 83 | }, 84 | arrival: '2018-08-14T15:27:00.000+02:00', 85 | arrivalPlatform: '2', 86 | arrivalDelay: 0, 87 | direction: 'Ringbahn S 42', 88 | line: { 89 | type: 'line', 90 | id: 's42', 91 | name: 'S42', 92 | public: true, 93 | mode: 'train', 94 | product: 'suburban', 95 | operator: { /* … */ }, 96 | // … 97 | }, 98 | cycle: { min: 300, max: 300 } 99 | } ], 100 | refreshToken: '…' 101 | } 102 | ``` 103 | 104 | 105 | ## Related 106 | 107 | Check [`hafas-client`'s related projects](https://github.com/public-transport/hafas-client/blob/6/readme.md#related-projects). 108 | 109 | 110 | ## Contributing 111 | 112 | If you **have a question**, **found a bug** or want to **propose a feature**, have a look at [the issues page](https://github.com/public-transport/bvg-hafas/issues). 113 | -------------------------------------------------------------------------------- /retry.js: -------------------------------------------------------------------------------- 1 | import {createClient} from 'hafas-client' 2 | import {withRetrying} from 'hafas-client/retry.js' 3 | import {profile as bvgProfile} from 'hafas-client/p/bvg/index.js' 4 | 5 | const createRetryingClient = (userAgent, opt = {}) => { 6 | const {retryOpts} = {retryOpts: {}, ...opt} 7 | 8 | const retryingProfile = withRetrying(bvgProfile, retryOpts) 9 | return createClient(retryingProfile, userAgent, opt) 10 | } 11 | 12 | export { 13 | createRetryingClient, 14 | } 15 | -------------------------------------------------------------------------------- /throttle.js: -------------------------------------------------------------------------------- 1 | import {createClient} from 'hafas-client' 2 | import {withThrottling} from 'hafas-client/throttle.js' 3 | import {profile as bvgProfile} from 'hafas-client/p/bvg/index.js' 4 | 5 | const createThrottledClient = (userAgent, opt = {}) => { 6 | const { 7 | throttlingLimit: limit, 8 | throttlingInterval: interval 9 | } = { 10 | throttlingLimit: 5, 11 | throttlingInterval: 1000, // 1s 12 | ...opt 13 | } 14 | 15 | const throttledProfile = withThrottling(bvgProfile, limit, interval) 16 | return createClient(throttledProfile, userAgent, opt) 17 | } 18 | 19 | export { 20 | createThrottledClient, 21 | } 22 | --------------------------------------------------------------------------------