sbb-mcp 0.4.2 → 0.5.0
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/LICENSE +50 -57
- package/README.md +26 -296
- package/dist/index.js +47 -17
- package/package.json +10 -29
- package/dist/auth.d.ts +0 -2
- package/dist/auth.js +0 -44
- package/dist/auth.js.map +0 -1
- package/dist/cache.d.ts +0 -12
- package/dist/cache.js +0 -58
- package/dist/cache.js.map +0 -1
- package/dist/client.d.ts +0 -17
- package/dist/client.js +0 -70
- package/dist/client.js.map +0 -1
- package/dist/formatters.d.ts +0 -22
- package/dist/formatters.js +0 -210
- package/dist/formatters.js.map +0 -1
- package/dist/http.d.ts +0 -2
- package/dist/http.js +0 -61
- package/dist/http.js.map +0 -1
- package/dist/i18n.d.ts +0 -22
- package/dist/i18n.js +0 -36
- package/dist/i18n.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js.map +0 -1
- package/dist/journey.d.ts +0 -5
- package/dist/journey.js +0 -67
- package/dist/journey.js.map +0 -1
- package/dist/prices.d.ts +0 -3
- package/dist/prices.js +0 -51
- package/dist/prices.js.map +0 -1
- package/dist/profile.d.ts +0 -16
- package/dist/profile.js +0 -77
- package/dist/profile.js.map +0 -1
- package/dist/rate-limit.d.ts +0 -5
- package/dist/rate-limit.js +0 -44
- package/dist/rate-limit.js.map +0 -1
- package/dist/structured.d.ts +0 -119
- package/dist/structured.js +0 -133
- package/dist/structured.js.map +0 -1
- package/dist/swisstrip.d.ts +0 -41
- package/dist/swisstrip.js +0 -119
- package/dist/swisstrip.js.map +0 -1
- package/dist/tools.d.ts +0 -2
- package/dist/tools.js +0 -464
- package/dist/tools.js.map +0 -1
- package/dist/transport/index.d.ts +0 -9
- package/dist/transport/index.js +0 -9
- package/dist/transport/index.js.map +0 -1
- package/dist/transport/smapi-auth.d.ts +0 -2
- package/dist/transport/smapi-auth.js +0 -39
- package/dist/transport/smapi-auth.js.map +0 -1
- package/dist/transport/smapi-client.d.ts +0 -22
- package/dist/transport/smapi-client.js +0 -83
- package/dist/transport/smapi-client.js.map +0 -1
- package/dist/transport/smapi-journey.d.ts +0 -23
- package/dist/transport/smapi-journey.js +0 -82
- package/dist/transport/smapi-journey.js.map +0 -1
- package/dist/transport/smapi-mock.d.ts +0 -9
- package/dist/transport/smapi-mock.js +0 -151
- package/dist/transport/smapi-mock.js.map +0 -1
- package/dist/transport/smapi-prices.d.ts +0 -14
- package/dist/transport/smapi-prices.js +0 -73
- package/dist/transport/smapi-prices.js.map +0 -1
- package/dist/transport/smapi-types.d.ts +0 -153
- package/dist/transport/smapi-types.js +0 -2
- package/dist/transport/smapi-types.js.map +0 -1
- package/dist/types.d.ts +0 -139
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
- package/dist/widgets.d.ts +0 -33
- package/dist/widgets.js +0 -120
- package/dist/widgets.js.map +0 -1
- package/web/dist/widgets.css +0 -1
- package/web/dist/widgets.js +0 -1
package/dist/auth.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// OAuth 2.0 Client Credentials flow for SBB SMAPI
|
|
2
|
-
// Token endpoint: Microsoft Azure AD
|
|
3
|
-
// Tokens cached in-memory with 55-min TTL (5-min safety margin on 60-min expiry)
|
|
4
|
-
let cachedToken = null;
|
|
5
|
-
export function isSmapiConfigured() {
|
|
6
|
-
return !!(process.env.SMAPI_CLIENT_ID &&
|
|
7
|
-
process.env.SMAPI_CLIENT_SECRET &&
|
|
8
|
-
process.env.SMAPI_SCOPE);
|
|
9
|
-
}
|
|
10
|
-
export async function getAccessToken() {
|
|
11
|
-
if (cachedToken && Date.now() < cachedToken.expiresAt) {
|
|
12
|
-
return cachedToken.token;
|
|
13
|
-
}
|
|
14
|
-
const clientId = process.env.SMAPI_CLIENT_ID;
|
|
15
|
-
const clientSecret = process.env.SMAPI_CLIENT_SECRET;
|
|
16
|
-
const scope = process.env.SMAPI_SCOPE;
|
|
17
|
-
if (!clientId || !clientSecret || !scope) {
|
|
18
|
-
throw new Error('SMAPI credentials not configured. Set SMAPI_CLIENT_ID, SMAPI_CLIENT_SECRET, and SMAPI_SCOPE.');
|
|
19
|
-
}
|
|
20
|
-
const tenantId = process.env.SMAPI_TENANT_ID || '2cda5d11-f0ac-46b3-967d-af1b2e1bd01a';
|
|
21
|
-
const tokenUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
|
|
22
|
-
const body = new URLSearchParams({
|
|
23
|
-
grant_type: 'client_credentials',
|
|
24
|
-
client_id: clientId,
|
|
25
|
-
client_secret: clientSecret,
|
|
26
|
-
scope,
|
|
27
|
-
});
|
|
28
|
-
const res = await fetch(tokenUrl, {
|
|
29
|
-
method: 'POST',
|
|
30
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
31
|
-
body: body.toString(),
|
|
32
|
-
});
|
|
33
|
-
if (!res.ok) {
|
|
34
|
-
const text = await res.text();
|
|
35
|
-
throw new Error(`SMAPI token request failed: ${res.status} ${text}`);
|
|
36
|
-
}
|
|
37
|
-
const data = await res.json();
|
|
38
|
-
cachedToken = {
|
|
39
|
-
token: data.access_token,
|
|
40
|
-
expiresAt: Date.now() + 55 * 60 * 1000,
|
|
41
|
-
};
|
|
42
|
-
return cachedToken.token;
|
|
43
|
-
}
|
|
44
|
-
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,qCAAqC;AACrC,iFAAiF;AAEjF,IAAI,WAAW,GAAgD,IAAI,CAAA;AAEnE,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CAAC,CAAC,CACP,OAAO,CAAC,GAAG,CAAC,eAAe;QAC3B,OAAO,CAAC,GAAG,CAAC,mBAAmB;QAC/B,OAAO,CAAC,GAAG,CAAC,WAAW,CACxB,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,CAAC,SAAS,EAAE,CAAC;QACtD,OAAO,WAAW,CAAC,KAAK,CAAA;IAC1B,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAA;IAC5C,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAA;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAA;IAErC,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY,IAAI,CAAC,KAAK,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CACb,8FAA8F,CAC/F,CAAA;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,sCAAsC,CAAA;IACtF,MAAM,QAAQ,GAAG,qCAAqC,QAAQ,oBAAoB,CAAA;IAElF,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;QAC/B,UAAU,EAAE,oBAAoB;QAChC,SAAS,EAAE,QAAQ;QACnB,aAAa,EAAE,YAAY;QAC3B,KAAK;KACN,CAAC,CAAA;IAEF,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;QAChE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;KACtB,CAAC,CAAA;IAEF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;QAC7B,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAA;IACtE,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;IAE7B,WAAW,GAAG;QACZ,KAAK,EAAE,IAAI,CAAC,YAAY;QACxB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;KACvC,CAAA;IAED,OAAO,WAAW,CAAC,KAAK,CAAA;AAC1B,CAAC"}
|
package/dist/cache.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple in-memory TTL cache with LRU eviction to reduce SMAPI calls.
|
|
3
|
-
* Station searches cached 24h, connections cached 5min, prices cached 2min.
|
|
4
|
-
*/
|
|
5
|
-
export declare function cacheGet<T>(key: string): T | undefined;
|
|
6
|
-
export declare function cacheSet<T>(key: string, data: T, ttlMs: number): void;
|
|
7
|
-
export declare const TTL: {
|
|
8
|
-
readonly STATIONS: number;
|
|
9
|
-
readonly CONNECTIONS: number;
|
|
10
|
-
readonly PRICES: number;
|
|
11
|
-
readonly TRIP_DETAILS: number;
|
|
12
|
-
};
|
package/dist/cache.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple in-memory TTL cache with LRU eviction to reduce SMAPI calls.
|
|
3
|
-
* Station searches cached 24h, connections cached 5min, prices cached 2min.
|
|
4
|
-
*/
|
|
5
|
-
const store = new Map();
|
|
6
|
-
const MAX_ENTRIES = 10000;
|
|
7
|
-
function evictExpired() {
|
|
8
|
-
const now = Date.now();
|
|
9
|
-
let evicted = 0;
|
|
10
|
-
for (const [key, entry] of store) {
|
|
11
|
-
if (now >= entry.expiresAt) {
|
|
12
|
-
store.delete(key);
|
|
13
|
-
evicted++;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
return evicted;
|
|
17
|
-
}
|
|
18
|
-
function evictOldest(count) {
|
|
19
|
-
// Map iteration order is insertion order — oldest first
|
|
20
|
-
let removed = 0;
|
|
21
|
-
for (const key of store.keys()) {
|
|
22
|
-
if (removed >= count)
|
|
23
|
-
break;
|
|
24
|
-
store.delete(key);
|
|
25
|
-
removed++;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
export function cacheGet(key) {
|
|
29
|
-
const entry = store.get(key);
|
|
30
|
-
if (!entry)
|
|
31
|
-
return undefined;
|
|
32
|
-
if (Date.now() >= entry.expiresAt) {
|
|
33
|
-
store.delete(key);
|
|
34
|
-
return undefined;
|
|
35
|
-
}
|
|
36
|
-
// Move to end for LRU (re-insert refreshes position)
|
|
37
|
-
store.delete(key);
|
|
38
|
-
store.set(key, entry);
|
|
39
|
-
return entry.data;
|
|
40
|
-
}
|
|
41
|
-
export function cacheSet(key, data, ttlMs) {
|
|
42
|
-
if (store.size >= MAX_ENTRIES) {
|
|
43
|
-
const evicted = evictExpired();
|
|
44
|
-
// If expired eviction didn't free enough, drop oldest 10%
|
|
45
|
-
if (evicted < MAX_ENTRIES * 0.1) {
|
|
46
|
-
evictOldest(Math.floor(MAX_ENTRIES * 0.1));
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
store.set(key, { data, expiresAt: Date.now() + ttlMs });
|
|
50
|
-
}
|
|
51
|
-
// TTLs
|
|
52
|
-
export const TTL = {
|
|
53
|
-
STATIONS: 24 * 60 * 60 * 1000, // 24 hours
|
|
54
|
-
CONNECTIONS: 5 * 60 * 1000, // 5 minutes
|
|
55
|
-
PRICES: 2 * 60 * 1000, // 2 minutes
|
|
56
|
-
TRIP_DETAILS: 5 * 60 * 1000, // 5 minutes
|
|
57
|
-
};
|
|
58
|
-
//# sourceMappingURL=cache.js.map
|
package/dist/cache.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAA;AAEpD,MAAM,WAAW,GAAG,KAAK,CAAA;AAEzB,SAAS,YAAY;IACnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IACtB,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;QACjC,IAAI,GAAG,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YAC3B,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACjB,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,wDAAwD;IACxD,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC/B,IAAI,OAAO,IAAI,KAAK;YAAE,MAAK;QAC3B,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACjB,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAI,GAAW;IACrC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5B,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAA;IAC5B,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QAClC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACjB,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,qDAAqD;IACrD,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IACjB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACrB,OAAO,KAAK,CAAC,IAAS,CAAA;AACxB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAI,GAAW,EAAE,IAAO,EAAE,KAAa;IAC7D,IAAI,KAAK,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,YAAY,EAAE,CAAA;QAC9B,0DAA0D;QAC1D,IAAI,OAAO,GAAG,WAAW,GAAG,GAAG,EAAE,CAAC;YAChC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC,CAAA;QAC5C,CAAC;IACH,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,CAAA;AACzD,CAAC;AAED,OAAO;AACP,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAK,WAAW;IAC7C,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAS,YAAY;IAC/C,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAc,YAAY;IAC/C,YAAY,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAQ,YAAY;CACvC,CAAA"}
|
package/dist/client.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { SmapiProblem } from './types.js';
|
|
2
|
-
export declare function getJourneyBaseUrl(): string;
|
|
3
|
-
export declare function getTicketingBaseUrl(): string;
|
|
4
|
-
export declare class SmapiError extends Error {
|
|
5
|
-
problem?: SmapiProblem;
|
|
6
|
-
status: number;
|
|
7
|
-
constructor(message: string, status: number, problem?: SmapiProblem);
|
|
8
|
-
get displayMessages(): string[];
|
|
9
|
-
}
|
|
10
|
-
type RequestOptions = {
|
|
11
|
-
method?: 'GET' | 'POST';
|
|
12
|
-
body?: unknown;
|
|
13
|
-
conversationId?: string;
|
|
14
|
-
acceptLanguage?: string;
|
|
15
|
-
};
|
|
16
|
-
export declare function smapiRequest<T>(baseUrl: string, path: string, options?: RequestOptions): Promise<T>;
|
|
17
|
-
export {};
|
package/dist/client.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { getAccessToken } from './auth.js';
|
|
2
|
-
const JOURNEY_URLS = {
|
|
3
|
-
int: 'https://smapi-osdm-journey-int.api.sbb.ch',
|
|
4
|
-
prod: 'https://smapi-osdm-journey.api.sbb.ch',
|
|
5
|
-
};
|
|
6
|
-
const TICKETING_URLS = {
|
|
7
|
-
int: 'https://b2p-int.api.sbb.ch',
|
|
8
|
-
prod: 'https://b2p.api.sbb.ch',
|
|
9
|
-
};
|
|
10
|
-
function getEnv() {
|
|
11
|
-
return process.env.SMAPI_ENV || 'int';
|
|
12
|
-
}
|
|
13
|
-
export function getJourneyBaseUrl() {
|
|
14
|
-
return JOURNEY_URLS[getEnv()];
|
|
15
|
-
}
|
|
16
|
-
export function getTicketingBaseUrl() {
|
|
17
|
-
return TICKETING_URLS[getEnv()];
|
|
18
|
-
}
|
|
19
|
-
export class SmapiError extends Error {
|
|
20
|
-
problem;
|
|
21
|
-
status;
|
|
22
|
-
constructor(message, status, problem) {
|
|
23
|
-
super(message);
|
|
24
|
-
this.name = 'SmapiError';
|
|
25
|
-
this.status = status;
|
|
26
|
-
this.problem = problem;
|
|
27
|
-
}
|
|
28
|
-
get displayMessages() {
|
|
29
|
-
return this.problem?.displayMessages ?? [];
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
export async function smapiRequest(baseUrl, path, options = {}) {
|
|
33
|
-
const { method = 'GET', body, conversationId, acceptLanguage = 'en' } = options;
|
|
34
|
-
const token = await getAccessToken();
|
|
35
|
-
const contractId = process.env.SMAPI_CONTRACT_ID || '';
|
|
36
|
-
const headers = {
|
|
37
|
-
Authorization: `Bearer ${token}`,
|
|
38
|
-
'x-contract-id': contractId,
|
|
39
|
-
'x-conversation-id': conversationId || crypto.randomUUID(),
|
|
40
|
-
Accept: 'application/json',
|
|
41
|
-
'Accept-Language': acceptLanguage,
|
|
42
|
-
'Cache-Control': 'no-cache',
|
|
43
|
-
};
|
|
44
|
-
if (body) {
|
|
45
|
-
headers['Content-Type'] = 'application/json';
|
|
46
|
-
}
|
|
47
|
-
const res = await fetch(`${baseUrl}${path}`, {
|
|
48
|
-
method,
|
|
49
|
-
headers,
|
|
50
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
51
|
-
});
|
|
52
|
-
if (!res.ok) {
|
|
53
|
-
let problem;
|
|
54
|
-
try {
|
|
55
|
-
const contentType = res.headers.get('content-type') || '';
|
|
56
|
-
if (contentType.includes('json')) {
|
|
57
|
-
problem = await res.json();
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
// ignore parse errors
|
|
62
|
-
}
|
|
63
|
-
throw new SmapiError(problem?.title || `SMAPI request failed: ${res.status}`, res.status, problem);
|
|
64
|
-
}
|
|
65
|
-
if (res.status === 204) {
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
return res.json();
|
|
69
|
-
}
|
|
70
|
-
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/formatters.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { SmapiPlace, SmapiTrip, SmapiTripsCollection, SmapiPriceResult } from './transport/smapi-types.js';
|
|
2
|
-
import type { Lang } from './i18n.js';
|
|
3
|
-
export declare function formatStations(stations: SmapiPlace[], lang?: Lang): string;
|
|
4
|
-
export declare function formatConnections(collection: SmapiTripsCollection, lang?: Lang): string;
|
|
5
|
-
export declare function formatTripDetails(trip: SmapiTrip, lang?: Lang): string;
|
|
6
|
-
export declare function formatPrices(results: SmapiPriceResult[], lang?: Lang): string;
|
|
7
|
-
/**
|
|
8
|
-
* Build an SBB.ch deep link URL with connection pre-filled.
|
|
9
|
-
* SBB.ch URLs support de/fr/it/en; other languages fall back to `en`.
|
|
10
|
-
*/
|
|
11
|
-
export declare function buildSbbDeepLink(params: {
|
|
12
|
-
fromName: string;
|
|
13
|
-
fromId: string;
|
|
14
|
-
toName: string;
|
|
15
|
-
toId: string;
|
|
16
|
-
date: string;
|
|
17
|
-
time: string;
|
|
18
|
-
lang?: Lang;
|
|
19
|
-
}): string;
|
|
20
|
-
export declare function formatTicketLink(tripId: string, deepLink?: string, sbbLink?: string, lang?: Lang): string;
|
|
21
|
-
/** Append destination weather to formatted connections */
|
|
22
|
-
export declare function appendWeatherToConnections(formatted: string, destinationLat: number, destinationLon: number, date: string, destinationName: string): Promise<string>;
|
package/dist/formatters.js
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import { getWeatherSummary } from 'swiss-weather-mcp';
|
|
2
|
-
import { toLocale, toSbbLinkLang, t } from './i18n.js';
|
|
3
|
-
function formatTime(iso, lang) {
|
|
4
|
-
const d = new Date(iso);
|
|
5
|
-
return d.toLocaleTimeString(toLocale(lang), {
|
|
6
|
-
hour: '2-digit',
|
|
7
|
-
minute: '2-digit',
|
|
8
|
-
timeZone: 'Europe/Zurich',
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
function formatDate(iso, lang) {
|
|
12
|
-
const d = new Date(iso);
|
|
13
|
-
return d.toLocaleDateString(toLocale(lang), {
|
|
14
|
-
weekday: 'short',
|
|
15
|
-
day: '2-digit',
|
|
16
|
-
month: '2-digit',
|
|
17
|
-
year: 'numeric',
|
|
18
|
-
timeZone: 'Europe/Zurich',
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
function parseDuration(iso) {
|
|
22
|
-
const match = iso.match(/PT(?:(\d+)H)?(?:(\d+)M)?/);
|
|
23
|
-
if (!match)
|
|
24
|
-
return iso;
|
|
25
|
-
const h = match[1] ? `${match[1]}h` : '';
|
|
26
|
-
const m = match[2] ? `${match[2]}m` : '';
|
|
27
|
-
return `${h}${h && m ? ' ' : ''}${m}` || '0m';
|
|
28
|
-
}
|
|
29
|
-
function transfersLabel(n, lang) {
|
|
30
|
-
const tr = t(lang);
|
|
31
|
-
if (n === 0)
|
|
32
|
-
return tr.direct;
|
|
33
|
-
if (n === 1)
|
|
34
|
-
return tr.oneChange;
|
|
35
|
-
return tr.nChanges(n);
|
|
36
|
-
}
|
|
37
|
-
export function formatStations(stations, lang = 'en') {
|
|
38
|
-
if (stations.length === 0) {
|
|
39
|
-
return 'No stations found.';
|
|
40
|
-
}
|
|
41
|
-
const lines = [`Found ${stations.length} station(s):`, ''];
|
|
42
|
-
lines.push('| Station | ID | Coordinates |');
|
|
43
|
-
lines.push('|---|---|---|');
|
|
44
|
-
for (const s of stations) {
|
|
45
|
-
const coords = s.geoPosition
|
|
46
|
-
? `${s.geoPosition.latitude.toFixed(4)}, ${s.geoPosition.longitude.toFixed(4)}`
|
|
47
|
-
: '-';
|
|
48
|
-
lines.push(`| ${s.name} | \`${s.id}\` | ${coords} |`);
|
|
49
|
-
}
|
|
50
|
-
return lines.join('\n');
|
|
51
|
-
}
|
|
52
|
-
function formatLegSummary(leg, lang) {
|
|
53
|
-
if (leg.type === 'timed') {
|
|
54
|
-
const tl = leg;
|
|
55
|
-
const line = tl.service.publishedLineName || 'Train';
|
|
56
|
-
const platform = tl.board.platform ? ` ${t(lang).pl}.${tl.board.platform}` : '';
|
|
57
|
-
return `${line}${platform}`;
|
|
58
|
-
}
|
|
59
|
-
if (leg.type === 'transfer') {
|
|
60
|
-
const tr = leg;
|
|
61
|
-
return `Walk ${parseDuration(tr.duration)}`;
|
|
62
|
-
}
|
|
63
|
-
return t(lang).transfer;
|
|
64
|
-
}
|
|
65
|
-
export function formatConnections(collection, lang = 'en') {
|
|
66
|
-
const trips = collection.trips;
|
|
67
|
-
const tr = t(lang);
|
|
68
|
-
if (trips.length === 0) {
|
|
69
|
-
return tr.noConnections;
|
|
70
|
-
}
|
|
71
|
-
const first = trips[0];
|
|
72
|
-
const date = formatDate(first.startTime, lang);
|
|
73
|
-
const lines = [
|
|
74
|
-
`**${first.origin.name} -> ${first.destination.name}** | ${date}`,
|
|
75
|
-
`Collection ID: \`${collection.id}\` (use with get_more_connections)`,
|
|
76
|
-
'',
|
|
77
|
-
`| ${tr.dep} | ${tr.arr} | ${tr.dur} | ${tr.changes} | Route | Trip ID |`,
|
|
78
|
-
'|-----|-----|----------|-----------|-------|---------|',
|
|
79
|
-
];
|
|
80
|
-
for (const trip of trips) {
|
|
81
|
-
const dep = formatTime(trip.startTime, lang);
|
|
82
|
-
const arr = formatTime(trip.endTime, lang);
|
|
83
|
-
const dur = parseDuration(trip.duration);
|
|
84
|
-
const route = trip.legs.map(l => formatLegSummary(l, lang)).join(' > ');
|
|
85
|
-
lines.push(`| ${dep} | ${arr} | ${dur} | ${transfersLabel(trip.transfers, lang)} | ${route} | \`${trip.id}\` |`);
|
|
86
|
-
}
|
|
87
|
-
lines.push('');
|
|
88
|
-
lines.push(`*Use \`get_prices\` with trip IDs to see ticket prices. Use \`get_more_connections\` to see earlier/later trains.*`);
|
|
89
|
-
return lines.join('\n');
|
|
90
|
-
}
|
|
91
|
-
export function formatTripDetails(trip, lang = 'en') {
|
|
92
|
-
const tr = t(lang);
|
|
93
|
-
const lines = [
|
|
94
|
-
`**Trip Details** | ${formatDate(trip.startTime, lang)}`,
|
|
95
|
-
`${trip.origin.name} -> ${trip.destination.name} | ${parseDuration(trip.duration)} | ${transfersLabel(trip.transfers, lang)}`,
|
|
96
|
-
`Status: ${trip.tripStatus}`,
|
|
97
|
-
'',
|
|
98
|
-
];
|
|
99
|
-
for (let i = 0; i < trip.legs.length; i++) {
|
|
100
|
-
const leg = trip.legs[i];
|
|
101
|
-
if (leg.type === 'timed') {
|
|
102
|
-
const tl = leg;
|
|
103
|
-
const line = tl.service.publishedLineName || 'Train';
|
|
104
|
-
const operator = tl.service.operatorName || '';
|
|
105
|
-
const boardPlatform = tl.board.platform ? ` | ${tr.platform} ${tl.board.platform}` : '';
|
|
106
|
-
const alightPlatform = tl.alight.platform ? ` | ${tr.platform} ${tl.alight.platform}` : '';
|
|
107
|
-
lines.push(`### Leg ${i + 1}: ${line} ${operator}`.trim());
|
|
108
|
-
lines.push(`- **${formatTime(tl.board.departureTime, lang)}** ${tl.board.stopPlace.name}${boardPlatform}`);
|
|
109
|
-
if (tl.intermediateStops?.length) {
|
|
110
|
-
for (const stop of tl.intermediateStops) {
|
|
111
|
-
const time = stop.arrivalTime ? formatTime(stop.arrivalTime, lang) : '';
|
|
112
|
-
lines.push(` - ${time} ${stop.stopPlace.name}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
lines.push(`- **${formatTime(tl.alight.arrivalTime, lang)}** ${tl.alight.stopPlace.name}${alightPlatform}`);
|
|
116
|
-
if (tl.occupancy) {
|
|
117
|
-
const occ = [];
|
|
118
|
-
if (tl.occupancy.firstClass)
|
|
119
|
-
occ.push(`1st: ${tl.occupancy.firstClass}`);
|
|
120
|
-
if (tl.occupancy.secondClass)
|
|
121
|
-
occ.push(`2nd: ${tl.occupancy.secondClass}`);
|
|
122
|
-
if (occ.length)
|
|
123
|
-
lines.push(` Occupancy: ${occ.join(', ')}`);
|
|
124
|
-
}
|
|
125
|
-
lines.push(` ${tr.dur}: ${parseDuration(tl.duration)}`);
|
|
126
|
-
}
|
|
127
|
-
else if (leg.type === 'transfer') {
|
|
128
|
-
const tfer = leg;
|
|
129
|
-
lines.push(`### ${tr.transfer}: Walk ${parseDuration(tfer.duration)}`);
|
|
130
|
-
}
|
|
131
|
-
lines.push('');
|
|
132
|
-
}
|
|
133
|
-
lines.push(`*Use \`get_prices\` with trip ID \`${trip.id}\` to see ticket prices.*`);
|
|
134
|
-
return lines.join('\n');
|
|
135
|
-
}
|
|
136
|
-
export function formatPrices(results, lang = 'en') {
|
|
137
|
-
if (results.length === 0) {
|
|
138
|
-
return 'No price information available.';
|
|
139
|
-
}
|
|
140
|
-
const tr = t(lang);
|
|
141
|
-
const lines = [`**${tr.prices}**`, ''];
|
|
142
|
-
lines.push(`| Trip ID | 2nd Class | 1st Class |`);
|
|
143
|
-
lines.push('|---------|-----------|-----------|');
|
|
144
|
-
for (const r of results) {
|
|
145
|
-
const second = r.prices.find(p => p.class === '2');
|
|
146
|
-
const first = r.prices.find(p => p.class === '1');
|
|
147
|
-
const secondStr = second ? `CHF ${second.amount.toFixed(2)}` : '-';
|
|
148
|
-
const firstStr = first ? `CHF ${first.amount.toFixed(2)}` : '-';
|
|
149
|
-
lines.push(`| \`${r.tripId}\` | ${secondStr} | ${firstStr} |`);
|
|
150
|
-
}
|
|
151
|
-
lines.push('');
|
|
152
|
-
lines.push('*Prices are estimates. Use `get_ticket_link` to get the purchase link with final pricing.*');
|
|
153
|
-
return lines.join('\n');
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Build an SBB.ch deep link URL with connection pre-filled.
|
|
157
|
-
* SBB.ch URLs support de/fr/it/en; other languages fall back to `en`.
|
|
158
|
-
*/
|
|
159
|
-
export function buildSbbDeepLink(params) {
|
|
160
|
-
const { fromName, fromId, toName, toId, date, time } = params;
|
|
161
|
-
const linkLang = params.lang ? toSbbLinkLang(params.lang) : 'en';
|
|
162
|
-
const stops = JSON.stringify([
|
|
163
|
-
{ value: fromId, type: 'ID', label: fromName },
|
|
164
|
-
{ value: toId, type: 'ID', label: toName },
|
|
165
|
-
]);
|
|
166
|
-
const url = new URL(`https://www.sbb.ch/${linkLang}`);
|
|
167
|
-
url.searchParams.set('stops', stops);
|
|
168
|
-
url.searchParams.set('date', `"${date}"`);
|
|
169
|
-
url.searchParams.set('time', `"${time}"`);
|
|
170
|
-
url.searchParams.set('moment', '"DEPARTURE"');
|
|
171
|
-
url.searchParams.set('selected_trip', '0');
|
|
172
|
-
return url.toString();
|
|
173
|
-
}
|
|
174
|
-
export function formatTicketLink(tripId, deepLink, sbbLink, lang = 'en') {
|
|
175
|
-
const tr = t(lang);
|
|
176
|
-
const links = [];
|
|
177
|
-
if (sbbLink) {
|
|
178
|
-
links.push(`[${tr.buyTicket}](${sbbLink})`);
|
|
179
|
-
}
|
|
180
|
-
if (deepLink && deepLink !== sbbLink) {
|
|
181
|
-
links.push(`[Buy via affiliate](${deepLink})`);
|
|
182
|
-
}
|
|
183
|
-
if (links.length === 0) {
|
|
184
|
-
return `No ticket link available for trip \`${tripId}\`. The trip may have expired or is not bookable online.`;
|
|
185
|
-
}
|
|
186
|
-
return [
|
|
187
|
-
`**${tr.buyTicket}**`,
|
|
188
|
-
'',
|
|
189
|
-
`Trip: \`${tripId}\``,
|
|
190
|
-
'',
|
|
191
|
-
...links,
|
|
192
|
-
'',
|
|
193
|
-
`*${tr.opensInApp}*`,
|
|
194
|
-
].join('\n');
|
|
195
|
-
}
|
|
196
|
-
/** Append destination weather to formatted connections */
|
|
197
|
-
export async function appendWeatherToConnections(formatted, destinationLat, destinationLon, date, destinationName) {
|
|
198
|
-
// Weather stays English for now — swiss-weather-mcp getWeatherSummary() doesn't accept a language yet.
|
|
199
|
-
// TODO(v0.5.0): thread lang through once swiss-weather-mcp exposes it.
|
|
200
|
-
try {
|
|
201
|
-
const summary = await getWeatherSummary(destinationLat, destinationLon, date);
|
|
202
|
-
if (!summary)
|
|
203
|
-
return formatted;
|
|
204
|
-
return formatted + `\n\n**${destinationName} weather:** ${summary}`;
|
|
205
|
-
}
|
|
206
|
-
catch {
|
|
207
|
-
return formatted;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
//# sourceMappingURL=formatters.js.map
|
package/dist/formatters.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"formatters.js","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAErD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC,EAAE,MAAM,WAAW,CAAA;AAEtD,SAAS,UAAU,CAAC,GAAW,EAAE,IAAU;IACzC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAA;IACvB,OAAO,CAAC,CAAC,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;QAC1C,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,QAAQ,EAAE,eAAe;KAC1B,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,GAAW,EAAE,IAAU;IACzC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAA;IACvB,OAAO,CAAC,CAAC,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;QAC1C,OAAO,EAAE,OAAO;QAChB,GAAG,EAAE,SAAS;QACd,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,eAAe;KAC1B,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IAChC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAA;IACnD,IAAI,CAAC,KAAK;QAAE,OAAO,GAAG,CAAA;IACtB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;IACxC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;IACxC,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,IAAI,CAAA;AAC/C,CAAC;AAED,SAAS,cAAc,CAAC,CAAS,EAAE,IAAU;IAC3C,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAA;IAClB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC,MAAM,CAAA;IAC7B,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC,SAAS,CAAA;IAChC,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;AACvB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAsB,EAAE,OAAa,IAAI;IACtE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,oBAAoB,CAAA;IAC7B,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,SAAS,QAAQ,CAAC,MAAM,cAAc,EAAE,EAAE,CAAC,CAAA;IAC1D,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAA;IAC5C,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;IAE3B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,CAAC,CAAC,WAAW;YAC1B,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YAC/E,CAAC,CAAC,GAAG,CAAA;QACP,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,EAAE,QAAQ,MAAM,IAAI,CAAC,CAAA;IACvD,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAiB,EAAE,IAAU;IACrD,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,GAAoB,CAAA;QAC/B,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,iBAAiB,IAAI,OAAO,CAAA;QACpD,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAC/E,OAAO,GAAG,IAAI,GAAG,QAAQ,EAAE,CAAA;IAC7B,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC5B,MAAM,EAAE,GAAG,GAAuB,CAAA;QAClC,OAAO,QAAQ,aAAa,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAA;IAC7C,CAAC;IACD,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,UAAgC,EAAE,OAAa,IAAI;IACnF,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAA;IAC9B,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAA;IAClB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC,aAAa,CAAA;IACzB,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;IACtB,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;IAC9C,MAAM,KAAK,GAAG;QACZ,KAAK,KAAK,CAAC,MAAM,CAAC,IAAI,OAAO,KAAK,CAAC,WAAW,CAAC,IAAI,QAAQ,IAAI,EAAE;QACjE,oBAAoB,UAAU,CAAC,EAAE,oCAAoC;QACrE,EAAE;QACF,KAAK,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,OAAO,sBAAsB;QACzE,wDAAwD;KACzD,CAAA;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;QAC5C,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QAC1C,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACvE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;IAClH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACd,KAAK,CAAC,IAAI,CAAC,oHAAoH,CAAC,CAAA;IAEhI,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAe,EAAE,OAAa,IAAI;IAClE,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAA;IAClB,MAAM,KAAK,GAAG;QACZ,sBAAsB,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE;QACxD,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,MAAM,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE;QAC7H,WAAW,IAAI,CAAC,UAAU,EAAE;QAC5B,EAAE;KACH,CAAA;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAExB,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACzB,MAAM,EAAE,GAAG,GAAoB,CAAA;YAC/B,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,iBAAiB,IAAI,OAAO,CAAA;YACpD,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAA;YAC9C,MAAM,aAAa,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;YACvF,MAAM,cAAc,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;YAE1F,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,CAAA;YAC1D,KAAK,CAAC,IAAI,CAAC,OAAO,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,GAAG,aAAa,EAAE,CAAC,CAAA;YAE1G,IAAI,EAAE,CAAC,iBAAiB,EAAE,MAAM,EAAE,CAAC;gBACjC,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,iBAAiB,EAAE,CAAC;oBACxC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;oBACvE,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAA;gBAClD,CAAC;YACH,CAAC;YAED,KAAK,CAAC,IAAI,CAAC,OAAO,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,GAAG,cAAc,EAAE,CAAC,CAAA;YAE3G,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC;gBACjB,MAAM,GAAG,GAAG,EAAE,CAAA;gBACd,IAAI,EAAE,CAAC,SAAS,CAAC,UAAU;oBAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,CAAA;gBACxE,IAAI,EAAE,CAAC,SAAS,CAAC,WAAW;oBAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAA;gBAC1E,IAAI,GAAG,CAAC,MAAM;oBAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC9D,CAAC;YAED,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,KAAK,aAAa,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;QAC1D,CAAC;aAAM,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,GAAuB,CAAA;YACpC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,QAAQ,UAAU,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;QACxE,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAChB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,sCAAsC,IAAI,CAAC,EAAE,2BAA2B,CAAC,CAAA;IAEpF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAA2B,EAAE,OAAa,IAAI;IACzE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,iCAAiC,CAAA;IAC1C,CAAC;IAED,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAA;IAClB,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAA;IACtC,KAAK,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAA;IACjD,KAAK,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAA;IAEjD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAA;QAClD,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAA;QACjD,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAA;QAClE,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAA;QAC/D,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,QAAQ,SAAS,MAAM,QAAQ,IAAI,CAAC,CAAA;IAChE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACd,KAAK,CAAC,IAAI,CAAC,4FAA4F,CAAC,CAAA;IAExG,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAQhC;IACC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAM,CAAA;IAC7D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAEhE,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC;QAC3B,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE;QAC9C,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;KAC3C,CAAC,CAAA;IAEF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,sBAAsB,QAAQ,EAAE,CAAC,CAAA;IACrD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IACpC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,IAAI,GAAG,CAAC,CAAA;IACzC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,IAAI,GAAG,CAAC,CAAA;IACzC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAA;IAC7C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,GAAG,CAAC,CAAA;IAE1C,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAA;AACvB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,MAAc,EACd,QAAiB,EACjB,OAAgB,EAChB,OAAa,IAAI;IAEjB,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAA;IAClB,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,SAAS,KAAK,OAAO,GAAG,CAAC,CAAA;IAC7C,CAAC;IACD,IAAI,QAAQ,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,uBAAuB,QAAQ,GAAG,CAAC,CAAA;IAChD,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,uCAAuC,MAAM,0DAA0D,CAAA;IAChH,CAAC;IAED,OAAO;QACL,KAAK,EAAE,CAAC,SAAS,IAAI;QACrB,EAAE;QACF,WAAW,MAAM,IAAI;QACrB,EAAE;QACF,GAAG,KAAK;QACR,EAAE;QACF,IAAI,EAAE,CAAC,UAAU,GAAG;KACrB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACd,CAAC;AAED,0DAA0D;AAC1D,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,SAAiB,EACjB,cAAsB,EACtB,cAAsB,EACtB,IAAY,EACZ,eAAuB;IAEvB,uGAAuG;IACvG,uEAAuE;IACvE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,cAAc,EAAE,cAAc,EAAE,IAAI,CAAC,CAAA;QAC7E,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAA;QAC9B,OAAO,SAAS,GAAG,SAAS,eAAe,eAAe,OAAO,EAAE,CAAA;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC"}
|
package/dist/http.d.ts
DELETED
package/dist/http.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
3
|
-
import { createMcpExpressApp } from '@modelcontextprotocol/sdk/server/express.js';
|
|
4
|
-
import { isSmapiConfigured } from './transport/index.js';
|
|
5
|
-
import { isSwissTripConfigured } from './swisstrip.js';
|
|
6
|
-
import { createSbbMcpServer } from './tools.js';
|
|
7
|
-
import { isRateLimited } from './rate-limit.js';
|
|
8
|
-
const useMock = !isSmapiConfigured();
|
|
9
|
-
const useCloud = isSwissTripConfigured();
|
|
10
|
-
async function main() {
|
|
11
|
-
const port = parseInt(process.env.PORT || '3001');
|
|
12
|
-
const app = createMcpExpressApp({ host: '0.0.0.0' });
|
|
13
|
-
app.post('/mcp', async (req, res) => {
|
|
14
|
-
const ip = req.ip || req.socket.remoteAddress || 'unknown';
|
|
15
|
-
if (isRateLimited(ip)) {
|
|
16
|
-
res.status(429).json({ error: 'Too many requests. Max 60 per minute.' });
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
const server = createSbbMcpServer();
|
|
20
|
-
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
|
|
21
|
-
try {
|
|
22
|
-
await server.connect(transport);
|
|
23
|
-
await transport.handleRequest(req, res, req.body);
|
|
24
|
-
}
|
|
25
|
-
finally {
|
|
26
|
-
await transport.close();
|
|
27
|
-
await server.close();
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
app.get('/health', (_req, res) => {
|
|
31
|
-
res.json({ status: 'ok', mode: useMock ? 'mock' : 'live' });
|
|
32
|
-
});
|
|
33
|
-
app.get('/.well-known/mcp/server-card.json', (_req, res) => {
|
|
34
|
-
res.json({
|
|
35
|
-
name: 'sbb-mcp',
|
|
36
|
-
description: 'Swiss Federal Railways (SBB/CFF/FFS) — train schedules, prices, and ticket links',
|
|
37
|
-
homepage: 'https://github.com/Fabsbags/sbb-mcp',
|
|
38
|
-
configSchema: {
|
|
39
|
-
type: 'object',
|
|
40
|
-
properties: {
|
|
41
|
-
SMAPI_CLIENT_ID: { type: 'string', description: 'SBB SMAPI OAuth 2.0 client ID' },
|
|
42
|
-
SMAPI_CLIENT_SECRET: { type: 'string', description: 'SBB SMAPI OAuth 2.0 client secret' },
|
|
43
|
-
SMAPI_SCOPE: { type: 'string', description: 'SBB SMAPI OAuth scope' },
|
|
44
|
-
SMAPI_CONTRACT_ID: { type: 'string', description: 'SBB business contract ID' },
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
app.listen(port, '0.0.0.0', () => {
|
|
50
|
-
console.log(`[sbb-mcp] HTTP server listening on port ${port}`);
|
|
51
|
-
console.log(`[sbb-mcp] MCP endpoint: http://0.0.0.0:${port}/mcp`);
|
|
52
|
-
console.log(`[sbb-mcp] Mode: ${useMock ? 'MOCK' : 'LIVE'}`);
|
|
53
|
-
console.log(`[sbb-mcp] SwissTrip cloud: ${useCloud ? 'enabled' : 'disabled'}`);
|
|
54
|
-
console.log(`[sbb-mcp] Rate limit: 60 req/min per IP`);
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
main().catch((err) => {
|
|
58
|
-
console.error('[sbb-mcp] Fatal error:', err);
|
|
59
|
-
process.exit(1);
|
|
60
|
-
});
|
|
61
|
-
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Language helpers for sbb-mcp.
|
|
3
|
-
*
|
|
4
|
-
* Re-exports the shared `sbb-i18n` primitives and adds MCP-specific helpers:
|
|
5
|
-
*
|
|
6
|
-
* - `toLocale(lang)` — maps our 9 language codes to BCP-47 locale tags for
|
|
7
|
-
* `Intl.DateTimeFormat`. Swiss languages get `-CH` (so e.g. dates render as
|
|
8
|
-
* DD.MM.YYYY for de-CH, not DD/MM/YYYY); non-Swiss use their primary region.
|
|
9
|
-
* - `SBB_LINK_LANGS` — languages SBB.ch actually supports in URL paths. The
|
|
10
|
-
* rest fall back to English for deep links.
|
|
11
|
-
*/
|
|
12
|
-
import type { Lang } from 'sbb-i18n';
|
|
13
|
-
export type { Lang, Translations } from 'sbb-i18n';
|
|
14
|
-
export { resolveLang, t, SUPPORTED_LANGS, isLang } from 'sbb-i18n';
|
|
15
|
-
/** BCP-47 locale tag for `Intl.DateTimeFormat`. Swiss languages use -CH variants. */
|
|
16
|
-
export declare function toLocale(lang: Lang): string;
|
|
17
|
-
/**
|
|
18
|
-
* Languages SBB.ch supports in its public URLs (/de, /fr, /it, /en).
|
|
19
|
-
* Other input languages fall back to English when building deep links.
|
|
20
|
-
*/
|
|
21
|
-
export declare const SBB_LINK_LANGS: readonly Lang[];
|
|
22
|
-
export declare function toSbbLinkLang(lang: Lang): 'de' | 'fr' | 'it' | 'en';
|
package/dist/i18n.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Language helpers for sbb-mcp.
|
|
3
|
-
*
|
|
4
|
-
* Re-exports the shared `sbb-i18n` primitives and adds MCP-specific helpers:
|
|
5
|
-
*
|
|
6
|
-
* - `toLocale(lang)` — maps our 9 language codes to BCP-47 locale tags for
|
|
7
|
-
* `Intl.DateTimeFormat`. Swiss languages get `-CH` (so e.g. dates render as
|
|
8
|
-
* DD.MM.YYYY for de-CH, not DD/MM/YYYY); non-Swiss use their primary region.
|
|
9
|
-
* - `SBB_LINK_LANGS` — languages SBB.ch actually supports in URL paths. The
|
|
10
|
-
* rest fall back to English for deep links.
|
|
11
|
-
*/
|
|
12
|
-
export { resolveLang, t, SUPPORTED_LANGS, isLang } from 'sbb-i18n';
|
|
13
|
-
const LOCALE_MAP = {
|
|
14
|
-
de: 'de-CH',
|
|
15
|
-
fr: 'fr-CH',
|
|
16
|
-
it: 'it-CH',
|
|
17
|
-
en: 'en-CH',
|
|
18
|
-
es: 'es-ES',
|
|
19
|
-
pt: 'pt-PT',
|
|
20
|
-
ru: 'ru-RU',
|
|
21
|
-
ar: 'ar',
|
|
22
|
-
zh: 'zh-CN',
|
|
23
|
-
};
|
|
24
|
-
/** BCP-47 locale tag for `Intl.DateTimeFormat`. Swiss languages use -CH variants. */
|
|
25
|
-
export function toLocale(lang) {
|
|
26
|
-
return LOCALE_MAP[lang];
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Languages SBB.ch supports in its public URLs (/de, /fr, /it, /en).
|
|
30
|
-
* Other input languages fall back to English when building deep links.
|
|
31
|
-
*/
|
|
32
|
-
export const SBB_LINK_LANGS = ['de', 'fr', 'it', 'en'];
|
|
33
|
-
export function toSbbLinkLang(lang) {
|
|
34
|
-
return SBB_LINK_LANGS.includes(lang) ? lang : 'en';
|
|
35
|
-
}
|
|
36
|
-
//# sourceMappingURL=i18n.js.map
|
package/dist/i18n.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAElE,MAAM,UAAU,GAAyB;IACvC,EAAE,EAAE,OAAO;IACX,EAAE,EAAE,OAAO;IACX,EAAE,EAAE,OAAO;IACX,EAAE,EAAE,OAAO;IACX,EAAE,EAAE,OAAO;IACX,EAAE,EAAE,OAAO;IACX,EAAE,EAAE,OAAO;IACX,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,OAAO;CACZ,CAAA;AAED,qFAAqF;AACrF,MAAM,UAAU,QAAQ,CAAC,IAAU;IACjC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAU,CAAA;AAEhF,MAAM,UAAU,aAAa,CAAC,IAAU;IACtC,OAAQ,cAAoC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,IAAkC,CAAC,CAAC,CAAC,IAAI,CAAA;AAC1G,CAAC"}
|
package/dist/index.d.ts
DELETED
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAE/C,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAA;IACnC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAA;IAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAE/B,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAA;QACjF,OAAO,CAAC,KAAK,CAAC,+EAA+E,CAAC,CAAA;IAChG,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACnD,CAAC;IAED,IAAI,qBAAqB,EAAE,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAA;IACnF,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAA;IAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
|
package/dist/journey.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { Place, Trip, TripsCollection, TripSearchParams, PlaceSearchParams } from './types.js';
|
|
2
|
-
export declare function searchPlaces(params: PlaceSearchParams): Promise<Place[]>;
|
|
3
|
-
export declare function searchTrips(params: TripSearchParams): Promise<TripsCollection>;
|
|
4
|
-
export declare function getTrip(tripId: string, stopBehavior?: 'ORIGIN_DESTINATION_ONLY' | 'REAL_BOARDING_ALIGHTING'): Promise<Trip>;
|
|
5
|
-
export declare function paginateTrips(collectionId: string, direction: 'next' | 'previous'): Promise<TripsCollection>;
|