{"version":3,"file":"divia-api.mjs","names":[],"sources":["../src/api.ts","../src/formatters.ts","../src/index.ts"],"sourcesContent":["function bufferToBase64(buffer: ArrayBuffer | Uint8Array): string {\n  const bytes = new Uint8Array(buffer);\n  let binary = \"\";\n  for (let i = 0; i < bytes.byteLength; i++) {\n    binary += String.fromCharCode(bytes[i]!);\n  }\n  return btoa(binary);\n}\n\nconst originUrl = \"https://nws-main.hove.io\";\nconst clientName = \"divia\";\n\nasync function generateToken(): Promise<string> {\n  const enc = new TextEncoder();\n  const originMaterial = enc.encode(originUrl);\n\n  const baseKey = await crypto.subtle.importKey(\n    \"raw\",\n    originMaterial,\n    \"PBKDF2\",\n    false,\n    [\"deriveKey\"],\n  );\n\n  const salt = enc.encode(\"mon-sel-fixe-ou-dynamique\");\n\n  const aesKey = await crypto.subtle.deriveKey(\n    {\n      name: \"PBKDF2\",\n      salt,\n      iterations: 1e5,\n      hash: \"SHA-256\",\n    },\n    baseKey,\n    { name: \"AES-GCM\", length: 256 },\n    true,\n    [\"encrypt\", \"decrypt\"],\n  );\n\n  const payload = {\n    clientName: clientName,\n    tokenId: crypto.randomUUID(),\n    iat: Math.floor(Date.now() / 1000),\n  };\n\n  const payloadBytes = enc.encode(JSON.stringify(payload));\n\n  const iv = crypto.getRandomValues(new Uint8Array(12));\n\n  const ciphertextBuffer = await crypto.subtle.encrypt(\n    { name: \"AES-GCM\", iv },\n    aesKey,\n    payloadBytes,\n  );\n\n  const base64Iv = bufferToBase64(iv);\n  const base64Ciphertext = bufferToBase64(ciphertextBuffer);\n\n  return `${base64Iv}.${base64Ciphertext}`;\n}\n\nexport async function fetchData({\n  pathname,\n  query = {},\n  referrerUrl,\n}: {\n  pathname: string;\n  query?: Record<string, string>;\n  referrerUrl?: string;\n}): Promise<any> {\n  // Generate token\n  const token = await generateToken();\n\n  // Get presigned URL\n  const res = await fetch(\n    `${originUrl}/api/presign`,\n    {\n      method: \"POST\",\n      headers: {\n        \"Content-Type\": \"application/json\",\n        \"X-Auth\": token,\n        Origin: originUrl,\n      },\n      referrer: referrerUrl || `${originUrl}/standalone/schedules/divia`,\n      body: JSON.stringify({\n        clientName,\n        method: \"POST\",\n        path: pathname,\n        query,\n      }),\n    },\n  ).then((res) => res.json());\n  const { url: presignedUrl } = res as { url: string };\n\n  // Fetch data using presigned URL\n  return await fetch(`${originUrl}/api/proxy`, {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/json\",\n      \"x-auth-token\": token,\n    },\n    body: JSON.stringify({\n      clientName,\n      href: `https://api.navitia.io${pathname}?${new URLSearchParams(query).toString()}`,\n      presignedUrl,\n    }),\n  }).then((res) => res.json());\n}\n","import type { DateTimeObject, DirectionObject, LineObject, RouteObject, ScheduleObject, StopAreaObject, StopPointObject } from \"./types\";\n\nconst timezone = \"Europe/Paris\";\n\nfunction getTimezoneOffset(timeZone: string): number {\n  const now = new Date();\n  const tz = new Intl.DateTimeFormat('en-US', {\n    timeZone,\n    timeZoneName: 'longOffset'\n  }).formatToParts(now);\n\n  const offset = tz.find(p => p.type === 'timeZoneName')!.value;\n\n  const match = offset.match(/GMT([+-]\\d{2}):(\\d{2})/)!;\n  const hours = parseInt(match?.[1] || \"0\", 10);\n  const minutes = parseInt(match?.[2] || \"0\", 10);\n\n  return hours * 60 + Math.sign(hours) * minutes;\n}\n\nfunction formatTimeString(time: string): Date { // \"HHMMSS\"\n  const hours = parseInt(time.substring(0, 2), 10);\n  const minutes = parseInt(time.substring(2, 4), 10);\n  const seconds = parseInt(time.substring(4, 6), 10);\n  const now = new Date();\n  now.setHours(hours, minutes, seconds, 0);\n  return now;\n}\n\nfunction formatDateTimeString(dateTime: string): Date { // \"YYYYMMDDTHHMMSS\"\n  const year = parseInt(dateTime.substring(0, 4), 10);\n  const month = parseInt(dateTime.substring(4, 6), 10) - 1;\n  const day = parseInt(dateTime.substring(6, 8), 10);\n  const hours = parseInt(dateTime.substring(9, 11), 10);\n  const minutes = parseInt(dateTime.substring(11, 13), 10);\n  const seconds = parseInt(dateTime.substring(13, 15), 10);\n  const date = new Date(Date.UTC(year, month, day, hours, minutes, seconds));\n  return new Date(date.getTime() - getTimezoneOffset(timezone) * 60000);\n}\n\nexport function formatLine(line: any): LineObject {\n  return {\n    id: line.id,\n    name: line.name,\n    code: line.code,\n    color: line.color,\n    text_color: line.text_color,\n    codes: line.codes,\n    routes: line.routes.map(formatRoute),\n    opening_time: formatTimeString(line.opening_time),\n    closing_time: formatTimeString(line.closing_time),\n  };\n}\n\nexport function formatRoute(route: any): RouteObject {\n  return {\n    id: route.id,\n    name: route.name,\n    is_frequence: route.is_frequence === \"True\",\n    direction_type: route.direction_type,\n    codes: route.codes,\n    direction: formatDirection(route.direction),\n  };\n}\n\nexport function formatDirection(direction: any): DirectionObject {\n  return {\n    id: direction.id,\n    name: direction.name,\n    quality: direction.quality,\n    stop_area: formatStopArea(direction.stop_area),\n  };\n}\n\nexport function formatStopArea(stopArea: any): StopAreaObject {\n  return {\n    id: stopArea.id,\n    name: stopArea.name,\n    codes: stopArea.codes,\n    timezone: stopArea.timezone,\n    label: stopArea.label,\n    coord: {\n      lon: parseFloat(stopArea.coord.lon),\n      lat: parseFloat(stopArea.coord.lat),\n    },\n  };\n}\n\nexport function formatSchedule(schedule: any): ScheduleObject {\n  return {\n    stop_point: formatStopPoint(schedule.stop_point),\n    route: formatRoute(schedule.route),\n    display_informations: schedule.display_informations,\n    date_times: schedule.date_times.map(formatDateTime),\n    links: schedule.links,\n    first_datetime: formatDateTime(schedule.first_datetime),\n    last_datetime: formatDateTime(schedule.last_datetime),\n  };\n}\n\nexport function formatStopPoint(stopPoint: any): StopPointObject {\n  return {\n    id: stopPoint.id,\n    name: stopPoint.name,\n    codes: stopPoint.codes,\n    label: stopPoint.label,\n    coord: {\n      lon: parseFloat(stopPoint.coord.lon),\n      lat: parseFloat(stopPoint.coord.lat),\n    },\n    stop_area: formatStopArea(stopPoint.stop_area),\n    equipments: stopPoint.equipments,\n    address: stopPoint.address,\n  };\n}\n\nexport function formatDateTime(dateTime: any): DateTimeObject {\n  return {\n    date_time: formatDateTimeString(dateTime.date_time),\n    base_date_time: formatDateTimeString(dateTime.base_date_time),\n    data_freshness: dateTime.data_freshness,\n  };\n}","import { fetchData } from \"./api\";\nimport type { LineObject, ScheduleObject, StopAreaObject } from \"./types\";\nimport { formatLine, formatSchedule, formatStopArea } from \"./formatters\";\n\nexport type { LineObject, StopAreaObject, ScheduleObject } from \"./types\";\n\nasync function listLines(mode: \"bus\" | \"tramway\"): Promise<LineObject[]> {\n  const res = await fetchData({\n    pathname: \"/v1/coverage/fr-ne-dijon/lines\",\n    query: {\n      count: \"300\",\n      disable_geojson: \"true\",\n      filter: `physical_mode.id=physical_mode:${mode.substring(0, 1).toUpperCase() + mode.substring(1)}`,\n    },\n  });\n  return res.lines.map(formatLine);\n}\n\nasync function listStops(lineId: string): Promise<StopAreaObject[]> {\n  const res = await fetchData({\n    pathname: `/v1/coverage/fr-ne-dijon/lines/${lineId}/stop_areas`,\n    query: {\n      count: \"100\",\n      depth: \"3\"\n    },\n  });\n  return res.stop_areas.map(formatStopArea);\n}\n\nasync function getSchedules(lineId: string, stopAreaId: string): Promise<ScheduleObject[]> {\n  const datetime = new Date(Date.now() - new Date().getTimezoneOffset() * 60000);\n  const formattedDatetime = datetime.toISOString().replace(/[^\\dT]/g, \"\").slice(0, -3);\n  const res = await fetchData({\n    pathname: `/v1/coverage/fr-ne-dijon/lines/${lineId}/stop_areas/${stopAreaId}/terminus_schedules`,\n    query: {\n      count: \"10\",\n      data_freshness: \"realtime\",\n      disable_geojson: \"true\",\n      from_datetime: formattedDatetime,\n      items_per_schedule: \"600\"\n    },\n  });\n  return res.terminus_schedules.map(formatSchedule);\n}\n\nexport { listLines, listStops, getSchedules };\n"],"mappings":"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"}