import { HafasError, byErrorCode } from 'hafas-client/lib/errors.js'; const randomBytesHexString = length => [...Array(length)].map( () => Math.floor(Math.random() * 16).toString(16) ).join('') export const checkIfHafasResponseIsOk = (_) => { 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 (_.errTxt) errProps.hafasMessage = _.errTxt; if (_.errTxtOut) errProps.hafasDescription = _.errTxtOut; if (_.err in byErrorCode) return byErrorCode[_.err]; return { Error: HafasError, message: body.errTxt || 'unknown error', props: {}, }; }; if (body.err && body.err !== 'OK') { const { Error: HafasError, message, props } = getError(body); throw new HafasError(message, body.err, { ...errProps, ...props }); } if (!body.svcResL || !body.svcResL[0]) throw new HafasError('invalid/unsupported response structure', null, errProps); if (body.svcResL[0].err !== 'OK') { const {Error: HafasError, message, props} = getError(body.svcResL[0]); throw new HafasError(message, body.svcResL[0].err, { ...errProps, ...props }); } }, hafasRequest = async (ctx, userAgent, reqData) => { const {profile, opt} = ctx; if (profile.addChecksum) throw new Error('profile.addChecksum set but not implemented!'); if (profile.addMicMac) throw new Error('profile.addMicMac set but not implemented!'); const rawReqBody = profile.transformReqBody(ctx, { // todo: is it `eng` actually? // RSAG has `deu` instead of `de` lang: opt.language || profile.defaultLanguage || 'en', svcReqL: [reqData], client: profile.client, // client identification ext: profile.ext, // ? ver: profile.ver, // HAFAS protocol version auth: profile.auth, // static authentication }), reqId = randomBytesHexString(3).toString('hex'), req = profile.transformReq(ctx, { agent: null, method: 'post', // todo: CORS? referrer policy? body: JSON.stringify(rawReqBody), headers: { 'Content-Type': 'application/json', 'Accept-Encoding': 'gzip, br, deflate', 'Accept': 'application/json', 'user-agent': userAgent, 'connection': 'keep-alive', // prevent excessive re-connecting }, redirect: 'follow', query: {}, }), url = `/hafas/${profile.client.id}?${(new URLSearchParams(req.query)).toString()}`, fetchReq = new Request(url, req), res = await fetch(url, req), 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? const err = new Error(res.statusText); Object.assign(err, errProps); throw err; } let cType = res.headers.get('content-type'); if (!cType.startsWith('application/json')) throw new HafasError('invalid/unsupported response content-type: ' + cType, null, errProps); const body = JSON.parse(await res.text()) checkIfHafasResponseIsOk({ body, errProps }); const svcRes = body.svcResL[0].res; return { res: svcRes, common: profile.parseCommon({...ctx, res: svcRes}), }; };