sbb-mcp 0.4.3 → 0.5.1
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 +25 -214
- package/dist/index.js +47 -19
- package/package.json +10 -33
- 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 -14
- package/dist/cache.js +0 -62
- 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 -35
- package/dist/formatters.js +0 -285
- package/dist/formatters.js.map +0 -1
- package/dist/http.d.ts +0 -2
- package/dist/http.js +0 -117
- 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/look2book.d.ts +0 -98
- package/dist/look2book.js +0 -212
- package/dist/look2book.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 -84
- 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/shortlink.d.ts +0 -60
- package/dist/shortlink.js +0 -122
- package/dist/shortlink.js.map +0 -1
- package/dist/structured.d.ts +0 -125
- package/dist/structured.js +0 -134
- package/dist/structured.js.map +0 -1
- package/dist/swisstrip.d.ts +0 -41
- package/dist/swisstrip.js +0 -135
- package/dist/swisstrip.js.map +0 -1
- package/dist/tools.d.ts +0 -40
- package/dist/tools.js +0 -509
- package/dist/tools.js.map +0 -1
- package/dist/transport/index.d.ts +0 -10
- package/dist/transport/index.js +0 -13
- package/dist/transport/index.js.map +0 -1
- package/dist/transport/setup.d.ts +0 -1
- package/dist/transport/setup.js +0 -59
- package/dist/transport/setup.js.map +0 -1
- package/dist/transport/smapi-auth.d.ts +0 -14
- package/dist/transport/smapi-auth.js +0 -89
- package/dist/transport/smapi-auth.js.map +0 -1
- package/dist/transport/smapi-client.d.ts +0 -46
- package/dist/transport/smapi-client.js +0 -186
- package/dist/transport/smapi-client.js.map +0 -1
- package/dist/transport/smapi-journey.d.ts +0 -29
- package/dist/transport/smapi-journey.js +0 -91
- 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 -48
- package/dist/transport/smapi-prices.js +0 -144
- package/dist/transport/smapi-prices.js.map +0 -1
- package/dist/transport/smapi-types.d.ts +0 -181
- 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 -60
- package/dist/widgets.js +0 -184
- package/dist/widgets.js.map +0 -1
- package/web/dist/widgets.css +0 -1
- package/web/dist/widgets.js +0 -1
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { SmapiPriceResult, SmapiOfferResult, SmapiTraveler } from './smapi-types.js';
|
|
2
|
-
/**
|
|
3
|
-
* ## Endpoint inventory (observed against b2p-int.api.sbb.ch on 2026-04-23)
|
|
4
|
-
*
|
|
5
|
-
* GET /api/networks — known working ✓
|
|
6
|
-
* GET /api/trip-offers?tripId=…&… — 400 "At least one of passengers
|
|
7
|
-
* or dogs or bikes must be set"
|
|
8
|
-
* (contract + auth ok; schema below)
|
|
9
|
-
* POST /api/v2/prices?tripId=… — 400 "Failed to read request"
|
|
10
|
-
* (contract + auth ok; need right
|
|
11
|
-
* body shape)
|
|
12
|
-
* /api/prices (v1) — 403 NOT FOUND at this gateway
|
|
13
|
-
*
|
|
14
|
-
* The legacy fallback to `/api/prices` for traveler-less lookups has been
|
|
15
|
-
* removed — that endpoint doesn't exist in the current Ticketing API. Both
|
|
16
|
-
* exported functions now always hit their v2 / correct paths.
|
|
17
|
-
*
|
|
18
|
-
* The exact query-param / request-body shapes for `/api/trip-offers` and
|
|
19
|
-
* `/api/v2/prices` still need live-tripId verification once Journey API is
|
|
20
|
-
* approved and we can fetch a real tripId to probe against. The payload
|
|
21
|
-
* schemas in this file are inferred from SBB's RFC 9457 error messages and
|
|
22
|
-
* may need refinement — tracked in docs/sbb-train-tickets-implementation.md
|
|
23
|
-
* under "Known limits".
|
|
24
|
-
*/
|
|
25
|
-
/**
|
|
26
|
-
* Fetch price points for a single trip via `POST /api/v2/prices?tripId=…`.
|
|
27
|
-
*
|
|
28
|
-
* SBB's /api/prices (v1) endpoint was removed — the current Ticketing API
|
|
29
|
-
* only has v2. Always requires passenger details (id, age, reduction).
|
|
30
|
-
*
|
|
31
|
-
* Returns [] on any error so one bad trip doesn't blow up a batch lookup.
|
|
32
|
-
*/
|
|
33
|
-
export declare function getTripPrices(tripIds: string[], travelers?: SmapiTraveler[], acceptLanguage?: string): Promise<SmapiPriceResult[]>;
|
|
34
|
-
/**
|
|
35
|
-
* Fetch trip offers + affiliate deep link via `GET /api/trip-offers?tripId=…`.
|
|
36
|
-
*
|
|
37
|
-
* The legacy `POST /api/trip-offers` with JSON body is obsolete — the current
|
|
38
|
-
* contract is GET with query parameters. The `passengers` param is required
|
|
39
|
-
* (at least one of passengers / dogs / bikes).
|
|
40
|
-
*
|
|
41
|
-
* We send passengers as a URL-encoded JSON array because simple form encoding
|
|
42
|
-
* drops structured fields (id/age/reduction). This mirrors how most b2p
|
|
43
|
-
* partner integrations pass structured collections to their GET endpoints.
|
|
44
|
-
*
|
|
45
|
-
* Note: this call burns the Look2Book offers ratio — only invoke when the
|
|
46
|
-
* user actually intends to see prices / buy.
|
|
47
|
-
*/
|
|
48
|
-
export declare function getTripOffers(tripId: string, travelers: SmapiTraveler[], acceptLanguage?: string): Promise<SmapiOfferResult>;
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
// AUTO-GENERATED from packages/sbb-transport/src/smapi-prices.ts
|
|
2
|
-
// Run `npm run sync:transport` in packages/sbb-mcp to refresh.
|
|
3
|
-
// Do not edit this file directly — edit the sbb-transport source instead.
|
|
4
|
-
import { smapiRequest, getTicketingBaseUrl } from './smapi-client.js';
|
|
5
|
-
/**
|
|
6
|
-
* ## Endpoint inventory (observed against b2p-int.api.sbb.ch on 2026-04-23)
|
|
7
|
-
*
|
|
8
|
-
* GET /api/networks — known working ✓
|
|
9
|
-
* GET /api/trip-offers?tripId=…&… — 400 "At least one of passengers
|
|
10
|
-
* or dogs or bikes must be set"
|
|
11
|
-
* (contract + auth ok; schema below)
|
|
12
|
-
* POST /api/v2/prices?tripId=… — 400 "Failed to read request"
|
|
13
|
-
* (contract + auth ok; need right
|
|
14
|
-
* body shape)
|
|
15
|
-
* /api/prices (v1) — 403 NOT FOUND at this gateway
|
|
16
|
-
*
|
|
17
|
-
* The legacy fallback to `/api/prices` for traveler-less lookups has been
|
|
18
|
-
* removed — that endpoint doesn't exist in the current Ticketing API. Both
|
|
19
|
-
* exported functions now always hit their v2 / correct paths.
|
|
20
|
-
*
|
|
21
|
-
* The exact query-param / request-body shapes for `/api/trip-offers` and
|
|
22
|
-
* `/api/v2/prices` still need live-tripId verification once Journey API is
|
|
23
|
-
* approved and we can fetch a real tripId to probe against. The payload
|
|
24
|
-
* schemas in this file are inferred from SBB's RFC 9457 error messages and
|
|
25
|
-
* may need refinement — tracked in docs/sbb-train-tickets-implementation.md
|
|
26
|
-
* under "Known limits".
|
|
27
|
-
*/
|
|
28
|
-
/**
|
|
29
|
-
* Fetch price points for a single trip via `POST /api/v2/prices?tripId=…`.
|
|
30
|
-
*
|
|
31
|
-
* SBB's /api/prices (v1) endpoint was removed — the current Ticketing API
|
|
32
|
-
* only has v2. Always requires passenger details (id, age, reduction).
|
|
33
|
-
*
|
|
34
|
-
* Returns [] on any error so one bad trip doesn't blow up a batch lookup.
|
|
35
|
-
*/
|
|
36
|
-
export async function getTripPrices(tripIds, travelers, acceptLanguage) {
|
|
37
|
-
const effectiveTravelers = travelers && travelers.length > 0
|
|
38
|
-
? travelers
|
|
39
|
-
: [{ id: 'p0', type: 'ADULT' }];
|
|
40
|
-
return Promise.all(tripIds.map(async (tripId) => {
|
|
41
|
-
const params = new URLSearchParams({ tripId });
|
|
42
|
-
try {
|
|
43
|
-
const data = await smapiRequest(getTicketingBaseUrl(), `/api/v2/prices?${params}`, {
|
|
44
|
-
method: 'POST',
|
|
45
|
-
body: { passengers: effectiveTravelers.map(toPassengerPayload) },
|
|
46
|
-
acceptLanguage,
|
|
47
|
-
});
|
|
48
|
-
const prices = data.prices ?? [];
|
|
49
|
-
return {
|
|
50
|
-
tripId,
|
|
51
|
-
prices: prices.map((p) => ({
|
|
52
|
-
amount: p.amount,
|
|
53
|
-
currency: p.currency || 'CHF',
|
|
54
|
-
class: (p.class || '2'),
|
|
55
|
-
reductionCard: p.reductionCard,
|
|
56
|
-
})),
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
catch (err) {
|
|
60
|
-
console.warn(`[smapi-prices] Failed to get price for trip ${tripId}:`, err);
|
|
61
|
-
return { tripId, prices: [] };
|
|
62
|
-
}
|
|
63
|
-
}));
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Fetch trip offers + affiliate deep link via `GET /api/trip-offers?tripId=…`.
|
|
67
|
-
*
|
|
68
|
-
* The legacy `POST /api/trip-offers` with JSON body is obsolete — the current
|
|
69
|
-
* contract is GET with query parameters. The `passengers` param is required
|
|
70
|
-
* (at least one of passengers / dogs / bikes).
|
|
71
|
-
*
|
|
72
|
-
* We send passengers as a URL-encoded JSON array because simple form encoding
|
|
73
|
-
* drops structured fields (id/age/reduction). This mirrors how most b2p
|
|
74
|
-
* partner integrations pass structured collections to their GET endpoints.
|
|
75
|
-
*
|
|
76
|
-
* Note: this call burns the Look2Book offers ratio — only invoke when the
|
|
77
|
-
* user actually intends to see prices / buy.
|
|
78
|
-
*/
|
|
79
|
-
export async function getTripOffers(tripId, travelers, acceptLanguage) {
|
|
80
|
-
const passengers = (travelers.length > 0 ? travelers : [{ id: 'p0', type: 'ADULT' }])
|
|
81
|
-
.map(toPassengerPayload);
|
|
82
|
-
const params = new URLSearchParams({
|
|
83
|
-
tripId,
|
|
84
|
-
passengers: JSON.stringify(passengers),
|
|
85
|
-
});
|
|
86
|
-
const data = await smapiRequest(getTicketingBaseUrl(), `/api/trip-offers?${params}`, { method: 'GET', acceptLanguage });
|
|
87
|
-
// Extract affiliate deep link from HATEOAS `_links` (OSDM convention) or
|
|
88
|
-
// top-level `links` (legacy shape) — we accept either to stay resilient
|
|
89
|
-
// across spec revisions.
|
|
90
|
-
const hateoas = ((data._links ?? data.links) ?? []);
|
|
91
|
-
const affiliateLink = hateoas.find((l) => l.rel === 'online-offers')?.href;
|
|
92
|
-
return {
|
|
93
|
-
tripId,
|
|
94
|
-
containers: [], // Full offer parsing not needed for deep-link flow
|
|
95
|
-
affiliateDeepLink: affiliateLink,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Map our internal SmapiTraveler → SBB's b2p passenger payload shape.
|
|
100
|
-
*
|
|
101
|
-
* SBB's /api/trip-offers expects `{ id, age, reduction }` per passenger
|
|
102
|
-
* (observed from the RFC 9457 error: "Passenger data has to contain id,
|
|
103
|
-
* age and reduction."). Our SmapiTraveler uses {id, type, dateOfBirth,
|
|
104
|
-
* reductionCard}; we translate.
|
|
105
|
-
*
|
|
106
|
-
* - age: derived from dateOfBirth when present; else default 30 for ADULT,
|
|
107
|
-
* 10 for CHILD (b2p classifies by age bracket, not by type)
|
|
108
|
-
* - reduction: mapped from reductionCard; NONE → 'NO_REDUCTION' by default
|
|
109
|
-
*/
|
|
110
|
-
function toPassengerPayload(t) {
|
|
111
|
-
return {
|
|
112
|
-
id: t.id || 'p0',
|
|
113
|
-
age: deriveAge(t),
|
|
114
|
-
reduction: mapReduction(t.reductionCard),
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
function deriveAge(t) {
|
|
118
|
-
if (t.dateOfBirth) {
|
|
119
|
-
const dob = new Date(t.dateOfBirth);
|
|
120
|
-
if (!Number.isNaN(dob.getTime())) {
|
|
121
|
-
const now = new Date();
|
|
122
|
-
let age = now.getFullYear() - dob.getFullYear();
|
|
123
|
-
const m = now.getMonth() - dob.getMonth();
|
|
124
|
-
if (m < 0 || (m === 0 && now.getDate() < dob.getDate()))
|
|
125
|
-
age--;
|
|
126
|
-
return age;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return t.type === 'CHILD' ? 10 : 30;
|
|
130
|
-
}
|
|
131
|
-
function mapReduction(card) {
|
|
132
|
-
switch (card) {
|
|
133
|
-
case 'HALF_FARE':
|
|
134
|
-
return 'HALFFARE';
|
|
135
|
-
case 'GA':
|
|
136
|
-
return 'GA';
|
|
137
|
-
case 'NONE':
|
|
138
|
-
case undefined:
|
|
139
|
-
return 'NO_REDUCTION';
|
|
140
|
-
default:
|
|
141
|
-
return 'NO_REDUCTION';
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
//# sourceMappingURL=smapi-prices.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"smapi-prices.js","sourceRoot":"","sources":["../../src/transport/smapi-prices.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
export type SmapiPlaceType = 'StopPlace' | 'Address' | 'PointOfInterest';
|
|
2
|
-
export type SmapiGeoPosition = {
|
|
3
|
-
longitude: number;
|
|
4
|
-
latitude: number;
|
|
5
|
-
};
|
|
6
|
-
export type SmapiPlaceRef = {
|
|
7
|
-
objectType: 'StopPlaceRef' | 'AddressRef' | 'PointOfInterestRef';
|
|
8
|
-
stopPlaceRef?: string;
|
|
9
|
-
};
|
|
10
|
-
export type SmapiPlace = {
|
|
11
|
-
objectType: SmapiPlaceType;
|
|
12
|
-
id: string;
|
|
13
|
-
name: string;
|
|
14
|
-
geoPosition?: SmapiGeoPosition;
|
|
15
|
-
ref?: SmapiPlaceRef;
|
|
16
|
-
};
|
|
17
|
-
export type SmapiTripStatus = 'PLANNED' | 'CONFIRMED' | 'CHANGED' | 'CANCELLED';
|
|
18
|
-
export type SmapiTimedLeg = {
|
|
19
|
-
type: 'timed';
|
|
20
|
-
board: {
|
|
21
|
-
stopPlace: SmapiPlace;
|
|
22
|
-
departureTime: string;
|
|
23
|
-
platform?: string;
|
|
24
|
-
};
|
|
25
|
-
alight: {
|
|
26
|
-
stopPlace: SmapiPlace;
|
|
27
|
-
arrivalTime: string;
|
|
28
|
-
platform?: string;
|
|
29
|
-
};
|
|
30
|
-
service: {
|
|
31
|
-
publishedLineName?: string;
|
|
32
|
-
operatorName?: string;
|
|
33
|
-
};
|
|
34
|
-
duration: string;
|
|
35
|
-
intermediateStops?: Array<{
|
|
36
|
-
stopPlace: SmapiPlace;
|
|
37
|
-
arrivalTime?: string;
|
|
38
|
-
departureTime?: string;
|
|
39
|
-
}>;
|
|
40
|
-
occupancy?: {
|
|
41
|
-
firstClass?: 'LOW' | 'MEDIUM' | 'HIGH' | 'UNKNOWN';
|
|
42
|
-
secondClass?: 'LOW' | 'MEDIUM' | 'HIGH' | 'UNKNOWN';
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
export type SmapiTransferLeg = {
|
|
46
|
-
type: 'transfer';
|
|
47
|
-
start: SmapiPlaceRef;
|
|
48
|
-
end: SmapiPlaceRef;
|
|
49
|
-
duration: string;
|
|
50
|
-
transferMode: string;
|
|
51
|
-
};
|
|
52
|
-
export type SmapiContinuousLeg = {
|
|
53
|
-
type: 'continuous';
|
|
54
|
-
service: {
|
|
55
|
-
providerName?: string;
|
|
56
|
-
};
|
|
57
|
-
duration: string;
|
|
58
|
-
};
|
|
59
|
-
export type SmapiTripLeg = SmapiTimedLeg | SmapiTransferLeg | SmapiContinuousLeg;
|
|
60
|
-
export type SmapiTrip = {
|
|
61
|
-
id: string;
|
|
62
|
-
origin: SmapiPlace;
|
|
63
|
-
destination: SmapiPlace;
|
|
64
|
-
startTime: string;
|
|
65
|
-
endTime: string;
|
|
66
|
-
duration: string;
|
|
67
|
-
transfers: number;
|
|
68
|
-
legs: SmapiTripLeg[];
|
|
69
|
-
tripStatus: SmapiTripStatus;
|
|
70
|
-
};
|
|
71
|
-
export type SmapiTripSummary = {
|
|
72
|
-
id: string;
|
|
73
|
-
origin: SmapiPlace;
|
|
74
|
-
destination: SmapiPlace;
|
|
75
|
-
startTime: string;
|
|
76
|
-
endTime: string;
|
|
77
|
-
duration: string;
|
|
78
|
-
transfers: number;
|
|
79
|
-
};
|
|
80
|
-
export type SmapiTripsCollection = {
|
|
81
|
-
id: string;
|
|
82
|
-
trips: SmapiTrip[];
|
|
83
|
-
tripSummaries: SmapiTripSummary[];
|
|
84
|
-
links?: {
|
|
85
|
-
next?: string;
|
|
86
|
-
previous?: string;
|
|
87
|
-
};
|
|
88
|
-
warnings?: string[];
|
|
89
|
-
};
|
|
90
|
-
export type SmapiTransportMode = 'HIGH_SPEED_TRAIN' | 'HISTORIC_TRAIN' | 'INTERCITY' | 'REGIONAL' | 'INTERREGIONAL' | 'URBAN' | 'TRAIN' | 'TRAM' | 'UNDERGROUND' | 'NIGHT_TRAIN' | 'SHARED_TAXI' | 'MOTOR_RAIL' | 'MOUNTAIN_TRAIN' | 'PLANE' | 'COACH_GROUP' | 'SHIP' | 'BUS';
|
|
91
|
-
export type SmapiTripSearchParams = {
|
|
92
|
-
origin: string;
|
|
93
|
-
destination: string;
|
|
94
|
-
departureTime?: string;
|
|
95
|
-
arrivalTime?: string;
|
|
96
|
-
transferLimit?: number;
|
|
97
|
-
vias?: Array<{
|
|
98
|
-
stopPlaceRef: string;
|
|
99
|
-
dwellTime?: string;
|
|
100
|
-
}>;
|
|
101
|
-
ptModeFilter?: {
|
|
102
|
-
exclude: boolean;
|
|
103
|
-
transportModes: SmapiTransportMode[];
|
|
104
|
-
};
|
|
105
|
-
};
|
|
106
|
-
export type SmapiPlaceSearchParams = {
|
|
107
|
-
name: string;
|
|
108
|
-
type?: 'STOP' | 'ADDRESS' | 'POI';
|
|
109
|
-
numberOfResults?: number;
|
|
110
|
-
};
|
|
111
|
-
export type SmapiReductionCard = 'HALF_FARE' | 'GA' | 'NONE';
|
|
112
|
-
export type SmapiTraveler = {
|
|
113
|
-
id: string;
|
|
114
|
-
type: 'ADULT' | 'CHILD';
|
|
115
|
-
dateOfBirth?: string;
|
|
116
|
-
reductionCard?: SmapiReductionCard;
|
|
117
|
-
firstName?: string;
|
|
118
|
-
lastName?: string;
|
|
119
|
-
};
|
|
120
|
-
export type SmapiPrice = {
|
|
121
|
-
amount: number;
|
|
122
|
-
currency: string;
|
|
123
|
-
class: '1' | '2';
|
|
124
|
-
reductionCard?: SmapiReductionCard;
|
|
125
|
-
};
|
|
126
|
-
export type SmapiPriceResult = {
|
|
127
|
-
tripId: string;
|
|
128
|
-
prices: SmapiPrice[];
|
|
129
|
-
};
|
|
130
|
-
export type SmapiOfferCategory = 'TRANSPORT' | 'RESERVATION' | 'ANCILLARY';
|
|
131
|
-
export type SmapiOffer = {
|
|
132
|
-
offerId: string;
|
|
133
|
-
category: SmapiOfferCategory;
|
|
134
|
-
price: SmapiPrice;
|
|
135
|
-
validUntil: string;
|
|
136
|
-
affiliateLink?: string;
|
|
137
|
-
};
|
|
138
|
-
export type SmapiOfferContainer = {
|
|
139
|
-
offers: SmapiOffer[];
|
|
140
|
-
totalPrice: SmapiPrice;
|
|
141
|
-
};
|
|
142
|
-
export type SmapiOfferResult = {
|
|
143
|
-
tripId: string;
|
|
144
|
-
containers: SmapiOfferContainer[];
|
|
145
|
-
affiliateDeepLink?: string;
|
|
146
|
-
};
|
|
147
|
-
/**
|
|
148
|
-
* Error type per RFC 9457 (Problem Details for HTTP APIs), which obsoletes
|
|
149
|
-
* RFC 7807 with the `code` and `pointers[]` extensions. SBB's cookbook still
|
|
150
|
-
* cites 7807 but the Journey OpenAPI v1.3.17 produces 9457 — the formats are
|
|
151
|
-
* compatible: 9457 just adds optional fields. Parse leniently and surface
|
|
152
|
-
* pointers in logs to make support tickets actionable.
|
|
153
|
-
*/
|
|
154
|
-
export type SmapiProblemPointer = {
|
|
155
|
-
code?: string;
|
|
156
|
-
type?: string;
|
|
157
|
-
title?: string;
|
|
158
|
-
status?: number;
|
|
159
|
-
detail?: string;
|
|
160
|
-
instance?: string;
|
|
161
|
-
/** JSON pointer into the request body for the problematic attribute. */
|
|
162
|
-
requestPointer?: string;
|
|
163
|
-
/** JSON pointer into the response body for the problematic attribute. */
|
|
164
|
-
responsePointer?: string;
|
|
165
|
-
/** Identifier of the originating server, useful when SBB chains backends. */
|
|
166
|
-
originator?: string;
|
|
167
|
-
};
|
|
168
|
-
export type SmapiProblem = {
|
|
169
|
-
/** RFC 9457 short error code; optional in 3.1, mandatory in upcoming. */
|
|
170
|
-
code?: string;
|
|
171
|
-
type: string;
|
|
172
|
-
title?: string;
|
|
173
|
-
status?: number;
|
|
174
|
-
detail?: string;
|
|
175
|
-
/** Absolute URI identifying this specific occurrence (RFC 9457). */
|
|
176
|
-
instance?: string;
|
|
177
|
-
/** Per-attribute problem pointers (RFC 9457). */
|
|
178
|
-
pointers?: SmapiProblemPointer[];
|
|
179
|
-
/** SBB extension: end-user-translatable messages (Accept-Language honored). */
|
|
180
|
-
displayMessages?: string[];
|
|
181
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"smapi-types.js","sourceRoot":"","sources":["../../src/transport/smapi-types.ts"],"names":[],"mappings":""}
|
package/dist/types.d.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
export type PlaceType = 'StopPlace' | 'Address' | 'PointOfInterest';
|
|
2
|
-
export type GeoPosition = {
|
|
3
|
-
longitude: number;
|
|
4
|
-
latitude: number;
|
|
5
|
-
};
|
|
6
|
-
export type PlaceRef = {
|
|
7
|
-
objectType: 'StopPlaceRef' | 'AddressRef' | 'PointOfInterestRef';
|
|
8
|
-
stopPlaceRef?: string;
|
|
9
|
-
};
|
|
10
|
-
export type Place = {
|
|
11
|
-
objectType: PlaceType;
|
|
12
|
-
id: string;
|
|
13
|
-
name: string;
|
|
14
|
-
geoPosition?: GeoPosition;
|
|
15
|
-
ref?: PlaceRef;
|
|
16
|
-
};
|
|
17
|
-
export type TripStatus = 'PLANNED' | 'CONFIRMED' | 'CHANGED' | 'CANCELLED';
|
|
18
|
-
export type TimedLeg = {
|
|
19
|
-
type: 'timed';
|
|
20
|
-
board: {
|
|
21
|
-
stopPlace: Place;
|
|
22
|
-
departureTime: string;
|
|
23
|
-
platform?: string;
|
|
24
|
-
};
|
|
25
|
-
alight: {
|
|
26
|
-
stopPlace: Place;
|
|
27
|
-
arrivalTime: string;
|
|
28
|
-
platform?: string;
|
|
29
|
-
};
|
|
30
|
-
service: {
|
|
31
|
-
publishedLineName?: string;
|
|
32
|
-
operatorName?: string;
|
|
33
|
-
};
|
|
34
|
-
duration: string;
|
|
35
|
-
intermediateStops?: Array<{
|
|
36
|
-
stopPlace: Place;
|
|
37
|
-
arrivalTime?: string;
|
|
38
|
-
departureTime?: string;
|
|
39
|
-
}>;
|
|
40
|
-
occupancy?: {
|
|
41
|
-
firstClass?: 'LOW' | 'MEDIUM' | 'HIGH' | 'UNKNOWN';
|
|
42
|
-
secondClass?: 'LOW' | 'MEDIUM' | 'HIGH' | 'UNKNOWN';
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
export type TransferLeg = {
|
|
46
|
-
type: 'transfer';
|
|
47
|
-
start: PlaceRef;
|
|
48
|
-
end: PlaceRef;
|
|
49
|
-
duration: string;
|
|
50
|
-
transferMode: string;
|
|
51
|
-
};
|
|
52
|
-
export type ContinuousLeg = {
|
|
53
|
-
type: 'continuous';
|
|
54
|
-
service: {
|
|
55
|
-
providerName?: string;
|
|
56
|
-
};
|
|
57
|
-
duration: string;
|
|
58
|
-
};
|
|
59
|
-
export type TripLeg = TimedLeg | TransferLeg | ContinuousLeg;
|
|
60
|
-
export type Trip = {
|
|
61
|
-
id: string;
|
|
62
|
-
origin: Place;
|
|
63
|
-
destination: Place;
|
|
64
|
-
startTime: string;
|
|
65
|
-
endTime: string;
|
|
66
|
-
duration: string;
|
|
67
|
-
transfers: number;
|
|
68
|
-
legs: TripLeg[];
|
|
69
|
-
tripStatus: TripStatus;
|
|
70
|
-
};
|
|
71
|
-
export type TripsCollection = {
|
|
72
|
-
id: string;
|
|
73
|
-
trips: Trip[];
|
|
74
|
-
tripSummaries: Array<{
|
|
75
|
-
id: string;
|
|
76
|
-
origin: Place;
|
|
77
|
-
destination: Place;
|
|
78
|
-
startTime: string;
|
|
79
|
-
endTime: string;
|
|
80
|
-
duration: string;
|
|
81
|
-
transfers: number;
|
|
82
|
-
}>;
|
|
83
|
-
links?: {
|
|
84
|
-
next?: string;
|
|
85
|
-
previous?: string;
|
|
86
|
-
};
|
|
87
|
-
warnings?: string[];
|
|
88
|
-
};
|
|
89
|
-
export type TransportMode = 'HIGH_SPEED_TRAIN' | 'HISTORIC_TRAIN' | 'INTERCITY' | 'REGIONAL' | 'INTERREGIONAL' | 'URBAN' | 'TRAIN' | 'TRAM' | 'UNDERGROUND' | 'NIGHT_TRAIN' | 'SHARED_TAXI' | 'MOTOR_RAIL' | 'MOUNTAIN_TRAIN' | 'PLANE' | 'COACH_GROUP' | 'SHIP' | 'BUS';
|
|
90
|
-
export type TripSearchParams = {
|
|
91
|
-
origin: string;
|
|
92
|
-
destination: string;
|
|
93
|
-
departureTime?: string;
|
|
94
|
-
arrivalTime?: string;
|
|
95
|
-
transferLimit?: number;
|
|
96
|
-
vias?: Array<{
|
|
97
|
-
stopPlaceRef: string;
|
|
98
|
-
dwellTime?: string;
|
|
99
|
-
}>;
|
|
100
|
-
ptModeFilter?: {
|
|
101
|
-
exclude: boolean;
|
|
102
|
-
transportModes: TransportMode[];
|
|
103
|
-
};
|
|
104
|
-
};
|
|
105
|
-
export type PlaceSearchParams = {
|
|
106
|
-
name: string;
|
|
107
|
-
type?: 'STOP' | 'ADDRESS' | 'POI';
|
|
108
|
-
numberOfResults?: number;
|
|
109
|
-
};
|
|
110
|
-
export type ReductionCard = 'HALF_FARE' | 'GA' | 'NONE';
|
|
111
|
-
export type Traveler = {
|
|
112
|
-
id: string;
|
|
113
|
-
type: 'ADULT' | 'CHILD';
|
|
114
|
-
dateOfBirth?: string;
|
|
115
|
-
reductionCard?: ReductionCard;
|
|
116
|
-
firstName?: string;
|
|
117
|
-
lastName?: string;
|
|
118
|
-
};
|
|
119
|
-
export type Price = {
|
|
120
|
-
amount: number;
|
|
121
|
-
currency: string;
|
|
122
|
-
class: '1' | '2';
|
|
123
|
-
reductionCard?: ReductionCard;
|
|
124
|
-
};
|
|
125
|
-
export type PriceResult = {
|
|
126
|
-
tripId: string;
|
|
127
|
-
prices: Price[];
|
|
128
|
-
};
|
|
129
|
-
export type OfferResult = {
|
|
130
|
-
tripId: string;
|
|
131
|
-
affiliateDeepLink?: string;
|
|
132
|
-
};
|
|
133
|
-
export type SmapiProblem = {
|
|
134
|
-
type: string;
|
|
135
|
-
title?: string;
|
|
136
|
-
status?: number;
|
|
137
|
-
detail?: string;
|
|
138
|
-
displayMessages?: string[];
|
|
139
|
-
};
|
package/dist/types.js
DELETED
package/dist/types.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,yDAAyD"}
|
package/dist/widgets.d.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Registers ChatGPT Apps SDK widget resources on an McpServer.
|
|
3
|
-
*
|
|
4
|
-
* Each tool that returns structured data links to a widget via
|
|
5
|
-
* `_meta["openai/outputTemplate"] = "ui://widget/<name>.html"`.
|
|
6
|
-
*
|
|
7
|
-
* The HTML shell for every widget embeds the same JS bundle (dist/widgets.js)
|
|
8
|
-
* produced by `packages/sbb-mcp/web`. Routing to the right widget component
|
|
9
|
-
* happens in the bundle via `data-widget` on the root element.
|
|
10
|
-
*/
|
|
11
|
-
import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
12
|
-
/** Registered widget IDs (mirrored in web/src/main.tsx). */
|
|
13
|
-
export declare const WIDGETS: {
|
|
14
|
-
readonly STATIONS_LIST: "stations-list";
|
|
15
|
-
readonly CONNECTION_LIST: "connection-list";
|
|
16
|
-
readonly TRIP_DETAILS: "trip-details";
|
|
17
|
-
readonly PRICES_TABLE: "prices-table";
|
|
18
|
-
readonly TICKET_CARD: "ticket-card";
|
|
19
|
-
};
|
|
20
|
-
export type WidgetId = (typeof WIDGETS)[keyof typeof WIDGETS];
|
|
21
|
-
export declare function widgetUri(id: WidgetId): string;
|
|
22
|
-
/**
|
|
23
|
-
* True when the connected MCP client renders our widget iframe (currently
|
|
24
|
-
* ChatGPT via the Apps SDK). Used by tool handlers to decide between a full
|
|
25
|
-
* markdown response (non-widget clients need it to display anything useful)
|
|
26
|
-
* and a terse one-line summary (widget clients already show the rich UI, and
|
|
27
|
-
* the detailed prose just gets paraphrased by the LLM into a duplicate
|
|
28
|
-
* narration next to the iframe — see https://…/issues/connections-shown-twice).
|
|
29
|
-
*
|
|
30
|
-
* Detection is based on `clientInfo.name` from the MCP `initialize` handshake.
|
|
31
|
-
* ChatGPT self-identifies as "ChatGPT" / "ChatGPT-Atlas" / similar — we match
|
|
32
|
-
* case-insensitively on "chatgpt" or "openai" so future naming tweaks from
|
|
33
|
-
* OpenAI don't silently revert us to the noisy path.
|
|
34
|
-
*
|
|
35
|
-
* Falls back to `false` (full markdown) when no clientInfo has been received
|
|
36
|
-
* yet or when the name doesn't match — the safe default for unknown clients
|
|
37
|
-
* that might not render widgets.
|
|
38
|
-
*/
|
|
39
|
-
export declare function isWidgetRenderingClient(server: McpServer): boolean;
|
|
40
|
-
/**
|
|
41
|
-
* Descriptor `_meta` (on the tool and resource registrations).
|
|
42
|
-
* This is what tells ChatGPT to render a UI widget for the tool.
|
|
43
|
-
*/
|
|
44
|
-
export declare function widgetToolMeta(id: WidgetId, invoking: string, invoked: string): Record<string, unknown>;
|
|
45
|
-
/**
|
|
46
|
-
* Invocation `_meta` (on each CallTool response).
|
|
47
|
-
*
|
|
48
|
-
* IMPORTANT: matches OpenAI's Pizzaz reference server exactly — ONLY the
|
|
49
|
-
* invoking/invoked strings. Historically we also set `openai/outputTemplate`
|
|
50
|
-
* and `openai/widgetAccessible` here, but those belong on the tool descriptor
|
|
51
|
-
* + resource registration (see `widgetToolMeta`). Repeating them on the
|
|
52
|
-
* response appears to confuse ChatGPT's widget resolver: the iframe mounts
|
|
53
|
-
* but `window.openai.toolOutput` never populates — leaving every widget
|
|
54
|
-
* stuck on the "Loading…" fallback.
|
|
55
|
-
*
|
|
56
|
-
* Ref: https://github.com/openai/openai-apps-sdk-examples/blob/main/pizzaz_server_node/src/server.ts
|
|
57
|
-
*/
|
|
58
|
-
export declare function widgetResponseMeta(_id: WidgetId, invoking: string, invoked: string): Record<string, unknown>;
|
|
59
|
-
/** Registers all widget resources on the given MCP server. Call once per server instance. */
|
|
60
|
-
export declare function registerWidgets(server: McpServer): void;
|