@tmlmobilidade/external 20260604.1643.5 → 20260604.2236.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clients/ml/auth.js +5 -7
- package/dist/clients/ml/curl-fetcher.d.ts +5 -0
- package/dist/clients/ml/curl-fetcher.js +37 -0
- package/dist/clients/ml/index.d.ts +7 -1
- package/dist/clients/ml/index.js +78 -21
- package/dist/clients/ml/types.d.ts +115 -0
- package/dist/clients/ml/types.js +98 -1
- package/dist/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/clients/ml/auth.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* * */
|
|
2
2
|
import { Logger } from '@tmlmobilidade/logger';
|
|
3
3
|
import { asyncSingletonProxy } from '@tmlmobilidade/utils';
|
|
4
|
+
import { curlFetcher } from './curl-fetcher.js';
|
|
4
5
|
/* * */
|
|
5
6
|
export class MLAuthClient {
|
|
6
7
|
//
|
|
@@ -52,20 +53,17 @@ export class MLAuthClient {
|
|
|
52
53
|
// and handle the response, extracting the access token or throwing an error if the request fails.
|
|
53
54
|
const requestBody = new URLSearchParams({
|
|
54
55
|
grant_type: 'password',
|
|
55
|
-
password: process.env.
|
|
56
|
-
username: process.env.
|
|
56
|
+
password: process.env.ML_PASSWORD,
|
|
57
|
+
username: process.env.ML_USERNAME,
|
|
57
58
|
}).toString();
|
|
58
|
-
const
|
|
59
|
+
const data = await curlFetcher(process.env.ML_AUTH_URL, {
|
|
59
60
|
body: requestBody,
|
|
60
61
|
headers: {
|
|
62
|
+
'Authorization': `Basic ${Buffer.from(`${process.env.ML_CLIENT_ID}:${process.env.ML_CLIENT_SECRET}`).toString('base64')}`,
|
|
61
63
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
62
64
|
},
|
|
63
65
|
method: 'POST',
|
|
64
66
|
});
|
|
65
|
-
if (!response.ok) {
|
|
66
|
-
throw new Error(`[MLAuthClient] Token request failed (${response.status}): ${response.statusText}`);
|
|
67
|
-
}
|
|
68
|
-
const data = await response.json();
|
|
69
67
|
//
|
|
70
68
|
// With the response data, set the token and calculate the expiration time
|
|
71
69
|
// based on the current time and the expires_in value from the response.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// ! THIS IS A TEMPORARY FIX FOR THE ML API CERTIFICATE ISSUE
|
|
2
|
+
import { exec } from 'child_process';
|
|
3
|
+
export async function curlFetcher(url, options) {
|
|
4
|
+
const method = options?.method ?? 'GET';
|
|
5
|
+
const headers = options?.headers ?? {};
|
|
6
|
+
const curlArgs = [
|
|
7
|
+
'curl',
|
|
8
|
+
'-sSLf',
|
|
9
|
+
'-X', method,
|
|
10
|
+
...Object.entries(headers).map(([key, value]) => `-H "${key}: ${value}"`),
|
|
11
|
+
];
|
|
12
|
+
if (options?.body !== undefined) {
|
|
13
|
+
const bodyStr = typeof options.body === 'string' ? options.body : JSON.stringify(options.body);
|
|
14
|
+
curlArgs.push('--data-raw', `"${bodyStr}"`);
|
|
15
|
+
}
|
|
16
|
+
curlArgs.push(`"${url}"`);
|
|
17
|
+
const curlCommand = curlArgs.join(' ');
|
|
18
|
+
return await new Promise((resolve, reject) => {
|
|
19
|
+
exec(curlCommand, (error, stdout, stderr) => {
|
|
20
|
+
if (error) {
|
|
21
|
+
console.error(`curl error: ${error.message}`);
|
|
22
|
+
reject(new Error(`curl error: ${error.message}`));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (stderr) {
|
|
26
|
+
console.error(`curl stderr: ${stderr}`);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const data = JSON.parse(stdout);
|
|
30
|
+
resolve(data);
|
|
31
|
+
}
|
|
32
|
+
catch (parseError) {
|
|
33
|
+
reject(new Error(`Failed to parse curl response: ${parseError.message}`));
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ServiceAlertResponse } from '@tmlmobilidade/types';
|
|
1
|
+
import { type GtfsRtFeedMessage, ServiceAlertResponse } from '@tmlmobilidade/types';
|
|
2
2
|
import { BaseResponse, EstadoLinha, InfoEstacao, TempoEspera } from './types.js';
|
|
3
3
|
export declare const MlClient: Readonly<{
|
|
4
4
|
/**
|
|
@@ -45,4 +45,10 @@ export declare const MlClient: Readonly<{
|
|
|
45
45
|
* @returns An array of TempoEspera objects, one for each station.
|
|
46
46
|
*/
|
|
47
47
|
tempoEsperaTodasEstacoes: () => Promise<BaseResponse<TempoEspera[]>>;
|
|
48
|
+
/**
|
|
49
|
+
* Fetches waiting time estimates for a line and transforms them into a GTFS-RT TripUpdates feed.
|
|
50
|
+
* @param linha Line identifier as string.
|
|
51
|
+
* @returns A GtfsRtFeedMessage containing TripUpdates.
|
|
52
|
+
*/
|
|
53
|
+
tripUpdates: () => Promise<GtfsRtFeedMessage>;
|
|
48
54
|
}>;
|
package/dist/clients/ml/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/* * */
|
|
2
2
|
import { mlAuthClient } from './auth.js';
|
|
3
|
+
import { curlFetcher } from './curl-fetcher.js';
|
|
4
|
+
import { DESTINATION_MAP } from './types.js';
|
|
3
5
|
/* * */
|
|
4
6
|
const BASE_URL = process.env.ML_API_URL;
|
|
5
7
|
const ALERTS_URL = process.env.ML_ALERTS_URL;
|
|
@@ -8,15 +10,11 @@ async function fetcher(endpoint) {
|
|
|
8
10
|
throw new Error('Missing ML_API_URL environment variable.');
|
|
9
11
|
}
|
|
10
12
|
const apiToken = await mlAuthClient.getToken();
|
|
11
|
-
|
|
13
|
+
return await curlFetcher(`${BASE_URL}${endpoint}`, {
|
|
12
14
|
headers: {
|
|
13
15
|
Authorization: `Bearer ${apiToken}`,
|
|
14
16
|
},
|
|
15
17
|
});
|
|
16
|
-
if (!response.ok) {
|
|
17
|
-
throw new Error(`Request failed (${response.status}): ${response.statusText}`);
|
|
18
|
-
}
|
|
19
|
-
return response;
|
|
20
18
|
}
|
|
21
19
|
/* * */
|
|
22
20
|
const endpoints = {
|
|
@@ -36,16 +34,14 @@ export const MlClient = Object.freeze({
|
|
|
36
34
|
* @returns EstadoLinha object with the current status of the line.
|
|
37
35
|
*/
|
|
38
36
|
estadoLinha: async (linha) => {
|
|
39
|
-
|
|
40
|
-
return await response.json();
|
|
37
|
+
return await fetcher(endpoints.estadoLinha(linha));
|
|
41
38
|
},
|
|
42
39
|
/**
|
|
43
40
|
* Gets the status of all Metro Lisboa lines.
|
|
44
41
|
* @returns An array of EstadoLinha objects, each representing the status of a line.
|
|
45
42
|
*/
|
|
46
43
|
estadoLinhaTodas: async () => {
|
|
47
|
-
|
|
48
|
-
return await response.json();
|
|
44
|
+
return await fetcher(endpoints.estadoLinhaTodas);
|
|
49
45
|
},
|
|
50
46
|
/**
|
|
51
47
|
* Gets information about a specific Metro Lisboa station.
|
|
@@ -53,24 +49,21 @@ export const MlClient = Object.freeze({
|
|
|
53
49
|
* @returns InfoEstacao object with details about the station.
|
|
54
50
|
*/
|
|
55
51
|
infoEstacao: async (estacao) => {
|
|
56
|
-
|
|
57
|
-
return await response.json();
|
|
52
|
+
return await fetcher(endpoints.infoEstacao(estacao));
|
|
58
53
|
},
|
|
59
54
|
/**
|
|
60
55
|
* Gets information about all Metro Lisboa stations.
|
|
61
56
|
* @returns An array of InfoEstacao objects, one for each station.
|
|
62
57
|
*/
|
|
63
58
|
infoEstacaoTodas: async () => {
|
|
64
|
-
|
|
65
|
-
return await response.json();
|
|
59
|
+
return await fetcher(endpoints.infoEstacaoTodas);
|
|
66
60
|
},
|
|
67
61
|
/**
|
|
68
62
|
* Retrieves current Metro Lisboa service alerts.
|
|
69
63
|
* @returns A ServiceAlertResponse containing the active service alerts in GTFS-realtime format.
|
|
70
64
|
*/
|
|
71
65
|
serviceAlerts: async () => {
|
|
72
|
-
|
|
73
|
-
return await response.json();
|
|
66
|
+
return await fetcher(endpoints.serviceAlerts);
|
|
74
67
|
},
|
|
75
68
|
/**
|
|
76
69
|
* Gets the current waiting time estimates for a specific station.
|
|
@@ -78,8 +71,7 @@ export const MlClient = Object.freeze({
|
|
|
78
71
|
* @returns TempoEspera object with estimated waiting times for the station.
|
|
79
72
|
*/
|
|
80
73
|
tempoEsperaEstacao: async (estacao) => {
|
|
81
|
-
|
|
82
|
-
return await response.json();
|
|
74
|
+
return await fetcher(endpoints.tempoEsperaEstacao(estacao));
|
|
83
75
|
},
|
|
84
76
|
/**
|
|
85
77
|
* Gets the current waiting time estimates for a specific line.
|
|
@@ -87,15 +79,80 @@ export const MlClient = Object.freeze({
|
|
|
87
79
|
* @returns An array of TempoEspera objects, one for each station in the line.
|
|
88
80
|
*/
|
|
89
81
|
tempoEsperaLinha: async (linha) => {
|
|
90
|
-
|
|
91
|
-
return await response.json();
|
|
82
|
+
return await fetcher(endpoints.tempoEsperaLinha(linha));
|
|
92
83
|
},
|
|
93
84
|
/**
|
|
94
85
|
* Gets the current waiting time estimates for all stations.
|
|
95
86
|
* @returns An array of TempoEspera objects, one for each station.
|
|
96
87
|
*/
|
|
97
88
|
tempoEsperaTodasEstacoes: async () => {
|
|
98
|
-
|
|
99
|
-
|
|
89
|
+
return await fetcher(endpoints.tempoEsperaTodasEstacoes);
|
|
90
|
+
},
|
|
91
|
+
/**
|
|
92
|
+
* Fetches waiting time estimates for a line and transforms them into a GTFS-RT TripUpdates feed.
|
|
93
|
+
* @param linha Line identifier as string.
|
|
94
|
+
* @returns A GtfsRtFeedMessage containing TripUpdates.
|
|
95
|
+
*/
|
|
96
|
+
tripUpdates: async () => {
|
|
97
|
+
const now = Date.now();
|
|
98
|
+
const lines = ['Amarela', 'Azul', 'Verde', 'Vermelha'];
|
|
99
|
+
const entities = [];
|
|
100
|
+
for (const line of lines) {
|
|
101
|
+
const data = await fetcher(endpoints.tempoEsperaLinha(line));
|
|
102
|
+
const trainStops = new Map();
|
|
103
|
+
for (const [index, item] of data.resposta.entries()) {
|
|
104
|
+
const trains = [
|
|
105
|
+
{ comboio: item.comboio, tempo: item.tempoChegada1 },
|
|
106
|
+
{ comboio: item.comboio2, tempo: item.tempoChegada2 },
|
|
107
|
+
{ comboio: item.comboio3, tempo: item.tempoChegada3 },
|
|
108
|
+
];
|
|
109
|
+
for (const train of trains) {
|
|
110
|
+
if (!train.comboio || train.tempo === '--')
|
|
111
|
+
continue;
|
|
112
|
+
const arrivalSeconds = Number.parseInt(train.tempo, 10);
|
|
113
|
+
if (!trainStops.has(train.comboio)) {
|
|
114
|
+
trainStops.set(train.comboio, { destination: item.destino, stops: [] });
|
|
115
|
+
}
|
|
116
|
+
trainStops.get(train.comboio).stops.push({
|
|
117
|
+
arrival_seconds: arrivalSeconds,
|
|
118
|
+
stop_id: item.stop_id,
|
|
119
|
+
stop_sequence: index,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
entities.push(...Array.from(trainStops.entries()).map(([key, value]) => {
|
|
124
|
+
const sortedStops = value.stops.sort((a, b) => a.stop_sequence - b.stop_sequence);
|
|
125
|
+
return {
|
|
126
|
+
id: `${line}_${key}_${DESTINATION_MAP[value.destination].code}`,
|
|
127
|
+
trip_update: {
|
|
128
|
+
stop_time_update: sortedStops.map(stop => ({
|
|
129
|
+
arrival: {
|
|
130
|
+
time: now + stop.arrival_seconds * 1000,
|
|
131
|
+
},
|
|
132
|
+
stop_id: stop.stop_id,
|
|
133
|
+
stop_sequence: stop.stop_sequence,
|
|
134
|
+
})),
|
|
135
|
+
timestamp: now,
|
|
136
|
+
trip: {
|
|
137
|
+
line_id: line,
|
|
138
|
+
line_short_name: `${line}_${DESTINATION_MAP[value.destination].code}`,
|
|
139
|
+
trip_headsign: DESTINATION_MAP[value.destination].name,
|
|
140
|
+
trip_id: `${line}_${key}_${value.destination}`,
|
|
141
|
+
},
|
|
142
|
+
vehicle: {
|
|
143
|
+
id: key,
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
entity: entities,
|
|
151
|
+
header: {
|
|
152
|
+
gtfs_realtime_version: '2.0',
|
|
153
|
+
incrementality: 'FULL_DATASET',
|
|
154
|
+
timestamp: now,
|
|
155
|
+
},
|
|
156
|
+
};
|
|
100
157
|
},
|
|
101
158
|
});
|
|
@@ -15,6 +15,23 @@ export interface TempoEspera {
|
|
|
15
15
|
nomeEstacao: string;
|
|
16
16
|
tempoEspera: string;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Raw response item from GET /tempoEspera/Linha/{linha}.
|
|
20
|
+
* Each entry represents a stop/platform with up to 3 upcoming trains.
|
|
21
|
+
*/
|
|
22
|
+
export interface TempoEsperaRawItem {
|
|
23
|
+
cais: string;
|
|
24
|
+
comboio: string;
|
|
25
|
+
comboio2: string;
|
|
26
|
+
comboio3: string;
|
|
27
|
+
destino: string;
|
|
28
|
+
hora: string;
|
|
29
|
+
sairServico: string;
|
|
30
|
+
stop_id: string;
|
|
31
|
+
tempoChegada1: string;
|
|
32
|
+
tempoChegada2: string;
|
|
33
|
+
tempoChegada3: string;
|
|
34
|
+
}
|
|
18
35
|
/**
|
|
19
36
|
* @see GET /infoEstacao/todos
|
|
20
37
|
* @see GET /infoEstacao/{estacao}
|
|
@@ -36,3 +53,101 @@ export interface EstadoLinha {
|
|
|
36
53
|
estado: string;
|
|
37
54
|
linha: string;
|
|
38
55
|
}
|
|
56
|
+
export declare const DESTINATION_MAP: {
|
|
57
|
+
readonly 33: {
|
|
58
|
+
readonly code: "RB";
|
|
59
|
+
readonly name: "Reboleira";
|
|
60
|
+
};
|
|
61
|
+
readonly 34: {
|
|
62
|
+
readonly code: "AS";
|
|
63
|
+
readonly name: "Amadora Este";
|
|
64
|
+
};
|
|
65
|
+
readonly 35: {
|
|
66
|
+
readonly code: "PO";
|
|
67
|
+
readonly name: "Pontinha";
|
|
68
|
+
};
|
|
69
|
+
readonly 36: {
|
|
70
|
+
readonly code: "CM";
|
|
71
|
+
readonly name: "Colégio Militar/Luz";
|
|
72
|
+
};
|
|
73
|
+
readonly 37: {
|
|
74
|
+
readonly code: "LA";
|
|
75
|
+
readonly name: "Laranjeiras";
|
|
76
|
+
};
|
|
77
|
+
readonly 38: {
|
|
78
|
+
readonly code: "SS";
|
|
79
|
+
readonly name: "São Sebastião";
|
|
80
|
+
};
|
|
81
|
+
readonly 39: {
|
|
82
|
+
readonly code: "AV";
|
|
83
|
+
readonly name: "Avenida";
|
|
84
|
+
};
|
|
85
|
+
readonly 40: {
|
|
86
|
+
readonly code: "BC";
|
|
87
|
+
readonly name: "Baixa-Chiado";
|
|
88
|
+
};
|
|
89
|
+
readonly 41: {
|
|
90
|
+
readonly code: "TP";
|
|
91
|
+
readonly name: "Terreiro do Paço";
|
|
92
|
+
};
|
|
93
|
+
readonly 42: {
|
|
94
|
+
readonly code: "SP";
|
|
95
|
+
readonly name: "Santa Apolónia";
|
|
96
|
+
};
|
|
97
|
+
readonly 43: {
|
|
98
|
+
readonly code: "OD";
|
|
99
|
+
readonly name: "Odivelas";
|
|
100
|
+
};
|
|
101
|
+
readonly 44: {
|
|
102
|
+
readonly code: "LU";
|
|
103
|
+
readonly name: "Lumiar";
|
|
104
|
+
};
|
|
105
|
+
readonly 45: {
|
|
106
|
+
readonly code: "CG";
|
|
107
|
+
readonly name: "Campo Grande";
|
|
108
|
+
};
|
|
109
|
+
readonly 46: {
|
|
110
|
+
readonly code: "CP";
|
|
111
|
+
readonly name: "Campo Pequeno";
|
|
112
|
+
};
|
|
113
|
+
readonly 48: {
|
|
114
|
+
readonly code: "RA";
|
|
115
|
+
readonly name: "Rato";
|
|
116
|
+
};
|
|
117
|
+
readonly 50: {
|
|
118
|
+
readonly code: "TE";
|
|
119
|
+
readonly name: "Telheiras";
|
|
120
|
+
};
|
|
121
|
+
readonly 51: {
|
|
122
|
+
readonly code: "AL";
|
|
123
|
+
readonly name: "Alvalade";
|
|
124
|
+
};
|
|
125
|
+
readonly 52: {
|
|
126
|
+
readonly code: "AM";
|
|
127
|
+
readonly name: "Alameda";
|
|
128
|
+
};
|
|
129
|
+
readonly 53: {
|
|
130
|
+
readonly code: "MM";
|
|
131
|
+
readonly name: "Martim Moniz";
|
|
132
|
+
};
|
|
133
|
+
readonly 54: {
|
|
134
|
+
readonly code: "CS";
|
|
135
|
+
readonly name: "Cais do Sodré";
|
|
136
|
+
};
|
|
137
|
+
readonly 56: {
|
|
138
|
+
readonly code: "BV";
|
|
139
|
+
readonly name: "Bela Vista";
|
|
140
|
+
};
|
|
141
|
+
readonly 57: {
|
|
142
|
+
readonly code: "CH";
|
|
143
|
+
readonly name: "Chelas";
|
|
144
|
+
};
|
|
145
|
+
readonly 59: {
|
|
146
|
+
readonly code: "MO";
|
|
147
|
+
readonly name: "Moscavide";
|
|
148
|
+
};
|
|
149
|
+
readonly 60: {
|
|
150
|
+
readonly code: "AP";
|
|
151
|
+
readonly name: "Aeroporto";
|
|
152
|
+
};
|
|
153
|
+
};
|
package/dist/clients/ml/types.js
CHANGED
|
@@ -1,2 +1,99 @@
|
|
|
1
1
|
/* * */
|
|
2
|
-
export {
|
|
2
|
+
export const DESTINATION_MAP = {
|
|
3
|
+
33: {
|
|
4
|
+
code: 'RB',
|
|
5
|
+
name: 'Reboleira',
|
|
6
|
+
},
|
|
7
|
+
34: {
|
|
8
|
+
code: 'AS',
|
|
9
|
+
name: 'Amadora Este',
|
|
10
|
+
},
|
|
11
|
+
35: {
|
|
12
|
+
code: 'PO',
|
|
13
|
+
name: 'Pontinha',
|
|
14
|
+
},
|
|
15
|
+
36: {
|
|
16
|
+
code: 'CM',
|
|
17
|
+
name: 'Colégio Militar/Luz',
|
|
18
|
+
},
|
|
19
|
+
37: {
|
|
20
|
+
code: 'LA',
|
|
21
|
+
name: 'Laranjeiras',
|
|
22
|
+
},
|
|
23
|
+
38: {
|
|
24
|
+
code: 'SS',
|
|
25
|
+
name: 'São Sebastião',
|
|
26
|
+
},
|
|
27
|
+
39: {
|
|
28
|
+
code: 'AV',
|
|
29
|
+
name: 'Avenida',
|
|
30
|
+
},
|
|
31
|
+
40: {
|
|
32
|
+
code: 'BC',
|
|
33
|
+
name: 'Baixa-Chiado',
|
|
34
|
+
},
|
|
35
|
+
41: {
|
|
36
|
+
code: 'TP',
|
|
37
|
+
name: 'Terreiro do Paço',
|
|
38
|
+
},
|
|
39
|
+
42: {
|
|
40
|
+
code: 'SP',
|
|
41
|
+
name: 'Santa Apolónia',
|
|
42
|
+
},
|
|
43
|
+
43: {
|
|
44
|
+
code: 'OD',
|
|
45
|
+
name: 'Odivelas',
|
|
46
|
+
},
|
|
47
|
+
44: {
|
|
48
|
+
code: 'LU',
|
|
49
|
+
name: 'Lumiar',
|
|
50
|
+
},
|
|
51
|
+
45: {
|
|
52
|
+
code: 'CG',
|
|
53
|
+
name: 'Campo Grande',
|
|
54
|
+
},
|
|
55
|
+
46: {
|
|
56
|
+
code: 'CP',
|
|
57
|
+
name: 'Campo Pequeno',
|
|
58
|
+
},
|
|
59
|
+
48: {
|
|
60
|
+
code: 'RA',
|
|
61
|
+
name: 'Rato',
|
|
62
|
+
},
|
|
63
|
+
50: {
|
|
64
|
+
code: 'TE',
|
|
65
|
+
name: 'Telheiras',
|
|
66
|
+
},
|
|
67
|
+
51: {
|
|
68
|
+
code: 'AL',
|
|
69
|
+
name: 'Alvalade',
|
|
70
|
+
},
|
|
71
|
+
52: {
|
|
72
|
+
code: 'AM',
|
|
73
|
+
name: 'Alameda',
|
|
74
|
+
},
|
|
75
|
+
53: {
|
|
76
|
+
code: 'MM',
|
|
77
|
+
name: 'Martim Moniz',
|
|
78
|
+
},
|
|
79
|
+
54: {
|
|
80
|
+
code: 'CS',
|
|
81
|
+
name: 'Cais do Sodré',
|
|
82
|
+
},
|
|
83
|
+
56: {
|
|
84
|
+
code: 'BV',
|
|
85
|
+
name: 'Bela Vista',
|
|
86
|
+
},
|
|
87
|
+
57: {
|
|
88
|
+
code: 'CH',
|
|
89
|
+
name: 'Chelas',
|
|
90
|
+
},
|
|
91
|
+
59: {
|
|
92
|
+
code: 'MO',
|
|
93
|
+
name: 'Moscavide',
|
|
94
|
+
},
|
|
95
|
+
60: {
|
|
96
|
+
code: 'AP',
|
|
97
|
+
name: 'Aeroporto',
|
|
98
|
+
},
|
|
99
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export declare const externalClients: Readonly<{
|
|
|
40
40
|
tempoEsperaEstacao: (estacao: string) => Promise<import("./clients/ml/types.js").BaseResponse<import("./clients/ml/types.js").TempoEspera>>;
|
|
41
41
|
tempoEsperaLinha: (linha: string) => Promise<import("./clients/ml/types.js").BaseResponse<import("./clients/ml/types.js").TempoEspera[]>>;
|
|
42
42
|
tempoEsperaTodasEstacoes: () => Promise<import("./clients/ml/types.js").BaseResponse<import("./clients/ml/types.js").TempoEspera[]>>;
|
|
43
|
+
tripUpdates: () => Promise<import("@tmlmobilidade/types").GtfsRtFeedMessage>;
|
|
43
44
|
}>;
|
|
44
45
|
mobi: Readonly<{
|
|
45
46
|
tripUpdates: () => Promise<import("@tmlmobilidade/types").GtfsRtFeedMessage>;
|