UNPKG

tfl-ts

Version:

🚇 Fully-typed TypeScript client for Transport for London (TfL) API • Zero dependencies • Auto-generated types • Real-time arrivals • Journey planning • Universal compatibility

236 lines (235 loc) • 12.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.findClosestWithBikes = exports.sortByDistance = exports.findElectricBikes = exports.getPropertyValue = exports.LINE_ORDER = exports.SEVERITY_MAPPING = exports.LINE_COLORS = exports.getLineDisplayName = exports.getLineAriaLabel = exports.hasNightService = exports.isNormalService = exports.getLineStatusSummary = exports.sortLinesBySeverityAndOrder = exports.getAccessibleSeverityLabel = exports.getSeverityClasses = exports.getSeverityCategory = exports.getLineCssProps = exports.getLineColor = exports.TflErrorHandler = exports.TflConfigError = exports.TflTimeoutError = exports.TflValidationError = exports.TflNetworkError = exports.TflHttpError = exports.TflError = exports.severityDescriptions = exports.severityByMode = exports.DIRECTIONS = exports.SERVICE_TYPES = exports.MODES = exports.LINE_IDS = void 0; const tfl_1 = require("./generated/tfl"); const line_1 = require("./line"); const accidentStats_1 = require("./accidentStats"); const airQuality_1 = require("./airQuality"); const bikePoint_1 = require("./bikePoint"); const cabwise_1 = require("./cabwise"); const journey_1 = require("./journey"); const stopPoint_1 = require("./stopPoint"); const mode_1 = require("./mode"); const road_1 = require("./road"); const Meta_1 = require("./generated/meta/Meta"); const Line_1 = require("./generated/meta/Line"); const errors_1 = require("./errors"); Object.defineProperty(exports, "TflError", { enumerable: true, get: function () { return errors_1.TflError; } }); Object.defineProperty(exports, "TflHttpError", { enumerable: true, get: function () { return errors_1.TflHttpError; } }); Object.defineProperty(exports, "TflNetworkError", { enumerable: true, get: function () { return errors_1.TflNetworkError; } }); Object.defineProperty(exports, "TflValidationError", { enumerable: true, get: function () { return errors_1.TflValidationError; } }); Object.defineProperty(exports, "TflTimeoutError", { enumerable: true, get: function () { return errors_1.TflTimeoutError; } }); Object.defineProperty(exports, "TflConfigError", { enumerable: true, get: function () { return errors_1.TflConfigError; } }); Object.defineProperty(exports, "TflErrorHandler", { enumerable: true, get: function () { return errors_1.TflErrorHandler; } }); // Create mode metadata from the generated Modes data const modeMetadata = Meta_1.Modes.reduce((acc, mode) => { acc[mode.modeName] = { isTflService: mode.isTflService, isFarePaying: mode.isFarePaying, isScheduledService: mode.isScheduledService }; return acc; }, {}); // Build line IDs from generated Lines data const buildLineIds = () => { const lineIds = { tube: {}, dlr: {}, overground: {}, tram: {}, bus: {} }; Line_1.Lines.forEach(line => { const modeName = line.modeName; if (modeName === 'tube') { lineIds.tube[line.name.toUpperCase()] = line.id; } else if (modeName === 'dlr') { lineIds.dlr[line.name.toUpperCase()] = line.id; } else if (modeName === 'overground') { lineIds.overground[line.name.toUpperCase()] = line.id; } else if (modeName === 'tram') { lineIds.tram[line.name.toUpperCase()] = line.id; } else if (modeName === 'bus') { lineIds.bus[line.name.toUpperCase()] = line.id; } }); return lineIds; }; // Build severity by mode from generated Severity data const buildSeverityByMode = () => { const severityMap = {}; Meta_1.Severity.forEach(severity => { if (!severityMap[severity.modeName]) { severityMap[severity.modeName] = []; } severityMap[severity.modeName].push({ level: severity.severityLevel, description: severity.description }); }); return severityMap; }; // Build severity descriptions from generated Severity data const buildSeverityDescriptions = () => { const descriptions = new Set(); Meta_1.Severity.forEach(severity => { descriptions.add(severity.description); }); return Array.from(descriptions).sort(); }; // Tfl Line IDs - built from generated data const LINE_IDS = buildLineIds(); exports.LINE_IDS = LINE_IDS; // Tfl Transport Modes - from generated data const MODES = modeMetadata; exports.MODES = MODES; // Tfl Service Types - from generated data const SERVICE_TYPES = { REGULAR: 'Regular', NIGHT: 'Night' }; exports.SERVICE_TYPES = SERVICE_TYPES; // Tfl Direction Types const DIRECTIONS = { INBOUND: 'inbound', OUTBOUND: 'outbound', ALL: 'all' }; exports.DIRECTIONS = DIRECTIONS; // Build severity by mode and descriptions const severityByMode = buildSeverityByMode(); exports.severityByMode = severityByMode; const severityDescriptions = buildSeverityDescriptions(); exports.severityDescriptions = severityDescriptions; class TflClient { constructor(config) { /** * Generate a unique request ID for tracking */ this.generateRequestId = () => { return `tfl_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; }; const appId = config?.appId || process.env.TFL_APP_ID; const appKey = config?.appKey || process.env.TFL_APP_KEY; if (!appId || !appKey) { throw new errors_1.TflConfigError("Missing TFL API credentials. Please either:\n" + "1. Create a .env file in the root directory with:\n" + " TFL_APP_ID=your-app-id\n" + " TFL_APP_KEY=your-app-key\n" + "2. Or pass the credentials directly:\n" + " new TflClient({ appId: 'your-app-id', appKey: 'your-app-key' })\n" + "You can get these credentials by registering at https://api-portal.tfl.gov.uk/", 'credentials'); } this.config = { appId, appKey, timeout: config?.timeout || 30000, maxRetries: config?.maxRetries || 3, retryDelay: config?.retryDelay || 1000 }; this.api = new tfl_1.Api({ baseUrl: "https://api.tfl.gov.uk", customFetch: (input, init) => { const url = new URL(input.toString()); url.searchParams.set("app_id", this.config.appId); url.searchParams.set("app_key", this.config.appKey); // Add timeout to the request const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.config.timeout); return fetch(url, { ...init, signal: controller.signal }).finally(() => clearTimeout(timeoutId)); } }); // Initialize core transport services this.line = new line_1.Line(this.api); this.stopPoint = new stopPoint_1.StopPoint(this.api); this.journey = new journey_1.Journey(this.api); this.mode = new mode_1.Mode(this.api); this.road = new road_1.Road(this.api); this.bikePoint = new bikePoint_1.BikePoint(this.api); // Initialize additional services this.accidentStats = new accidentStats_1.AccidentStats(this.api); this.airQuality = new airQuality_1.AirQuality(this.api); this.cabwise = new cabwise_1.Cabwise(this.api); } /** * Execute an API call with error handling and retry logic */ async executeWithRetry(apiCall, _context) { const requestId = this.generateRequestId(); let lastError; for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) { try { return await apiCall(); } catch (error) { const tflError = errors_1.TflErrorHandler.handleApiError(error, undefined, requestId); lastError = tflError; // Don't retry on the last attempt if (attempt === this.config.maxRetries) { break; } // Check if error is retryable if (!errors_1.TflErrorHandler.isRetryableError(tflError)) { break; } // Calculate retry delay const delay = errors_1.TflErrorHandler.getRetryDelay(tflError, attempt, this.config.retryDelay); // Wait before retrying await new Promise(resolve => setTimeout(resolve, delay)); } } throw lastError; } /** * Get client configuration */ getConfig() { return this.config; } } exports.default = TflClient; // Export UI utilities for building user interfaces __exportStar(require("./utils/ui"), exports); // Explicitly export key UI functions for better documentation clarity var ui_1 = require("./utils/ui"); Object.defineProperty(exports, "getLineColor", { enumerable: true, get: function () { return ui_1.getLineColor; } }); Object.defineProperty(exports, "getLineCssProps", { enumerable: true, get: function () { return ui_1.getLineCssProps; } }); Object.defineProperty(exports, "getSeverityCategory", { enumerable: true, get: function () { return ui_1.getSeverityCategory; } }); Object.defineProperty(exports, "getSeverityClasses", { enumerable: true, get: function () { return ui_1.getSeverityClasses; } }); Object.defineProperty(exports, "getAccessibleSeverityLabel", { enumerable: true, get: function () { return ui_1.getAccessibleSeverityLabel; } }); Object.defineProperty(exports, "sortLinesBySeverityAndOrder", { enumerable: true, get: function () { return ui_1.sortLinesBySeverityAndOrder; } }); Object.defineProperty(exports, "getLineStatusSummary", { enumerable: true, get: function () { return ui_1.getLineStatusSummary; } }); Object.defineProperty(exports, "isNormalService", { enumerable: true, get: function () { return ui_1.isNormalService; } }); Object.defineProperty(exports, "hasNightService", { enumerable: true, get: function () { return ui_1.hasNightService; } }); Object.defineProperty(exports, "getLineAriaLabel", { enumerable: true, get: function () { return ui_1.getLineAriaLabel; } }); Object.defineProperty(exports, "getLineDisplayName", { enumerable: true, get: function () { return ui_1.getLineDisplayName; } }); Object.defineProperty(exports, "LINE_COLORS", { enumerable: true, get: function () { return ui_1.LINE_COLORS; } }); Object.defineProperty(exports, "SEVERITY_MAPPING", { enumerable: true, get: function () { return ui_1.SEVERITY_MAPPING; } }); Object.defineProperty(exports, "LINE_ORDER", { enumerable: true, get: function () { return ui_1.LINE_ORDER; } }); // Export bike point utilities for working with bike point data var bikePoint_2 = require("./utils/bikePoint"); Object.defineProperty(exports, "getPropertyValue", { enumerable: true, get: function () { return bikePoint_2.getPropertyValue; } }); Object.defineProperty(exports, "findElectricBikes", { enumerable: true, get: function () { return bikePoint_2.findElectricBikes; } }); Object.defineProperty(exports, "sortByDistance", { enumerable: true, get: function () { return bikePoint_2.sortByDistance; } }); Object.defineProperty(exports, "findClosestWithBikes", { enumerable: true, get: function () { return bikePoint_2.findClosestWithBikes; } });