{"version":3,"file":"divia-api.cjs","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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"}