sbb-mcp 0.4.1 → 0.4.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/LICENSE +57 -57
- package/README.md +258 -314
- package/dist/cache.d.ts +2 -0
- package/dist/cache.js +4 -0
- package/dist/cache.js.map +1 -1
- package/dist/formatters.d.ts +13 -0
- package/dist/formatters.js +94 -19
- package/dist/formatters.js.map +1 -1
- package/dist/http.js +59 -3
- package/dist/http.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/look2book.d.ts +98 -0
- package/dist/look2book.js +212 -0
- package/dist/look2book.js.map +1 -0
- package/dist/profile.js +15 -8
- package/dist/profile.js.map +1 -1
- package/dist/shortlink.d.ts +60 -0
- package/dist/shortlink.js +122 -0
- package/dist/shortlink.js.map +1 -0
- package/dist/structured.d.ts +7 -1
- package/dist/structured.js +2 -1
- package/dist/structured.js.map +1 -1
- package/dist/swisstrip.js +21 -5
- package/dist/swisstrip.js.map +1 -1
- package/dist/tools.d.ts +38 -0
- package/dist/tools.js +122 -77
- package/dist/tools.js.map +1 -1
- package/dist/transport/index.d.ts +1 -0
- package/dist/transport/index.js +4 -0
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/setup.d.ts +1 -0
- package/dist/transport/setup.js +59 -0
- package/dist/transport/setup.js.map +1 -0
- package/dist/transport/smapi-auth.d.ts +14 -2
- package/dist/transport/smapi-auth.js +67 -17
- package/dist/transport/smapi-auth.js.map +1 -1
- package/dist/transport/smapi-client.d.ts +25 -1
- package/dist/transport/smapi-client.js +112 -9
- package/dist/transport/smapi-client.js.map +1 -1
- package/dist/transport/smapi-journey.d.ts +11 -5
- package/dist/transport/smapi-journey.js +16 -7
- package/dist/transport/smapi-journey.js.map +1 -1
- package/dist/transport/smapi-mock.js.map +1 -1
- package/dist/transport/smapi-prices.d.ts +43 -9
- package/dist/transport/smapi-prices.js +112 -41
- package/dist/transport/smapi-prices.js.map +1 -1
- package/dist/transport/smapi-types.d.ts +28 -0
- package/dist/widgets.d.ts +30 -3
- package/dist/widgets.js +78 -14
- package/dist/widgets.js.map +1 -1
- package/package.json +79 -73
- package/web/dist/widgets.css +1 -1
- package/web/dist/widgets.js +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smapi-prices.js","sourceRoot":"","sources":["../../src/transport/smapi-prices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAOrE
|
|
1
|
+
{"version":3,"file":"smapi-prices.js","sourceRoot":"","sources":["../../src/transport/smapi-prices.ts"],"names":[],"mappings":"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"}
|
|
@@ -144,10 +144,38 @@ export type SmapiOfferResult = {
|
|
|
144
144
|
containers: SmapiOfferContainer[];
|
|
145
145
|
affiliateDeepLink?: string;
|
|
146
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
|
+
};
|
|
147
168
|
export type SmapiProblem = {
|
|
169
|
+
/** RFC 9457 short error code; optional in 3.1, mandatory in upcoming. */
|
|
170
|
+
code?: string;
|
|
148
171
|
type: string;
|
|
149
172
|
title?: string;
|
|
150
173
|
status?: number;
|
|
151
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). */
|
|
152
180
|
displayMessages?: string[];
|
|
153
181
|
};
|
package/dist/widgets.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* produced by `packages/sbb-mcp/web`. Routing to the right widget component
|
|
9
9
|
* happens in the bundle via `data-widget` on the root element.
|
|
10
10
|
*/
|
|
11
|
-
import type
|
|
11
|
+
import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
12
12
|
/** Registered widget IDs (mirrored in web/src/main.tsx). */
|
|
13
13
|
export declare const WIDGETS: {
|
|
14
14
|
readonly STATIONS_LIST: "stations-list";
|
|
@@ -19,6 +19,24 @@ export declare const WIDGETS: {
|
|
|
19
19
|
};
|
|
20
20
|
export type WidgetId = (typeof WIDGETS)[keyof typeof WIDGETS];
|
|
21
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;
|
|
22
40
|
/**
|
|
23
41
|
* Descriptor `_meta` (on the tool and resource registrations).
|
|
24
42
|
* This is what tells ChatGPT to render a UI widget for the tool.
|
|
@@ -26,8 +44,17 @@ export declare function widgetUri(id: WidgetId): string;
|
|
|
26
44
|
export declare function widgetToolMeta(id: WidgetId, invoking: string, invoked: string): Record<string, unknown>;
|
|
27
45
|
/**
|
|
28
46
|
* Invocation `_meta` (on each CallTool response).
|
|
29
|
-
*
|
|
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
|
|
30
57
|
*/
|
|
31
|
-
export declare function widgetResponseMeta(
|
|
58
|
+
export declare function widgetResponseMeta(_id: WidgetId, invoking: string, invoked: string): Record<string, unknown>;
|
|
32
59
|
/** Registers all widget resources on the given MCP server. Call once per server instance. */
|
|
33
60
|
export declare function registerWidgets(server: McpServer): void;
|
package/dist/widgets.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { readFileSync, existsSync } from 'node:fs';
|
|
12
12
|
import { dirname, resolve } from 'node:path';
|
|
13
13
|
import { fileURLToPath } from 'node:url';
|
|
14
|
+
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
14
15
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
16
|
/** Widgets ship under packages/sbb-mcp/web/dist, i.e. two levels above dist/*.js at runtime. */
|
|
16
17
|
const WEB_DIST = resolve(__dirname, '..', 'web', 'dist');
|
|
@@ -25,6 +26,28 @@ export const WIDGETS = {
|
|
|
25
26
|
export function widgetUri(id) {
|
|
26
27
|
return `ui://widget/${id}.html`;
|
|
27
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* True when the connected MCP client renders our widget iframe (currently
|
|
31
|
+
* ChatGPT via the Apps SDK). Used by tool handlers to decide between a full
|
|
32
|
+
* markdown response (non-widget clients need it to display anything useful)
|
|
33
|
+
* and a terse one-line summary (widget clients already show the rich UI, and
|
|
34
|
+
* the detailed prose just gets paraphrased by the LLM into a duplicate
|
|
35
|
+
* narration next to the iframe — see https://…/issues/connections-shown-twice).
|
|
36
|
+
*
|
|
37
|
+
* Detection is based on `clientInfo.name` from the MCP `initialize` handshake.
|
|
38
|
+
* ChatGPT self-identifies as "ChatGPT" / "ChatGPT-Atlas" / similar — we match
|
|
39
|
+
* case-insensitively on "chatgpt" or "openai" so future naming tweaks from
|
|
40
|
+
* OpenAI don't silently revert us to the noisy path.
|
|
41
|
+
*
|
|
42
|
+
* Falls back to `false` (full markdown) when no clientInfo has been received
|
|
43
|
+
* yet or when the name doesn't match — the safe default for unknown clients
|
|
44
|
+
* that might not render widgets.
|
|
45
|
+
*/
|
|
46
|
+
export function isWidgetRenderingClient(server) {
|
|
47
|
+
const info = server.server.getClientVersion();
|
|
48
|
+
const name = info?.name ?? '';
|
|
49
|
+
return /chatgpt|openai/i.test(name);
|
|
50
|
+
}
|
|
28
51
|
/**
|
|
29
52
|
* Descriptor `_meta` (on the tool and resource registrations).
|
|
30
53
|
* This is what tells ChatGPT to render a UI widget for the tool.
|
|
@@ -39,12 +62,21 @@ export function widgetToolMeta(id, invoking, invoked) {
|
|
|
39
62
|
}
|
|
40
63
|
/**
|
|
41
64
|
* Invocation `_meta` (on each CallTool response).
|
|
42
|
-
*
|
|
65
|
+
*
|
|
66
|
+
* IMPORTANT: matches OpenAI's Pizzaz reference server exactly — ONLY the
|
|
67
|
+
* invoking/invoked strings. Historically we also set `openai/outputTemplate`
|
|
68
|
+
* and `openai/widgetAccessible` here, but those belong on the tool descriptor
|
|
69
|
+
* + resource registration (see `widgetToolMeta`). Repeating them on the
|
|
70
|
+
* response appears to confuse ChatGPT's widget resolver: the iframe mounts
|
|
71
|
+
* but `window.openai.toolOutput` never populates — leaving every widget
|
|
72
|
+
* stuck on the "Loading…" fallback.
|
|
73
|
+
*
|
|
74
|
+
* Ref: https://github.com/openai/openai-apps-sdk-examples/blob/main/pizzaz_server_node/src/server.ts
|
|
43
75
|
*/
|
|
44
|
-
export function widgetResponseMeta(
|
|
76
|
+
export function widgetResponseMeta(_id, invoking, invoked) {
|
|
45
77
|
return {
|
|
46
|
-
'openai/
|
|
47
|
-
'openai/
|
|
78
|
+
'openai/toolInvocation/invoking': invoking,
|
|
79
|
+
'openai/toolInvocation/invoked': invoked,
|
|
48
80
|
};
|
|
49
81
|
}
|
|
50
82
|
let cachedBundles = null;
|
|
@@ -63,11 +95,26 @@ function loadBundles() {
|
|
|
63
95
|
}
|
|
64
96
|
function renderWidgetHtml(id) {
|
|
65
97
|
const { js, css } = loadBundles();
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
98
|
+
// Full HTML document shape matching OpenAI's Pizzaz reference server.
|
|
99
|
+
//
|
|
100
|
+
// We settled on a full `<!doctype html>` document (rather than a naked
|
|
101
|
+
// fragment) because ChatGPT's widget iframe resolver wraps text/html+
|
|
102
|
+
// skybridge resources as-is — no implicit <html>/<body> — and Preact's
|
|
103
|
+
// hydration was silently failing when the bundle executed before the
|
|
104
|
+
// document's body was parsed.
|
|
105
|
+
//
|
|
106
|
+
// Ref: https://github.com/openai/openai-apps-sdk-examples
|
|
107
|
+
return `<!doctype html>
|
|
108
|
+
<html>
|
|
109
|
+
<head>
|
|
110
|
+
<meta charset="utf-8">
|
|
111
|
+
<style>${css}</style>
|
|
112
|
+
</head>
|
|
113
|
+
<body>
|
|
114
|
+
<div id="sbb-widget-root" data-widget="${id}"></div>
|
|
115
|
+
<script>${js}</script>
|
|
116
|
+
</body>
|
|
117
|
+
</html>`;
|
|
71
118
|
}
|
|
72
119
|
const DEFINITIONS = [
|
|
73
120
|
{
|
|
@@ -100,21 +147,38 @@ const DEFINITIONS = [
|
|
|
100
147
|
export function registerWidgets(server) {
|
|
101
148
|
for (const def of DEFINITIONS) {
|
|
102
149
|
const uri = widgetUri(def.id);
|
|
103
|
-
|
|
150
|
+
const meta = widgetToolMeta(def.id, 'Loading…', 'Done');
|
|
151
|
+
const config = {
|
|
104
152
|
title: def.title,
|
|
105
153
|
description: def.description,
|
|
106
154
|
mimeType: 'text/html+skybridge',
|
|
107
|
-
_meta:
|
|
108
|
-
}
|
|
155
|
+
_meta: meta,
|
|
156
|
+
};
|
|
157
|
+
const read = async () => ({
|
|
109
158
|
contents: [
|
|
110
159
|
{
|
|
111
160
|
uri,
|
|
112
161
|
mimeType: 'text/html+skybridge',
|
|
113
162
|
text: renderWidgetHtml(def.id),
|
|
114
|
-
_meta:
|
|
163
|
+
_meta: meta,
|
|
115
164
|
},
|
|
116
165
|
],
|
|
117
|
-
})
|
|
166
|
+
});
|
|
167
|
+
// Static registration — surfaces in resources/list + enables plain
|
|
168
|
+
// resources/read by URI. Matches Pizzaz's ListResourcesRequest shape.
|
|
169
|
+
server.registerResource(`widget-${def.id}`, uri, config, read);
|
|
170
|
+
// Template registration — surfaces in resources/templates/list, which
|
|
171
|
+
// is what ChatGPT's Apps SDK widget resolver actually queries to
|
|
172
|
+
// discover mountable widgets. Before this dual registration, ChatGPT
|
|
173
|
+
// saw an empty template list, failed with "Error loading app — Failed
|
|
174
|
+
// to fetch template", and never mounted the iframe.
|
|
175
|
+
//
|
|
176
|
+
// `list: undefined` matches the ResourceTemplate signature and tells
|
|
177
|
+
// the SDK there is no dynamic enumeration needed (our template URI
|
|
178
|
+
// has no {variables} — it's a plain URI, like Pizzaz).
|
|
179
|
+
//
|
|
180
|
+
// Ref: https://github.com/openai/openai-apps-sdk-examples/blob/main/pizzaz_server_node/src/server.ts
|
|
181
|
+
server.registerResource(`widget-${def.id}-template`, new ResourceTemplate(uri, { list: undefined }), config, read);
|
|
118
182
|
}
|
|
119
183
|
}
|
|
120
184
|
//# sourceMappingURL=widgets.js.map
|
package/dist/widgets.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widgets.js","sourceRoot":"","sources":["../src/widgets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"widgets.js","sourceRoot":"","sources":["../src/widgets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAkB,MAAM,yCAAyC,CAAA;AAE1F,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAEzD,gGAAgG;AAChG,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;AAExD,4DAA4D;AAC5D,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,aAAa,EAAE,eAAe;IAC9B,eAAe,EAAE,iBAAiB;IAClC,YAAY,EAAE,cAAc;IAC5B,YAAY,EAAE,cAAc;IAC5B,WAAW,EAAE,aAAa;CAClB,CAAA;AAIV,MAAM,UAAU,SAAS,CAAC,EAAY;IACpC,OAAO,eAAe,EAAE,OAAO,CAAA;AACjC,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAiB;IACvD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAA;IAC7C,MAAM,IAAI,GAAG,IAAI,EAAE,IAAI,IAAI,EAAE,CAAA;IAC7B,OAAO,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,EAAY,EAAE,QAAgB,EAAE,OAAe;IAC5E,OAAO;QACL,uBAAuB,EAAE,SAAS,CAAC,EAAE,CAAC;QACtC,gCAAgC,EAAE,QAAQ;QAC1C,+BAA+B,EAAE,OAAO;QACxC,yBAAyB,EAAE,IAAI;KAChC,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAChC,GAAa,EACb,QAAgB,EAChB,OAAe;IAEf,OAAO;QACL,gCAAgC,EAAE,QAAQ;QAC1C,+BAA+B,EAAE,OAAO;KACzC,CAAA;AACH,CAAC;AAED,IAAI,aAAa,GAAuC,IAAI,CAAA;AAE5D,SAAS,WAAW;IAClB,IAAI,aAAa;QAAE,OAAO,aAAa,CAAA;IAEvC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;IAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAA;IAEhD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,8BAA8B,MAAM,6EAA6E,CAClH,CAAA;IACH,CAAC;IAED,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACpE,aAAa,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,CAAA;IAC3B,OAAO,aAAa,CAAA;AACtB,CAAC;AAED,SAAS,gBAAgB,CAAC,EAAY;IACpC,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,WAAW,EAAE,CAAA;IACjC,sEAAsE;IACtE,EAAE;IACF,uEAAuE;IACvE,sEAAsE;IACtE,uEAAuE;IACvE,qEAAqE;IACrE,8BAA8B;IAC9B,EAAE;IACF,0DAA0D;IAC1D,OAAO;;;;SAIA,GAAG;;;yCAG6B,EAAE;UACjC,EAAE;;QAEJ,CAAA;AACR,CAAC;AAQD,MAAM,WAAW,GAAgB;IAC/B;QACE,EAAE,EAAE,OAAO,CAAC,aAAa;QACzB,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,kDAAkD;KAChE;IACD;QACE,EAAE,EAAE,OAAO,CAAC,eAAe;QAC3B,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,2EAA2E;KACzF;IACD;QACE,EAAE,EAAE,OAAO,CAAC,YAAY;QACxB,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,+EAA+E;KAC7F;IACD;QACE,EAAE,EAAE,OAAO,CAAC,YAAY;QACxB,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,oEAAoE;KAClF;IACD;QACE,EAAE,EAAE,OAAO,CAAC,WAAW;QACvB,KAAK,EAAE,YAAY;QACnB,WAAW,EAAE,kFAAkF;KAChG;CACF,CAAA;AAED,6FAA6F;AAC7F,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC7B,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG;YACb,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,QAAQ,EAAE,qBAAqB;YAC/B,KAAK,EAAE,IAAI;SACZ,CAAA;QACD,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC;YACxB,QAAQ,EAAE;gBACR;oBACE,GAAG;oBACH,QAAQ,EAAE,qBAAqB;oBAC/B,IAAI,EAAE,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC9B,KAAK,EAAE,IAAI;iBACZ;aACF;SACF,CAAC,CAAA;QAEF,mEAAmE;QACnE,sEAAsE;QACtE,MAAM,CAAC,gBAAgB,CAAC,UAAU,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,CAAA;QAE9D,sEAAsE;QACtE,iEAAiE;QACjE,qEAAqE;QACrE,sEAAsE;QACtE,oDAAoD;QACpD,EAAE;QACF,qEAAqE;QACrE,mEAAmE;QACnE,uDAAuD;QACvD,EAAE;QACF,qGAAqG;QACrG,MAAM,CAAC,gBAAgB,CACrB,UAAU,GAAG,CAAC,EAAE,WAAW,EAC3B,IAAI,gBAAgB,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAC9C,MAAM,EACN,IAAI,CACL,CAAA;IACH,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,73 +1,79 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "sbb-mcp",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"mcpName": "io.github.Fabsbags/sbb-mcp",
|
|
5
|
-
"description": "MCP server for Swiss Federal Railways (SBB/CFF/FFS) — real-time train schedules, prices, and ticket purchase links for any AI assistant",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"main": "dist/index.js",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": "./dist/index.js",
|
|
10
|
-
"./transport": "./dist/transport/index.js"
|
|
11
|
-
},
|
|
12
|
-
"bin": {
|
|
13
|
-
"sbb-mcp": "dist/index.js"
|
|
14
|
-
},
|
|
15
|
-
"files": [
|
|
16
|
-
"dist",
|
|
17
|
-
"web/dist",
|
|
18
|
-
"README.md",
|
|
19
|
-
"LICENSE"
|
|
20
|
-
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
}
|
|
73
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "sbb-mcp",
|
|
3
|
+
"version": "0.4.3",
|
|
4
|
+
"mcpName": "io.github.Fabsbags/sbb-mcp",
|
|
5
|
+
"description": "MCP server for Swiss Federal Railways (SBB/CFF/FFS) — real-time train schedules, prices, and ticket purchase links for any AI assistant",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js",
|
|
10
|
+
"./transport": "./dist/transport/index.js"
|
|
11
|
+
},
|
|
12
|
+
"bin": {
|
|
13
|
+
"sbb-mcp": "dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"web/dist",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"ensure:i18n": "node scripts/ensure-i18n.cjs",
|
|
23
|
+
"sync:transport": "node scripts/sync-transport.cjs",
|
|
24
|
+
"check:transport": "node scripts/sync-transport.cjs --check",
|
|
25
|
+
"build:widgets": "npm --prefix web install --no-audit --no-fund && npm --prefix web run build",
|
|
26
|
+
"build:server": "tsc -p tsconfig.build.json",
|
|
27
|
+
"build": "npm run ensure:i18n && npm run sync:transport && npm run build:widgets && npm run build:server",
|
|
28
|
+
"dev": "tsc -w -p tsconfig.build.json",
|
|
29
|
+
"start:http": "node dist/http.js",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"smoke:int": "node scripts/smoke-int.mjs",
|
|
32
|
+
"prepack": "npm run sync:transport && npm run build",
|
|
33
|
+
"prepublishOnly": "npm run build"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"mcp",
|
|
37
|
+
"sbb",
|
|
38
|
+
"cff",
|
|
39
|
+
"ffs",
|
|
40
|
+
"swiss-railways",
|
|
41
|
+
"swiss-federal-railways",
|
|
42
|
+
"train",
|
|
43
|
+
"travel",
|
|
44
|
+
"switzerland",
|
|
45
|
+
"timetable",
|
|
46
|
+
"public-transport",
|
|
47
|
+
"ai",
|
|
48
|
+
"claude",
|
|
49
|
+
"cursor",
|
|
50
|
+
"model-context-protocol"
|
|
51
|
+
],
|
|
52
|
+
"author": "SwissTrip <fabsforward2@gmail.com>",
|
|
53
|
+
"license": "FSL-1.1-MIT",
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "https://github.com/Fabsbags/swisstrip-web",
|
|
57
|
+
"directory": "packages/sbb-mcp"
|
|
58
|
+
},
|
|
59
|
+
"homepage": "https://github.com/Fabsbags/swisstrip-web/tree/main/packages/sbb-mcp#readme",
|
|
60
|
+
"bugs": {
|
|
61
|
+
"url": "https://github.com/Fabsbags/swisstrip-web/issues"
|
|
62
|
+
},
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=18"
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
68
|
+
"express": "^5.1.0",
|
|
69
|
+
"sbb-i18n": "^0.1.1",
|
|
70
|
+
"swiss-weather-mcp": "^0.1.1",
|
|
71
|
+
"zod": "^3.24.4"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@types/express": "^5.0.2",
|
|
75
|
+
"@types/node": "^22.15.3",
|
|
76
|
+
"typescript": "^5.8.3",
|
|
77
|
+
"vitest": "^4.1.0"
|
|
78
|
+
}
|
|
79
|
+
}
|
package/web/dist/widgets.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
:host,.sbb-root{--bg: #ffffff;--bg-raised: #f7f7f8;--border: #e5e5e7;--text: #0f172a;--text-muted: #6b7280;--accent: #eb0000;--accent-fg: #ffffff;--accent-muted: #fff0f0;--success: #0a9447;--warn: #b45309;--radius: 12px;--radius-sm: 8px;--gap: 12px;--gap-sm: 8px;color:var(--text);background:var(--bg);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:14px;line-height:1.45;-webkit-font-smoothing:antialiased}.sbb-root[data-theme=dark]{--bg: #0f1115;--bg-raised: #1a1d23;--border: #2a2e37;--text: #e5e7eb;--text-muted: #9ca3af;--accent: #ff4444;--accent-fg: #ffffff;--accent-muted: #2a1515;--success: #10b981;--warn: #f59e0b}.sbb-root{padding:0;margin:0;max-width:560px}.sbb-header{display:flex;align-items:baseline;justify-content:space-between;gap:var(--gap-sm);margin:0 0 var(--gap) 0;padding:0}.sbb-header__title{font-size:15px;font-weight:600;margin:0}.sbb-header__meta{color:var(--text-muted);font-size:12px}.sbb-card{background:var(--bg-raised);border:1px solid var(--border);border-radius:var(--radius);padding:var(--gap);display:flex;flex-direction:column;gap:var(--gap-sm)}.sbb-list{display:flex;flex-direction:column;gap:var(--gap-sm)}.sbb-connection{display:grid;grid-template-columns:1fr auto;gap:var(--gap-sm);align-items:center;padding:var(--gap-sm) var(--gap);border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg)}.sbb-connection__times{display:flex;align-items:baseline;gap:8px;font-variant-numeric:tabular-nums}.sbb-connection__time{font-weight:600;font-size:16px}.sbb-connection__arrow{color:var(--text-muted)}.sbb-connection__meta{color:var(--text-muted);font-size:12px;margin-top:2px;display:flex;flex-wrap:wrap;gap:6px}.sbb-connection__route{font-size:12px;color:var(--text-muted);display:flex;flex-wrap:wrap;gap:4px;align-items:center}.sbb-connection__actions{display:flex;gap:6px;justify-self:end}.sbb-badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:var(--bg-raised);border:1px solid var(--border);font-size:11px;color:var(--text);white-space:nowrap}.sbb-badge--accent{background:var(--accent-muted);border-color:transparent;color:var(--accent);font-weight:600}.sbb-button{appearance:none;border:1px solid var(--border);background:var(--bg);color:var(--text);padding:6px 10px;font-size:12px;font-weight:500;border-radius:var(--radius-sm);cursor:pointer;display:inline-flex;align-items:center;gap:4px;text-decoration:none;font-family:inherit}.sbb-button:hover:not(:disabled){background:var(--bg-raised)}.sbb-button:disabled{opacity:.5;cursor:not-allowed}.sbb-button--primary{background:var(--accent);color:var(--accent-fg);border-color:var(--accent);padding:8px 14px;font-size:13px}.sbb-button--primary:hover:not(:disabled){background:var(--accent);filter:brightness(.95)}.sbb-footer{margin-top:var(--gap);padding:var(--gap-sm) 0;display:flex;gap:var(--gap-sm);flex-wrap:wrap}.sbb-table{width:100%;border-collapse:collapse;font-size:13px}.sbb-table th,.sbb-table td{padding:6px 10px;text-align:left;border-bottom:1px solid var(--border)}.sbb-table th{font-weight:600;color:var(--text-muted);font-size:12px;text-transform:uppercase;letter-spacing:.03em}.sbb-table td{font-variant-numeric:tabular-nums}.sbb-table tr:last-child td{border-bottom:0}.sbb-ticket-card{padding:16px;background:linear-gradient(135deg,var(--accent-muted),var(--bg-raised));border:1px solid var(--border);border-radius:var(--radius);display:flex;flex-direction:column;gap:var(--gap)}.sbb-ticket-card__route{font-size:16px;font-weight:600}.sbb-ticket-card__times{color:var(--text-muted);font-size:13px}.sbb-weather{padding:8px var(--gap);background:var(--bg-raised);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text-muted);font-size:12px;margin-top:var(--gap-sm)}.sbb-timeline{display:flex;flex-direction:column;gap:4px;position:relative;padding-left:16px}.sbb-timeline:before{content:"";position:absolute;left:4px;top:6px;bottom:6px;width:2px;background:var(--border)}.sbb-timeline__stop{position:relative;display:flex;justify-content:space-between;padding:2px 0;font-size:13px}.sbb-timeline__stop:before{content:"";position:absolute;left:-16px;top:8px;width:10px;height:10px;border-radius:50%;background:var(--bg);border:2px solid var(--accent)}.sbb-timeline__stop--intermediate:before{background:var(--border);border-color:var(--border);width:6px;height:6px;left:-14px;top:10px}.sbb-timeline__stop--intermediate{color:var(--text-muted);font-size:12px}.sbb-timeline__time{font-variant-numeric:tabular-nums;color:var(--text-muted);margin-right:8px}.sbb-empty{color:var(--text-muted);padding:var(--gap);text-align:center;font-size:13px}
|
|
1
|
+
:host,.sbb-root{--bg: #ffffff;--bg-raised: #f7f7f8;--border: #e5e5e7;--text: #0f172a;--text-muted: #6b7280;--accent: #eb0000;--accent-fg: #ffffff;--accent-muted: #fff0f0;--success: #0a9447;--warn: #b45309;--radius: 12px;--radius-sm: 8px;--gap: 12px;--gap-sm: 8px;color:var(--text);background:var(--bg);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:14px;line-height:1.45;-webkit-font-smoothing:antialiased}.sbb-root[data-theme=dark]{--bg: #0f1115;--bg-raised: #1a1d23;--border: #2a2e37;--text: #e5e7eb;--text-muted: #9ca3af;--accent: #ff4444;--accent-fg: #ffffff;--accent-muted: #2a1515;--success: #10b981;--warn: #f59e0b}.sbb-root{padding:0;margin:0;max-width:560px}.sbb-header{display:flex;align-items:baseline;justify-content:space-between;gap:var(--gap-sm);margin:0 0 var(--gap) 0;padding:0}.sbb-header__title{font-size:15px;font-weight:600;margin:0}.sbb-header__meta{color:var(--text-muted);font-size:12px}.sbb-card{background:var(--bg-raised);border:1px solid var(--border);border-radius:var(--radius);padding:var(--gap);display:flex;flex-direction:column;gap:var(--gap-sm)}.sbb-list{display:flex;flex-direction:column;gap:var(--gap-sm)}.sbb-connection{display:grid;grid-template-columns:1fr auto;gap:var(--gap-sm);align-items:center;padding:var(--gap-sm) var(--gap);border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg)}.sbb-connection__times{display:flex;align-items:baseline;gap:8px;font-variant-numeric:tabular-nums}.sbb-connection__time{font-weight:600;font-size:16px}.sbb-connection__time--link{color:var(--accent);text-decoration:none}.sbb-connection__time--link:hover{text-decoration:underline}.sbb-connection__arrow{color:var(--text-muted)}.sbb-connection__meta{color:var(--text-muted);font-size:12px;margin-top:2px;display:flex;flex-wrap:wrap;gap:6px}.sbb-connection__route{font-size:12px;color:var(--text-muted);display:flex;flex-wrap:wrap;gap:4px;align-items:center}.sbb-connection__actions{display:flex;gap:6px;justify-self:end}.sbb-badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:var(--bg-raised);border:1px solid var(--border);font-size:11px;color:var(--text);white-space:nowrap}.sbb-badge--accent{background:var(--accent-muted);border-color:transparent;color:var(--accent);font-weight:600}.sbb-button{appearance:none;border:1px solid var(--border);background:var(--bg);color:var(--text);padding:6px 10px;font-size:12px;font-weight:500;border-radius:var(--radius-sm);cursor:pointer;display:inline-flex;align-items:center;gap:4px;text-decoration:none;font-family:inherit}.sbb-button:hover:not(:disabled){background:var(--bg-raised)}.sbb-button:disabled{opacity:.5;cursor:not-allowed}.sbb-button--primary{background:var(--accent);color:var(--accent-fg);border-color:var(--accent);padding:8px 14px;font-size:13px}.sbb-button--primary:hover:not(:disabled){background:var(--accent);filter:brightness(.95)}.sbb-footer{margin-top:var(--gap);padding:var(--gap-sm) 0;display:flex;gap:var(--gap-sm);flex-wrap:wrap}.sbb-table{width:100%;border-collapse:collapse;font-size:13px}.sbb-table th,.sbb-table td{padding:6px 10px;text-align:left;border-bottom:1px solid var(--border)}.sbb-table th{font-weight:600;color:var(--text-muted);font-size:12px;text-transform:uppercase;letter-spacing:.03em}.sbb-table td{font-variant-numeric:tabular-nums}.sbb-table tr:last-child td{border-bottom:0}.sbb-ticket-card{padding:16px;background:linear-gradient(135deg,var(--accent-muted),var(--bg-raised));border:1px solid var(--border);border-radius:var(--radius);display:flex;flex-direction:column;gap:var(--gap)}.sbb-ticket-card__route{font-size:16px;font-weight:600}.sbb-ticket-card__times{color:var(--text-muted);font-size:13px}.sbb-weather{padding:8px var(--gap);background:var(--bg-raised);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text-muted);font-size:12px;margin-top:var(--gap-sm)}.sbb-timeline{display:flex;flex-direction:column;gap:4px;position:relative;padding-left:16px}.sbb-timeline:before{content:"";position:absolute;left:4px;top:6px;bottom:6px;width:2px;background:var(--border)}.sbb-timeline__stop{position:relative;display:flex;justify-content:space-between;padding:2px 0;font-size:13px}.sbb-timeline__stop:before{content:"";position:absolute;left:-16px;top:8px;width:10px;height:10px;border-radius:50%;background:var(--bg);border:2px solid var(--accent)}.sbb-timeline__stop--intermediate:before{background:var(--border);border-color:var(--border);width:6px;height:6px;left:-14px;top:10px}.sbb-timeline__stop--intermediate{color:var(--text-muted);font-size:12px}.sbb-timeline__time{font-variant-numeric:tabular-nums;color:var(--text-muted);margin-right:8px}.sbb-empty{color:var(--text-muted);padding:var(--gap);text-align:center;font-size:13px}.sbb-debug{margin-top:var(--gap);padding:8px;border:1px dashed var(--border);border-radius:var(--radius-sm);font-size:11px;color:var(--text-muted);text-align:left}.sbb-debug summary{cursor:pointer;font-weight:600}.sbb-debug code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;word-break:break-all}.sbb-traveler-bar{margin:0 0 var(--gap-sm) 0;padding:8px var(--gap);background:var(--bg-raised);border:1px solid var(--border);border-radius:var(--radius-sm);font-size:12px}.sbb-traveler-bar__summary{display:flex;align-items:center;justify-content:space-between;gap:var(--gap-sm)}.sbb-traveler-bar__text{color:var(--text-muted)}.sbb-traveler-bar__text strong{color:var(--text);font-weight:600}.sbb-traveler-bar__form{margin-top:var(--gap-sm);padding-top:var(--gap-sm);border-top:1px solid var(--border);display:flex;flex-direction:column;gap:var(--gap-sm)}.sbb-traveler-bar__group{display:flex;align-items:center;gap:var(--gap-sm);flex-wrap:wrap}.sbb-traveler-bar__label{color:var(--text-muted);font-size:11px;text-transform:uppercase;letter-spacing:.04em;min-width:110px}.sbb-traveler-bar__options{display:flex;gap:4px;flex-wrap:wrap}.sbb-traveler-bar__hint{margin:4px 0 0;color:var(--text-muted);font-size:11px;font-style:italic}.sbb-chip{appearance:none;border:1px solid var(--border);background:var(--bg);color:var(--text);padding:4px 10px;font-size:12px;border-radius:999px;cursor:pointer;font-family:inherit}.sbb-chip:hover{background:var(--bg-raised)}.sbb-chip--active{background:var(--accent-muted);border-color:var(--accent);color:var(--accent);font-weight:600}.sbb-button--ghost{background:transparent;border-color:transparent;color:var(--accent);padding:4px 8px}.sbb-button--ghost:hover:not(:disabled){background:var(--accent-muted)}
|
package/web/dist/widgets.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(){"use strict";var I,u,ee,T,ne,te,re,z,N,B,ie,Z,q,G,$={},E=[],ve=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,A=Array.isArray;function w(e,n){for(var t in n)e[t]=n[t];return e}function V(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function ye(e,n,t){var l,o,i,c={};for(i in n)i=="key"?l=n[i]:i=="ref"?o=n[i]:c[i]=n[i];if(arguments.length>2&&(c.children=arguments.length>3?I.call(arguments,2):t),typeof e=="function"&&e.defaultProps!=null)for(i in e.defaultProps)c[i]===void 0&&(c[i]=e.defaultProps[i]);return F(e,c,l,o,null)}function F(e,n,t,l,o){var i={type:e,props:n,key:t,ref:l,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:o??++ee,__i:-1,__u:0};return o==null&&u.vnode!=null&&u.vnode(i),i}function U(e){return e.children}function W(e,n){this.props=e,this.context=n}function P(e,n){if(n==null)return e.__?P(e.__,e.__i+1):null;for(var t;n<e.__k.length;n++)if((t=e.__k[n])!=null&&t.__e!=null)return t.__e;return typeof e.type=="function"?P(e):null}function ge(e){if(e.__P&&e.__d){var n=e.__v,t=n.__e,l=[],o=[],i=w({},n);i.__v=n.__v+1,u.vnode&&u.vnode(i),J(e.__P,i,n,e.__n,e.__P.namespaceURI,32&n.__u?[t]:null,l,t??P(n),!!(32&n.__u),o),i.__v=n.__v,i.__.__k[i.__i]=i,de(l,i,o),n.__e=n.__=null,i.__e!=t&&se(i)}}function se(e){if((e=e.__)!=null&&e.__c!=null)return e.__e=e.__c.base=null,e.__k.some(function(n){if(n!=null&&n.__e!=null)return e.__e=e.__c.base=n.__e}),se(e)}function le(e){(!e.__d&&(e.__d=!0)&&T.push(e)&&!H.__r++||ne!=u.debounceRendering)&&((ne=u.debounceRendering)||te)(H)}function H(){try{for(var e,n=1;T.length;)T.length>n&&T.sort(re),e=T.shift(),n=T.length,ge(e)}finally{T.length=H.__r=0}}function oe(e,n,t,l,o,i,c,a,h,_,p){var s,m,d,v,g,y,b,f=l&&l.__k||E,S=n.length;for(h=ke(t,n,f,h,S),s=0;s<S;s++)(d=t.__k[s])!=null&&(m=d.__i!=-1&&f[d.__i]||$,d.__i=s,y=J(e,d,m,o,i,c,a,h,_,p),v=d.__e,d.ref&&m.ref!=d.ref&&(m.ref&&Q(m.ref,null,d),p.push(d.ref,d.__c||v,d)),g==null&&v!=null&&(g=v),(b=!!(4&d.__u))||m.__k===d.__k?(h=ce(d,h,e,b),b&&m.__e&&(m.__e=null)):typeof d.type=="function"&&y!==void 0?h=y:v&&(h=v.nextSibling),d.__u&=-7);return t.__e=g,h}function ke(e,n,t,l,o){var i,c,a,h,_,p=t.length,s=p,m=0;for(e.__k=new Array(o),i=0;i<o;i++)(c=n[i])!=null&&typeof c!="boolean"&&typeof c!="function"?(typeof c=="string"||typeof c=="number"||typeof c=="bigint"||c.constructor==String?c=e.__k[i]=F(null,c,null,null,null):A(c)?c=e.__k[i]=F(U,{children:c},null,null,null):c.constructor===void 0&&c.__b>0?c=e.__k[i]=F(c.type,c.props,c.key,c.ref?c.ref:null,c.__v):e.__k[i]=c,h=i+m,c.__=e,c.__b=e.__b+1,a=null,(_=c.__i=we(c,t,h,s))!=-1&&(s--,(a=t[_])&&(a.__u|=2)),a==null||a.__v==null?(_==-1&&(o>p?m--:o<p&&m++),typeof c.type!="function"&&(c.__u|=4)):_!=h&&(_==h-1?m--:_==h+1?m++:(_>h?m--:m++,c.__u|=4))):e.__k[i]=null;if(s)for(i=0;i<p;i++)(a=t[i])!=null&&!(2&a.__u)&&(a.__e==l&&(l=P(a)),pe(a,a));return l}function ce(e,n,t,l){var o,i;if(typeof e.type=="function"){for(o=e.__k,i=0;o&&i<o.length;i++)o[i]&&(o[i].__=e,n=ce(o[i],n,t,l));return n}e.__e!=n&&(l&&(n&&e.type&&!n.parentNode&&(n=P(e)),t.insertBefore(e.__e,n||null)),n=e.__e);do n=n&&n.nextSibling;while(n!=null&&n.nodeType==8);return n}function we(e,n,t,l){var o,i,c,a=e.key,h=e.type,_=n[t],p=_!=null&&(2&_.__u)==0;if(_===null&&a==null||p&&a==_.key&&h==_.type)return t;if(l>(p?1:0)){for(o=t-1,i=t+1;o>=0||i<n.length;)if((_=n[c=o>=0?o--:i++])!=null&&!(2&_.__u)&&a==_.key&&h==_.type)return c}return-1}function _e(e,n,t){n[0]=="-"?e.setProperty(n,t??""):e[n]=t==null?"":typeof t!="number"||ve.test(n)?t:t+"px"}function R(e,n,t,l,o){var i,c;e:if(n=="style")if(typeof t=="string")e.style.cssText=t;else{if(typeof l=="string"&&(e.style.cssText=l=""),l)for(n in l)t&&n in t||_e(e.style,n,"");if(t)for(n in t)l&&t[n]==l[n]||_e(e.style,n,t[n])}else if(n[0]=="o"&&n[1]=="n")i=n!=(n=n.replace(ie,"$1")),c=n.toLowerCase(),n=c in e||n=="onFocusOut"||n=="onFocusIn"?c.slice(2):n.slice(2),e.l||(e.l={}),e.l[n+i]=t,t?l?t[B]=l[B]:(t[B]=Z,e.addEventListener(n,i?G:q,i)):e.removeEventListener(n,i?G:q,i);else{if(o=="http://www.w3.org/2000/svg")n=n.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(n!="width"&&n!="height"&&n!="href"&&n!="list"&&n!="form"&&n!="tabIndex"&&n!="download"&&n!="rowSpan"&&n!="colSpan"&&n!="role"&&n!="popover"&&n in e)try{e[n]=t??"";break e}catch{}typeof t=="function"||(t==null||t===!1&&n[4]!="-"?e.removeAttribute(n):e.setAttribute(n,n=="popover"&&t==1?"":t))}}function ae(e){return function(n){if(this.l){var t=this.l[n.type+e];if(n[N]==null)n[N]=Z++;else if(n[N]<t[B])return;return t(u.event?u.event(n):n)}}}function J(e,n,t,l,o,i,c,a,h,_){var p,s,m,d,v,g,y,b,f,S,x,M,me,j,Y,k=n.type;if(n.constructor!==void 0)return null;128&t.__u&&(h=!!(32&t.__u),i=[a=n.__e=t.__e]),(p=u.__b)&&p(n);e:if(typeof k=="function")try{if(b=n.props,f=k.prototype&&k.prototype.render,S=(p=k.contextType)&&l[p.__c],x=p?S?S.props.value:p.__:l,t.__c?y=(s=n.__c=t.__c).__=s.__E:(f?n.__c=s=new k(b,x):(n.__c=s=new W(b,x),s.constructor=k,s.render=Te),S&&S.sub(s),s.state||(s.state={}),s.__n=l,m=s.__d=!0,s.__h=[],s._sb=[]),f&&s.__s==null&&(s.__s=s.state),f&&k.getDerivedStateFromProps!=null&&(s.__s==s.state&&(s.__s=w({},s.__s)),w(s.__s,k.getDerivedStateFromProps(b,s.__s))),d=s.props,v=s.state,s.__v=n,m)f&&k.getDerivedStateFromProps==null&&s.componentWillMount!=null&&s.componentWillMount(),f&&s.componentDidMount!=null&&s.__h.push(s.componentDidMount);else{if(f&&k.getDerivedStateFromProps==null&&b!==d&&s.componentWillReceiveProps!=null&&s.componentWillReceiveProps(b,x),n.__v==t.__v||!s.__e&&s.shouldComponentUpdate!=null&&s.shouldComponentUpdate(b,s.__s,x)===!1){n.__v!=t.__v&&(s.props=b,s.state=s.__s,s.__d=!1),n.__e=t.__e,n.__k=t.__k,n.__k.some(function(L){L&&(L.__=n)}),E.push.apply(s.__h,s._sb),s._sb=[],s.__h.length&&c.push(s);break e}s.componentWillUpdate!=null&&s.componentWillUpdate(b,s.__s,x),f&&s.componentDidUpdate!=null&&s.__h.push(function(){s.componentDidUpdate(d,v,g)})}if(s.context=x,s.props=b,s.__P=e,s.__e=!1,M=u.__r,me=0,f)s.state=s.__s,s.__d=!1,M&&M(n),p=s.render(s.props,s.state,s.context),E.push.apply(s.__h,s._sb),s._sb=[];else do s.__d=!1,M&&M(n),p=s.render(s.props,s.state,s.context),s.state=s.__s;while(s.__d&&++me<25);s.state=s.__s,s.getChildContext!=null&&(l=w(w({},l),s.getChildContext())),f&&!m&&s.getSnapshotBeforeUpdate!=null&&(g=s.getSnapshotBeforeUpdate(d,v)),j=p!=null&&p.type===U&&p.key==null?he(p.props.children):p,a=oe(e,A(j)?j:[j],n,t,l,o,i,c,a,h,_),s.base=n.__e,n.__u&=-161,s.__h.length&&c.push(s),y&&(s.__E=s.__=null)}catch(L){if(n.__v=null,h||i!=null)if(L.then){for(n.__u|=h?160:128;a&&a.nodeType==8&&a.nextSibling;)a=a.nextSibling;i[i.indexOf(a)]=null,n.__e=a}else{for(Y=i.length;Y--;)V(i[Y]);K(n)}else n.__e=t.__e,n.__k=t.__k,L.then||K(n);u.__e(L,n,t)}else i==null&&n.__v==t.__v?(n.__k=t.__k,n.__e=t.__e):a=n.__e=Ce(t.__e,n,t,l,o,i,c,h,_);return(p=u.diffed)&&p(n),128&n.__u?void 0:a}function K(e){e&&(e.__c&&(e.__c.__e=!0),e.__k&&e.__k.some(K))}function de(e,n,t){for(var l=0;l<t.length;l++)Q(t[l],t[++l],t[++l]);u.__c&&u.__c(n,e),e.some(function(o){try{e=o.__h,o.__h=[],e.some(function(i){i.call(o)})}catch(i){u.__e(i,o.__v)}})}function he(e){return typeof e!="object"||e==null||e.__b>0?e:A(e)?e.map(he):w({},e)}function Ce(e,n,t,l,o,i,c,a,h){var _,p,s,m,d,v,g,y=t.props||$,b=n.props,f=n.type;if(f=="svg"?o="http://www.w3.org/2000/svg":f=="math"?o="http://www.w3.org/1998/Math/MathML":o||(o="http://www.w3.org/1999/xhtml"),i!=null){for(_=0;_<i.length;_++)if((d=i[_])&&"setAttribute"in d==!!f&&(f?d.localName==f:d.nodeType==3)){e=d,i[_]=null;break}}if(e==null){if(f==null)return document.createTextNode(b);e=document.createElementNS(o,f,b.is&&b),a&&(u.__m&&u.__m(n,i),a=!1),i=null}if(f==null)y===b||a&&e.data==b||(e.data=b);else{if(i=i&&I.call(e.childNodes),!a&&i!=null)for(y={},_=0;_<e.attributes.length;_++)y[(d=e.attributes[_]).name]=d.value;for(_ in y)d=y[_],_=="dangerouslySetInnerHTML"?s=d:_=="children"||_ in b||_=="value"&&"defaultValue"in b||_=="checked"&&"defaultChecked"in b||R(e,_,null,d,o);for(_ in b)d=b[_],_=="children"?m=d:_=="dangerouslySetInnerHTML"?p=d:_=="value"?v=d:_=="checked"?g=d:a&&typeof d!="function"||y[_]===d||R(e,_,d,y[_],o);if(p)a||s&&(p.__html==s.__html||p.__html==e.innerHTML)||(e.innerHTML=p.__html),n.__k=[];else if(s&&(e.innerHTML=""),oe(n.type=="template"?e.content:e,A(m)?m:[m],n,t,l,f=="foreignObject"?"http://www.w3.org/1999/xhtml":o,i,c,i?i[0]:t.__k&&P(t,0),a,h),i!=null)for(_=i.length;_--;)V(i[_]);a||(_="value",f=="progress"&&v==null?e.removeAttribute("value"):v!=null&&(v!==e[_]||f=="progress"&&!v||f=="option"&&v!=y[_])&&R(e,_,v,y[_],o),_="checked",g!=null&&g!=e[_]&&R(e,_,g,y[_],o))}return e}function Q(e,n,t){try{if(typeof e=="function"){var l=typeof e.__u=="function";l&&e.__u(),l&&n==null||(e.__u=e(n))}else e.current=n}catch(o){u.__e(o,t)}}function pe(e,n,t){var l,o;if(u.unmount&&u.unmount(e),(l=e.ref)&&(l.current&&l.current!=e.__e||Q(l,null,n)),(l=e.__c)!=null){if(l.componentWillUnmount)try{l.componentWillUnmount()}catch(i){u.__e(i,n)}l.base=l.__P=null}if(l=e.__k)for(o=0;o<l.length;o++)l[o]&&pe(l[o],n,t||typeof e.type!="function");t||V(e.__e),e.__c=e.__=e.__e=void 0}function Te(e,n,t){return this.constructor(e,t)}function Se(e,n,t){var l,o,i,c;n==document&&(n=document.documentElement),u.__&&u.__(e,n),o=(l=!1)?null:n.__k,i=[],c=[],J(n,e=n.__k=ye(U,null,[e]),o||$,$,n.namespaceURI,o?null:n.firstChild?I.call(n.childNodes):null,i,o?o.__e:n.firstChild,l,c),de(i,e,c)}I=E.slice,u={__e:function(e,n,t,l){for(var o,i,c;n=n.__;)if((o=n.__c)&&!o.__)try{if((i=o.constructor)&&i.getDerivedStateFromError!=null&&(o.setState(i.getDerivedStateFromError(e)),c=o.__d),o.componentDidCatch!=null&&(o.componentDidCatch(e,l||{}),c=o.__d),c)return o.__E=o}catch(a){e=a}throw e}},ee=0,W.prototype.setState=function(e,n){var t;t=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=w({},this.state),typeof e=="function"&&(e=e(w({},t),this.props)),e&&w(t,e),e!=null&&this.__v&&(n&&this._sb.push(n),le(this))},W.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),le(this))},W.prototype.render=U,T=[],te=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,re=function(e,n){return e.__v.__b-n.__v.__b},H.__r=0,z=Math.random().toString(8),N="__d"+z,B="__a"+z,ie=/(PointerCapture)$|Capture$/i,Z=0,q=ae(!1),G=ae(!0);var xe=0;function r(e,n,t,l,o,i){n||(n={});var c,a,h=n;if("ref"in h)for(a in h={},n)a=="ref"?c=n[a]:h[a]=n[a];var _={type:e,props:h,key:t,ref:c,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--xe,__i:-1,__u:0,__source:o,__self:i};if(typeof e=="function"&&(c=e.defaultProps))for(a in c)h[a]===void 0&&(h[a]=c[a]);return u.vnode&&u.vnode(_),_}function D(){return window.openai??{}}function Pe({data:e}){return e.stations.length?r("div",{children:[r("header",{class:"sbb-header",children:[r("h2",{class:"sbb-header__title",children:['Stations matching "',e.query,'"']}),r("span",{class:"sbb-header__meta",children:[e.stations.length," result",e.stations.length===1?"":"s"]})]}),r("div",{class:"sbb-list",children:e.stations.map(n=>r("div",{class:"sbb-connection",children:r("div",{children:[r("div",{style:{fontWeight:600},children:n.name}),r("div",{class:"sbb-connection__meta",children:[r("span",{class:"sbb-badge",children:["ID ",n.id]}),typeof n.lat=="number"&&typeof n.lon=="number"&&r("span",{children:[n.lat.toFixed(3),", ",n.lon.toFixed(3)]})]})]})},n.id))})]}):r("div",{class:"sbb-empty",children:['No stations matched "',e.query,'".']})}function C(e){try{return new Date(e).toLocaleTimeString("de-CH",{hour:"2-digit",minute:"2-digit",timeZone:"Europe/Zurich"})}catch{return e}}function X(e){try{return new Date(e).toLocaleDateString("en-CH",{weekday:"short",day:"2-digit",month:"short",timeZone:"Europe/Zurich"})}catch{return e}}function O(e){if(!Number.isFinite(e)||e<0)return"—";const n=Math.floor(e/60),t=e%60;return n===0?`${t}m`:t===0?`${n}h`:`${n}h ${t}m`}function ue(e,n="CHF"){return`${n} ${e.toFixed(2)}`}function Le({legs:e}){const n=e.filter(t=>t.type==="train");return n.length===0?null:r("span",{class:"sbb-connection__route",children:n.map((t,l)=>r("span",{children:[l>0&&r("span",{style:{color:"var(--text-muted)",margin:"0 2px"},children:"›"}),r("span",{class:"sbb-badge",children:[t.line??"Train",t.platform?` · Pl. ${t.platform}`:""]})]},l))})}function Be({c:e,onPrice:n}){return r("div",{class:"sbb-connection",children:[r("div",{children:[r("div",{class:"sbb-connection__times",children:[r("span",{class:"sbb-connection__time",children:C(e.departureTime)}),r("span",{class:"sbb-connection__arrow",children:"→"}),r("span",{class:"sbb-connection__time",children:C(e.arrivalTime)})]}),r("div",{class:"sbb-connection__meta",children:[r("span",{class:"sbb-badge",children:O(e.durationMinutes)}),r("span",{class:"sbb-badge",children:[e.transfers," transfer",e.transfers===1?"":"s"]}),r(Le,{legs:e.legs})]})]}),r("div",{class:"sbb-connection__actions",children:r("button",{type:"button",class:"sbb-button",onClick:n,children:"Price"})})]})}function De({data:e,theme:n}){const t=D(),l=c=>{t.callTool?.("get_prices",{trip_ids:[c]})},o=c=>{t.callTool?.("get_more_connections",{collection_id:e.collectionId,direction:c})},i=()=>{const c=e.connections.slice(0,5).map(a=>a.tripId);c.length&&t.callTool?.("get_prices",{trip_ids:c})};return e.connections.length?r("div",{children:[r("header",{class:"sbb-header",children:[r("h2",{class:"sbb-header__title",children:[e.origin.name," → ",e.destination.name]}),r("span",{class:"sbb-header__meta",children:X(e.date)})]}),r("div",{class:"sbb-list",children:e.connections.map(c=>r(Be,{c,onPrice:()=>l(c.tripId)},c.tripId))}),e.weather?.summary&&r("div",{class:"sbb-weather",children:["☁ ",e.destination.name,": ",e.weather.summary]}),r("div",{class:"sbb-footer",children:[r("button",{type:"button",class:"sbb-button",onClick:()=>o("previous"),children:"← Earlier"}),r("button",{type:"button",class:"sbb-button",onClick:()=>o("next"),children:"Later →"}),r("button",{type:"button",class:"sbb-button sbb-button--primary",onClick:i,children:"See all prices"})]})]}):r("div",{class:"sbb-empty",children:"No connections found."})}function Me({leg:e,index:n}){return e.type==="walk"?r("div",{class:"sbb-card",style:{background:"var(--bg)"},children:r("div",{style:{fontWeight:600},children:["Transfer · walk ",O(e.durationMinutes)]})}):r("div",{class:"sbb-card",children:[r("div",{style:{display:"flex",alignItems:"baseline",justifyContent:"space-between",gap:8},children:[r("div",{children:[r("span",{class:"sbb-badge sbb-badge--accent",children:["Leg ",n+1]}),r("span",{style:{marginLeft:8,fontWeight:600},children:[e.line??"Train",e.operator?r("span",{class:"sbb-header__meta",children:[" · ",e.operator]}):null]})]}),r("span",{class:"sbb-header__meta",children:O(e.durationMinutes)})]}),r("div",{class:"sbb-timeline",children:[e.from&&r("div",{class:"sbb-timeline__stop",children:[r("span",{children:[r("strong",{children:e.from.name}),e.from.platform?r("span",{class:"sbb-header__meta",children:[" · Pl. ",e.from.platform]}):null]}),r("span",{class:"sbb-timeline__time",children:C(e.from.time)})]}),e.intermediateStops?.map((t,l)=>r("div",{class:"sbb-timeline__stop sbb-timeline__stop--intermediate",children:[r("span",{children:t.name}),r("span",{class:"sbb-timeline__time",children:t.arrivalTime?C(t.arrivalTime):""})]},l)),e.to&&r("div",{class:"sbb-timeline__stop",children:[r("span",{children:[r("strong",{children:e.to.name}),e.to.platform?r("span",{class:"sbb-header__meta",children:[" · Pl. ",e.to.platform]}):null]}),r("span",{class:"sbb-timeline__time",children:C(e.to.time)})]})]}),e.occupancy&&r("div",{class:"sbb-connection__meta",children:[e.occupancy.firstClass&&r("span",{class:"sbb-badge",children:["1st: ",e.occupancy.firstClass]}),e.occupancy.secondClass&&r("span",{class:"sbb-badge",children:["2nd: ",e.occupancy.secondClass]})]})]})}function Ie({data:e}){const n=D();return r("div",{children:[r("header",{class:"sbb-header",children:[r("h2",{class:"sbb-header__title",children:[e.origin.name," → ",e.destination.name]}),r("span",{class:"sbb-header__meta",children:X(e.departureTime)})]}),r("div",{class:"sbb-card",style:{marginBottom:"var(--gap)"},children:r("div",{style:{display:"flex",justifyContent:"space-between"},children:[r("div",{class:"sbb-connection__times",children:[r("span",{class:"sbb-connection__time",children:C(e.departureTime)}),r("span",{class:"sbb-connection__arrow",children:"→"}),r("span",{class:"sbb-connection__time",children:C(e.arrivalTime)})]}),r("div",{class:"sbb-connection__meta",children:[r("span",{class:"sbb-badge",children:O(e.durationMinutes)}),r("span",{class:"sbb-badge",children:[e.transfers," transfer",e.transfers===1?"":"s"]}),r("span",{class:"sbb-badge",children:e.status})]})]})}),r("div",{class:"sbb-list",children:e.legs.map((t,l)=>r(Me,{leg:t,index:l},l))}),r("div",{class:"sbb-footer",children:r("button",{type:"button",class:"sbb-button sbb-button--primary",onClick:()=>n.callTool?.("get_prices",{trip_ids:[e.tripId]}),children:"See price"})})]})}function Ne({data:e}){return e.prices.length?r("div",{children:[r("header",{class:"sbb-header",children:[r("h2",{class:"sbb-header__title",children:"Ticket prices"}),r("span",{class:"sbb-header__meta",children:[e.prices.length," trip",e.prices.length===1?"":"s"]})]}),r("div",{class:"sbb-card",children:r("table",{class:"sbb-table",children:[r("thead",{children:r("tr",{children:[r("th",{children:"Trip"}),r("th",{children:"2nd class"}),r("th",{children:"1st class"})]})}),r("tbody",{children:e.prices.map(n=>r("tr",{children:[r("td",{style:{fontFamily:"ui-monospace, monospace",fontSize:11},children:[n.tripId.slice(0,12),"…"]}),r("td",{children:n.secondClass?ue(n.secondClass.amount,n.secondClass.currency):"—"}),r("td",{children:n.firstClass?ue(n.firstClass.amount,n.firstClass.currency):"—"})]},n.tripId))})]})}),r("div",{class:"sbb-header__meta",style:{marginTop:8},children:"Prices are estimates. Ask for the ticket link to see the final price on SBB.ch."})]}):r("div",{class:"sbb-empty",children:"No price information available."})}function be(e){return`https://swisstrip.app/go?url=${encodeURIComponent(e)}`}function $e({data:e}){const n=e.affiliateLink??e.primaryLink;return r("div",{class:"sbb-ticket-card",children:[r("header",{class:"sbb-header",children:[r("h2",{class:"sbb-header__title",children:"Buy ticket on SBB"}),r("span",{class:"sbb-header__meta",children:X(e.departureTime)})]}),r("div",{children:[r("div",{class:"sbb-ticket-card__route",children:[e.origin.name," → ",e.destination.name]}),r("div",{class:"sbb-ticket-card__times",children:[C(e.departureTime)," – ",C(e.arrivalTime)]})]}),r("div",{style:{display:"flex",gap:8,flexWrap:"wrap"},children:[r("a",{class:"sbb-button sbb-button--primary",href:be(n),target:"_blank",rel:"noopener noreferrer",children:"Buy on SBB.ch →"}),e.affiliateLink&&e.affiliateLink!==e.primaryLink&&r("a",{class:"sbb-button",href:be(e.primaryLink),target:"_blank",rel:"noopener noreferrer",children:"Direct SBB link"})]}),r("div",{class:"sbb-header__meta",style:{fontSize:11},children:"Opens SBB.ch with this connection pre-filled. On mobile, the SBB app opens directly with your Halbtax/GA applied."})]})}function Ee(){const n=document.getElementById("sbb-widget-root")?.getAttribute("data-widget");if(n)return n;const l=D().toolName;return l?{search_stations:"stations-list",search_connections:"connection-list",get_more_connections:"connection-list",get_trip_details:"trip-details",get_prices:"prices-table",get_ticket_link:"ticket-card"}[l]??null:null}function Ae(){const e=Ee(),n=D(),t=n.toolOutput?.structuredContent,l=n.theme==="dark"?"dark":"light";if(!e)return r("div",{class:"sbb-empty",children:"Widget not initialised."});if(!t)return r("div",{class:"sbb-empty",children:"Loading…"});switch(e){case"stations-list":return r(Pe,{data:t});case"connection-list":return r(De,{data:t,theme:l});case"trip-details":return r(Ie,{data:t});case"prices-table":return r(Ne,{data:t});case"ticket-card":return r($e,{data:t})}}function fe(){const e=document.getElementById("sbb-widget-root");if(!e){console.warn("[sbb-widgets] #sbb-widget-root not found");return}const n=D().theme==="dark"?"dark":"light";e.classList.add("sbb-root"),e.setAttribute("data-theme",n),Se(r(Ae,{}),e)}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",fe):fe()})();
|
|
1
|
+
(function(){"use strict";var H,b,le,L,ce,ae,de,V,B,A,ue,J,K,Q,E={},F=[],Ue=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,U=Array.isArray;function C(e,t){for(var n in t)e[n]=t[n];return e}function X(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function Me(e,t,n){var i,o,s,c={};for(s in t)s=="key"?i=t[s]:s=="ref"?o=t[s]:c[s]=t[s];if(arguments.length>2&&(c.children=arguments.length>3?H.call(arguments,2):n),typeof e=="function"&&e.defaultProps!=null)for(s in e.defaultProps)c[s]===void 0&&(c[s]=e.defaultProps[s]);return M(e,c,i,o,null)}function M(e,t,n,i,o){var s={type:e,props:t,key:n,ref:i,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:o??++le,__i:-1,__u:0};return o==null&&b.vnode!=null&&b.vnode(s),s}function O(e){return e.children}function R(e,t){this.props=e,this.context=t}function x(e,t){if(t==null)return e.__?x(e.__,e.__i+1):null;for(var n;t<e.__k.length;t++)if((n=e.__k[t])!=null&&n.__e!=null)return n.__e;return typeof e.type=="function"?x(e):null}function Oe(e){if(e.__P&&e.__d){var t=e.__v,n=t.__e,i=[],o=[],s=C({},t);s.__v=t.__v+1,b.vnode&&b.vnode(s),Y(e.__P,s,t,e.__n,e.__P.namespaceURI,32&t.__u?[n]:null,i,n??x(t),!!(32&t.__u),o),s.__v=t.__v,s.__.__k[s.__i]=s,ye(i,s,o),t.__e=t.__=null,s.__e!=n&&he(s)}}function he(e){if((e=e.__)!=null&&e.__c!=null)return e.__e=e.__c.base=null,e.__k.some(function(t){if(t!=null&&t.__e!=null)return e.__e=e.__c.base=t.__e}),he(e)}function pe(e){(!e.__d&&(e.__d=!0)&&L.push(e)&&!W.__r++||ce!=b.debounceRendering)&&((ce=b.debounceRendering)||ae)(W)}function W(){try{for(var e,t=1;L.length;)L.length>t&&L.sort(de),e=L.shift(),t=L.length,Oe(e)}finally{L.length=W.__r=0}}function be(e,t,n,i,o,s,c,a,d,l,h){var _,p,u,g,w,k,f,m=i&&i.__k||F,$=t.length;for(d=Re(n,t,m,d,$),_=0;_<$;_++)(u=n.__k[_])!=null&&(p=u.__i!=-1&&m[u.__i]||E,u.__i=_,k=Y(e,u,p,o,s,c,a,d,l,h),g=u.__e,u.ref&&p.ref!=u.ref&&(p.ref&&te(p.ref,null,u),h.push(u.ref,u.__c||g,u)),w==null&&g!=null&&(w=g),(f=!!(4&u.__u))||p.__k===u.__k?(d=fe(u,d,e,f),f&&p.__e&&(p.__e=null)):typeof u.type=="function"&&k!==void 0?d=k:g&&(d=g.nextSibling),u.__u&=-7);return n.__e=w,d}function Re(e,t,n,i,o){var s,c,a,d,l,h=n.length,_=h,p=0;for(e.__k=new Array(o),s=0;s<o;s++)(c=t[s])!=null&&typeof c!="boolean"&&typeof c!="function"?(typeof c=="string"||typeof c=="number"||typeof c=="bigint"||c.constructor==String?c=e.__k[s]=M(null,c,null,null,null):U(c)?c=e.__k[s]=M(O,{children:c},null,null,null):c.constructor===void 0&&c.__b>0?c=e.__k[s]=M(c.type,c.props,c.key,c.ref?c.ref:null,c.__v):e.__k[s]=c,d=s+p,c.__=e,c.__b=e.__b+1,a=null,(l=c.__i=We(c,n,d,_))!=-1&&(_--,(a=n[l])&&(a.__u|=2)),a==null||a.__v==null?(l==-1&&(o>h?p--:o<h&&p++),typeof c.type!="function"&&(c.__u|=4)):l!=d&&(l==d-1?p--:l==d+1?p++:(l>d?p--:p++,c.__u|=4))):e.__k[s]=null;if(_)for(s=0;s<h;s++)(a=n[s])!=null&&!(2&a.__u)&&(a.__e==i&&(i=x(a)),ke(a,a));return i}function fe(e,t,n,i){var o,s;if(typeof e.type=="function"){for(o=e.__k,s=0;o&&s<o.length;s++)o[s]&&(o[s].__=e,t=fe(o[s],t,n,i));return t}e.__e!=t&&(i&&(t&&e.type&&!t.parentNode&&(t=x(e)),n.insertBefore(e.__e,t||null)),t=e.__e);do t=t&&t.nextSibling;while(t!=null&&t.nodeType==8);return t}function We(e,t,n,i){var o,s,c,a=e.key,d=e.type,l=t[n],h=l!=null&&(2&l.__u)==0;if(l===null&&a==null||h&&a==l.key&&d==l.type)return n;if(i>(h?1:0)){for(o=n-1,s=n+1;o>=0||s<t.length;)if((l=t[c=o>=0?o--:s++])!=null&&!(2&l.__u)&&a==l.key&&d==l.type)return c}return-1}function me(e,t,n){t[0]=="-"?e.setProperty(t,n??""):e[t]=n==null?"":typeof n!="number"||Ue.test(t)?n:n+"px"}function Z(e,t,n,i,o){var s,c;e:if(t=="style")if(typeof n=="string")e.style.cssText=n;else{if(typeof i=="string"&&(e.style.cssText=i=""),i)for(t in i)n&&t in n||me(e.style,t,"");if(n)for(t in n)i&&n[t]==i[t]||me(e.style,t,n[t])}else if(t[0]=="o"&&t[1]=="n")s=t!=(t=t.replace(ue,"$1")),c=t.toLowerCase(),t=c in e||t=="onFocusOut"||t=="onFocusIn"?c.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+s]=n,n?i?n[A]=i[A]:(n[A]=J,e.addEventListener(t,s?Q:K,s)):e.removeEventListener(t,s?Q:K,s);else{if(o=="http://www.w3.org/2000/svg")t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(t!="width"&&t!="height"&&t!="href"&&t!="list"&&t!="form"&&t!="tabIndex"&&t!="download"&&t!="rowSpan"&&t!="colSpan"&&t!="role"&&t!="popover"&&t in e)try{e[t]=n??"";break e}catch{}typeof n=="function"||(n==null||n===!1&&t[4]!="-"?e.removeAttribute(t):e.setAttribute(t,t=="popover"&&n==1?"":n))}}function ve(e){return function(t){if(this.l){var n=this.l[t.type+e];if(t[B]==null)t[B]=J++;else if(t[B]<n[A])return;return n(b.event?b.event(t):t)}}}function Y(e,t,n,i,o,s,c,a,d,l){var h,_,p,u,g,w,k,f,m,$,P,D,Fe,z,_e,T=t.type;if(t.constructor!==void 0)return null;128&n.__u&&(d=!!(32&n.__u),s=[a=t.__e=n.__e]),(h=b.__b)&&h(t);e:if(typeof T=="function")try{if(f=t.props,m=T.prototype&&T.prototype.render,$=(h=T.contextType)&&i[h.__c],P=h?$?$.props.value:h.__:i,n.__c?k=(_=t.__c=n.__c).__=_.__E:(m?t.__c=_=new T(f,P):(t.__c=_=new R(f,P),_.constructor=T,_.render=je),$&&$.sub(_),_.state||(_.state={}),_.__n=i,p=_.__d=!0,_.__h=[],_._sb=[]),m&&_.__s==null&&(_.__s=_.state),m&&T.getDerivedStateFromProps!=null&&(_.__s==_.state&&(_.__s=C({},_.__s)),C(_.__s,T.getDerivedStateFromProps(f,_.__s))),u=_.props,g=_.state,_.__v=t,p)m&&T.getDerivedStateFromProps==null&&_.componentWillMount!=null&&_.componentWillMount(),m&&_.componentDidMount!=null&&_.__h.push(_.componentDidMount);else{if(m&&T.getDerivedStateFromProps==null&&f!==u&&_.componentWillReceiveProps!=null&&_.componentWillReceiveProps(f,P),t.__v==n.__v||!_.__e&&_.shouldComponentUpdate!=null&&_.shouldComponentUpdate(f,_.__s,P)===!1){t.__v!=n.__v&&(_.props=f,_.state=_.__s,_.__d=!1),t.__e=n.__e,t.__k=n.__k,t.__k.some(function(I){I&&(I.__=t)}),F.push.apply(_.__h,_._sb),_._sb=[],_.__h.length&&c.push(_);break e}_.componentWillUpdate!=null&&_.componentWillUpdate(f,_.__s,P),m&&_.componentDidUpdate!=null&&_.__h.push(function(){_.componentDidUpdate(u,g,w)})}if(_.context=P,_.props=f,_.__P=e,_.__e=!1,D=b.__r,Fe=0,m)_.state=_.__s,_.__d=!1,D&&D(t),h=_.render(_.props,_.state,_.context),F.push.apply(_.__h,_._sb),_._sb=[];else do _.__d=!1,D&&D(t),h=_.render(_.props,_.state,_.context),_.state=_.__s;while(_.__d&&++Fe<25);_.state=_.__s,_.getChildContext!=null&&(i=C(C({},i),_.getChildContext())),m&&!p&&_.getSnapshotBeforeUpdate!=null&&(w=_.getSnapshotBeforeUpdate(u,g)),z=h!=null&&h.type===O&&h.key==null?ge(h.props.children):h,a=be(e,U(z)?z:[z],t,n,i,o,s,c,a,d,l),_.base=t.__e,t.__u&=-161,_.__h.length&&c.push(_),k&&(_.__E=_.__=null)}catch(I){if(t.__v=null,d||s!=null)if(I.then){for(t.__u|=d?160:128;a&&a.nodeType==8&&a.nextSibling;)a=a.nextSibling;s[s.indexOf(a)]=null,t.__e=a}else{for(_e=s.length;_e--;)X(s[_e]);ee(t)}else t.__e=n.__e,t.__k=n.__k,I.then||ee(t);b.__e(I,t,n)}else s==null&&t.__v==n.__v?(t.__k=n.__k,t.__e=n.__e):a=t.__e=Ze(n.__e,t,n,i,o,s,c,d,l);return(h=b.diffed)&&h(t),128&t.__u?void 0:a}function ee(e){e&&(e.__c&&(e.__c.__e=!0),e.__k&&e.__k.some(ee))}function ye(e,t,n){for(var i=0;i<n.length;i++)te(n[i],n[++i],n[++i]);b.__c&&b.__c(t,e),e.some(function(o){try{e=o.__h,o.__h=[],e.some(function(s){s.call(o)})}catch(s){b.__e(s,o.__v)}})}function ge(e){return typeof e!="object"||e==null||e.__b>0?e:U(e)?e.map(ge):C({},e)}function Ze(e,t,n,i,o,s,c,a,d){var l,h,_,p,u,g,w,k=n.props||E,f=t.props,m=t.type;if(m=="svg"?o="http://www.w3.org/2000/svg":m=="math"?o="http://www.w3.org/1998/Math/MathML":o||(o="http://www.w3.org/1999/xhtml"),s!=null){for(l=0;l<s.length;l++)if((u=s[l])&&"setAttribute"in u==!!m&&(m?u.localName==m:u.nodeType==3)){e=u,s[l]=null;break}}if(e==null){if(m==null)return document.createTextNode(f);e=document.createElementNS(o,m,f.is&&f),a&&(b.__m&&b.__m(t,s),a=!1),s=null}if(m==null)k===f||a&&e.data==f||(e.data=f);else{if(s=s&&H.call(e.childNodes),!a&&s!=null)for(k={},l=0;l<e.attributes.length;l++)k[(u=e.attributes[l]).name]=u.value;for(l in k)u=k[l],l=="dangerouslySetInnerHTML"?_=u:l=="children"||l in f||l=="value"&&"defaultValue"in f||l=="checked"&&"defaultChecked"in f||Z(e,l,null,u,o);for(l in f)u=f[l],l=="children"?p=u:l=="dangerouslySetInnerHTML"?h=u:l=="value"?g=u:l=="checked"?w=u:a&&typeof u!="function"||k[l]===u||Z(e,l,u,k[l],o);if(h)a||_&&(h.__html==_.__html||h.__html==e.innerHTML)||(e.innerHTML=h.__html),t.__k=[];else if(_&&(e.innerHTML=""),be(t.type=="template"?e.content:e,U(p)?p:[p],t,n,i,m=="foreignObject"?"http://www.w3.org/1999/xhtml":o,s,c,s?s[0]:n.__k&&x(n,0),a,d),s!=null)for(l=s.length;l--;)X(s[l]);a||(l="value",m=="progress"&&g==null?e.removeAttribute("value"):g!=null&&(g!==e[l]||m=="progress"&&!g||m=="option"&&g!=k[l])&&Z(e,l,g,k[l],o),l="checked",w!=null&&w!=e[l]&&Z(e,l,w,k[l],o))}return e}function te(e,t,n){try{if(typeof e=="function"){var i=typeof e.__u=="function";i&&e.__u(),i&&t==null||(e.__u=e(t))}else e.current=t}catch(o){b.__e(o,n)}}function ke(e,t,n){var i,o;if(b.unmount&&b.unmount(e),(i=e.ref)&&(i.current&&i.current!=e.__e||te(i,null,t)),(i=e.__c)!=null){if(i.componentWillUnmount)try{i.componentWillUnmount()}catch(s){b.__e(s,t)}i.base=i.__P=null}if(i=e.__k)for(o=0;o<i.length;o++)i[o]&&ke(i[o],t,n||typeof e.type!="function");n||X(e.__e),e.__c=e.__=e.__e=void 0}function je(e,t,n){return this.constructor(e,n)}function qe(e,t,n){var i,o,s,c;t==document&&(t=document.documentElement),b.__&&b.__(e,t),o=(i=!1)?null:t.__k,s=[],c=[],Y(t,e=t.__k=Me(O,null,[e]),o||E,E,t.namespaceURI,o?null:t.firstChild?H.call(t.childNodes):null,s,o?o.__e:t.firstChild,i,c),ye(s,e,c)}H=F.slice,b={__e:function(e,t,n,i){for(var o,s,c;t=t.__;)if((o=t.__c)&&!o.__)try{if((s=o.constructor)&&s.getDerivedStateFromError!=null&&(o.setState(s.getDerivedStateFromError(e)),c=o.__d),o.componentDidCatch!=null&&(o.componentDidCatch(e,i||{}),c=o.__d),c)return o.__E=o}catch(a){e=a}throw e}},le=0,R.prototype.setState=function(e,t){var n;n=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=C({},this.state),typeof e=="function"&&(e=e(C({},n),this.props)),e&&C(n,e),e!=null&&this.__v&&(t&&this._sb.push(t),pe(this))},R.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),pe(this))},R.prototype.render=O,L=[],ae=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,de=function(e,t){return e.__v.__b-t.__v.__b},W.__r=0,V=Math.random().toString(8),B="__d"+V,A="__a"+V,ue=/(PointerCapture)$|Capture$/i,J=0,K=ve(!1),Q=ve(!0);var Ge=0;function r(e,t,n,i,o,s){t||(t={});var c,a,d=t;if("ref"in d)for(a in d={},t)a=="ref"?c=t[a]:d[a]=t[a];var l={type:e,props:d,key:n,ref:c,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--Ge,__i:-1,__u:0,__source:o,__self:s};if(typeof e=="function"&&(c=e.defaultProps))for(a in c)d[a]===void 0&&(d[a]=c[a]);return b.vnode&&b.vnode(l),l}function N(){return window.openai??{}}function ze({data:e}){return e.stations.length?r("div",{children:[r("header",{class:"sbb-header",children:[r("h2",{class:"sbb-header__title",children:['Stations matching "',e.query,'"']}),r("span",{class:"sbb-header__meta",children:[e.stations.length," result",e.stations.length===1?"":"s"]})]}),r("div",{class:"sbb-list",children:e.stations.map(t=>r("div",{class:"sbb-connection",children:r("div",{children:[r("div",{style:{fontWeight:600},children:t.name}),r("div",{class:"sbb-connection__meta",children:[r("span",{class:"sbb-badge",children:["ID ",t.id]}),typeof t.lat=="number"&&typeof t.lon=="number"&&r("span",{children:[t.lat.toFixed(3),", ",t.lon.toFixed(3)]})]})]})},t.id))})]}):r("div",{class:"sbb-empty",children:['No stations matched "',e.query,'".']})}var ne,v,re,we,ie=0,Te=[],y=b,Ce=y.__b,Se=y.__r,Le=y.diffed,Ne=y.__c,$e=y.unmount,Pe=y.__;function Ve(e,t){y.__h&&y.__h(v,e,ie||t),ie=0;var n=v.__H||(v.__H={__:[],__h:[]});return e>=n.__.length&&n.__.push({}),n.__[e]}function Je(e){return ie=1,Ke(Ie,e)}function Ke(e,t,n){var i=Ve(ne++,2);if(i.t=e,!i.__c&&(i.__=[Ie(void 0,t),function(a){var d=i.__N?i.__N[0]:i.__[0],l=i.t(d,a);d!==l&&(i.__N=[l,i.__[1]],i.__c.setState({}))}],i.__c=v,!v.__f)){var o=function(a,d,l){if(!i.__c.__H)return!0;var h=i.__c.__H.__.filter(function(p){return p.__c});if(h.every(function(p){return!p.__N}))return!s||s.call(this,a,d,l);var _=i.__c.props!==a;return h.some(function(p){if(p.__N){var u=p.__[0];p.__=p.__N,p.__N=void 0,u!==p.__[0]&&(_=!0)}}),s&&s.call(this,a,d,l)||_};v.__f=!0;var s=v.shouldComponentUpdate,c=v.componentWillUpdate;v.componentWillUpdate=function(a,d,l){if(this.__e){var h=s;s=void 0,o(a,d,l),s=h}c&&c.call(this,a,d,l)},v.shouldComponentUpdate=o}return i.__N||i.__}function Qe(){for(var e;e=Te.shift();){var t=e.__H;if(e.__P&&t)try{t.__h.some(j),t.__h.some(se),t.__h=[]}catch(n){t.__h=[],y.__e(n,e.__v)}}}y.__b=function(e){v=null,Ce&&Ce(e)},y.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),Pe&&Pe(e,t)},y.__r=function(e){Se&&Se(e),ne=0;var t=(v=e.__c).__H;t&&(re===v?(t.__h=[],v.__h=[],t.__.some(function(n){n.__N&&(n.__=n.__N),n.u=n.__N=void 0})):(t.__h.some(j),t.__h.some(se),t.__h=[],ne=0)),re=v},y.diffed=function(e){Le&&Le(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(Te.push(t)!==1&&we===y.requestAnimationFrame||((we=y.requestAnimationFrame)||Xe)(Qe)),t.__H.__.some(function(n){n.u&&(n.__H=n.u),n.u=void 0})),re=v=null},y.__c=function(e,t){t.some(function(n){try{n.__h.some(j),n.__h=n.__h.filter(function(i){return!i.__||se(i)})}catch(i){t.some(function(o){o.__h&&(o.__h=[])}),t=[],y.__e(i,n.__v)}}),Ne&&Ne(e,t)},y.unmount=function(e){$e&&$e(e);var t,n=e.__c;n&&n.__H&&(n.__H.__.some(function(i){try{j(i)}catch(o){t=o}}),n.__H=void 0,t&&y.__e(t,n.__v))};var xe=typeof requestAnimationFrame=="function";function Xe(e){var t,n=function(){clearTimeout(i),xe&&cancelAnimationFrame(t),setTimeout(e)},i=setTimeout(n,35);xe&&(t=requestAnimationFrame(n))}function j(e){var t=v,n=e.__c;typeof n=="function"&&(e.__c=void 0,n()),v=t}function se(e){var t=v;e.__c=e.__(),v=t}function Ie(e,t){return typeof t=="function"?t(e):t}function S(e){try{return new Date(e).toLocaleTimeString("de-CH",{hour:"2-digit",minute:"2-digit",timeZone:"Europe/Zurich"})}catch{return e}}function oe(e){try{return new Date(e).toLocaleDateString("en-CH",{weekday:"short",day:"2-digit",month:"short",timeZone:"Europe/Zurich"})}catch{return e}}function q(e){if(!Number.isFinite(e)||e<0)return"—";const t=Math.floor(e/60),n=e%60;return t===0?`${n}m`:n===0?`${t}h`:`${t}h ${n}m`}function Ae(e,t="CHF"){return`${t} ${e.toFixed(2)}`}const Ye="https://mcp.swisstrip.app",et=1;function tt(e){return btoa(unescape(encodeURIComponent(e))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function nt(e){const t=new Date(e),n=t.toLocaleDateString("en-CA",{timeZone:"Europe/Zurich"}),i=t.toLocaleTimeString("en-GB",{timeZone:"Europe/Zurich",hour:"2-digit",minute:"2-digit"});return{date:n,time:i}}function rt(e){const{date:t,time:n}=nt(e.departureIso),i={v:et,tid:e.tripId,o:e.fromId,on:e.fromName,d:e.toId,dn:e.toName,dt:t,t:n,l:e.lang??"en"},o=tt(JSON.stringify(i));return`${Ye}/r/${o}`}const it={reductionCard:"HALF_FARE",travelerType:"ADULT"};function De(e){switch(e){case"HALF_FARE":return"Halbtax";case"GA":return"GA";case"NONE":return"No card"}}function st(e){return e==="CHILD"?"child":"adult"}function ot({prefs:e,onChange:t}){const[n,i]=Je(!1);return r("div",{class:"sbb-traveler-bar",children:[r("div",{class:"sbb-traveler-bar__summary",children:[r("span",{class:"sbb-traveler-bar__text",children:["Pricing for: ",r("strong",{children:["1 ",st(e.travelerType)]})," · ",r("strong",{children:De(e.reductionCard)})]}),r("button",{type:"button",class:"sbb-button sbb-button--ghost",onClick:()=>i(!n),children:n?"Done":"Change"})]}),n&&r("div",{class:"sbb-traveler-bar__form",children:[r("div",{class:"sbb-traveler-bar__group",children:[r("span",{class:"sbb-traveler-bar__label",children:"Reduction card"}),r("div",{class:"sbb-traveler-bar__options",children:["HALF_FARE","GA","NONE"].map(o=>r("button",{type:"button",class:`sbb-chip ${e.reductionCard===o?"sbb-chip--active":""}`,onClick:()=>t({...e,reductionCard:o}),children:De(o)},o))})]}),r("div",{class:"sbb-traveler-bar__group",children:[r("span",{class:"sbb-traveler-bar__label",children:"Traveler"}),r("div",{class:"sbb-traveler-bar__options",children:["ADULT","CHILD"].map(o=>r("button",{type:"button",class:`sbb-chip ${e.travelerType===o?"sbb-chip--active":""}`,onClick:()=>t({...e,travelerType:o}),children:o==="ADULT"?"Adult":"Child (6–16)"},o))})]}),r("p",{class:"sbb-traveler-bar__hint",children:'For multiple travelers or family tickets, ask in chat — e.g. "2 adults + 1 kid age 8".'})]})]})}function _t({legs:e}){const t=e.filter(n=>n.type==="train");return t.length===0?null:r("span",{class:"sbb-connection__route",children:t.map((n,i)=>r("span",{children:[i>0&&r("span",{style:{color:"var(--text-muted)",margin:"0 2px"},children:"›"}),r("span",{class:"sbb-badge",children:[n.line??"Train",n.platform?` · Pl. ${n.platform}`:""]})]},i))})}function lt(e,t,n,i){return rt({tripId:e.tripId,fromId:t.id,fromName:t.name,toId:n.id,toName:n.name,departureIso:e.departureTime,lang:i})}function ct({c:e,origin:t,destination:n,lang:i,onPrice:o}){const s=lt(e,t,n,i);return r("div",{class:"sbb-connection",children:[r("div",{children:[r("div",{class:"sbb-connection__times",children:[r("a",{class:"sbb-connection__time sbb-connection__time--link",href:s,target:"_blank",rel:"noopener noreferrer",title:"Open on SBB.ch",children:S(e.departureTime)}),r("span",{class:"sbb-connection__arrow",children:"→"}),r("span",{class:"sbb-connection__time",children:S(e.arrivalTime)})]}),r("div",{class:"sbb-connection__meta",children:[r("span",{class:"sbb-badge",children:q(e.durationMinutes)}),r("span",{class:"sbb-badge",children:[e.transfers," transfer",e.transfers===1?"":"s"]}),r(_t,{legs:e.legs})]})]}),r("div",{class:"sbb-connection__actions",children:[r("button",{type:"button",class:"sbb-button",onClick:o,children:"Price"}),r("a",{class:"sbb-button sbb-button--primary",href:s,target:"_blank",rel:"noopener noreferrer",children:"Book"})]})]})}function at({data:e,theme:t}){const n=N(),i=n.widgetState?.travelerPrefs??it,o=l=>{n.setWidgetState?.({...n.widgetState??{},travelerPrefs:l})},s=()=>({traveler_type:i.travelerType,reduction_card:i.reductionCard}),c=l=>{n.callTool?.("get_prices",{trip_ids:[l],...s()})},a=l=>{n.callTool?.("get_more_connections",{collection_id:e.collectionId,direction:l})},d=()=>{const l=e.connections.slice(0,5).map(h=>h.tripId);l.length&&n.callTool?.("get_prices",{trip_ids:l,...s()})};return e.connections.length?r("div",{children:[r("header",{class:"sbb-header",children:[r("h2",{class:"sbb-header__title",children:[e.origin.name," → ",e.destination.name]}),r("span",{class:"sbb-header__meta",children:oe(e.date)})]}),r(ot,{prefs:i,onChange:o}),r("div",{class:"sbb-list",children:e.connections.map(l=>r(ct,{c:l,origin:e.origin,destination:e.destination,lang:e.lang,onPrice:()=>c(l.tripId)},l.tripId))}),e.weather?.summary&&r("div",{class:"sbb-weather",children:["☁ ",e.destination.name,": ",e.weather.summary]}),r("div",{class:"sbb-footer",children:[r("button",{type:"button",class:"sbb-button",onClick:()=>a("previous"),children:"← Earlier"}),r("button",{type:"button",class:"sbb-button",onClick:()=>a("next"),children:"Later →"}),r("button",{type:"button",class:"sbb-button sbb-button--primary",onClick:d,children:"See all prices"})]})]}):r("div",{class:"sbb-empty",children:"No connections found."})}function dt({leg:e,index:t}){return e.type==="walk"?r("div",{class:"sbb-card",style:{background:"var(--bg)"},children:r("div",{style:{fontWeight:600},children:["Transfer · walk ",q(e.durationMinutes)]})}):r("div",{class:"sbb-card",children:[r("div",{style:{display:"flex",alignItems:"baseline",justifyContent:"space-between",gap:8},children:[r("div",{children:[r("span",{class:"sbb-badge sbb-badge--accent",children:["Leg ",t+1]}),r("span",{style:{marginLeft:8,fontWeight:600},children:[e.line??"Train",e.operator?r("span",{class:"sbb-header__meta",children:[" · ",e.operator]}):null]})]}),r("span",{class:"sbb-header__meta",children:q(e.durationMinutes)})]}),r("div",{class:"sbb-timeline",children:[e.from&&r("div",{class:"sbb-timeline__stop",children:[r("span",{children:[r("strong",{children:e.from.name}),e.from.platform?r("span",{class:"sbb-header__meta",children:[" · Pl. ",e.from.platform]}):null]}),r("span",{class:"sbb-timeline__time",children:S(e.from.time)})]}),e.intermediateStops?.map((n,i)=>r("div",{class:"sbb-timeline__stop sbb-timeline__stop--intermediate",children:[r("span",{children:n.name}),r("span",{class:"sbb-timeline__time",children:n.arrivalTime?S(n.arrivalTime):""})]},i)),e.to&&r("div",{class:"sbb-timeline__stop",children:[r("span",{children:[r("strong",{children:e.to.name}),e.to.platform?r("span",{class:"sbb-header__meta",children:[" · Pl. ",e.to.platform]}):null]}),r("span",{class:"sbb-timeline__time",children:S(e.to.time)})]})]}),e.occupancy&&r("div",{class:"sbb-connection__meta",children:[e.occupancy.firstClass&&r("span",{class:"sbb-badge",children:["1st: ",e.occupancy.firstClass]}),e.occupancy.secondClass&&r("span",{class:"sbb-badge",children:["2nd: ",e.occupancy.secondClass]})]})]})}function ut({data:e}){const t=N();return r("div",{children:[r("header",{class:"sbb-header",children:[r("h2",{class:"sbb-header__title",children:[e.origin.name," → ",e.destination.name]}),r("span",{class:"sbb-header__meta",children:oe(e.departureTime)})]}),r("div",{class:"sbb-card",style:{marginBottom:"var(--gap)"},children:r("div",{style:{display:"flex",justifyContent:"space-between"},children:[r("div",{class:"sbb-connection__times",children:[r("span",{class:"sbb-connection__time",children:S(e.departureTime)}),r("span",{class:"sbb-connection__arrow",children:"→"}),r("span",{class:"sbb-connection__time",children:S(e.arrivalTime)})]}),r("div",{class:"sbb-connection__meta",children:[r("span",{class:"sbb-badge",children:q(e.durationMinutes)}),r("span",{class:"sbb-badge",children:[e.transfers," transfer",e.transfers===1?"":"s"]}),r("span",{class:"sbb-badge",children:e.status})]})]})}),r("div",{class:"sbb-list",children:e.legs.map((n,i)=>r(dt,{leg:n,index:i},i))}),r("div",{class:"sbb-footer",children:r("button",{type:"button",class:"sbb-button sbb-button--primary",onClick:()=>t.callTool?.("get_prices",{trip_ids:[e.tripId]}),children:"See price"})})]})}function ht({data:e}){return e.prices.length?r("div",{children:[r("header",{class:"sbb-header",children:[r("h2",{class:"sbb-header__title",children:"Ticket prices"}),r("span",{class:"sbb-header__meta",children:[e.prices.length," trip",e.prices.length===1?"":"s"]})]}),r("div",{class:"sbb-card",children:r("table",{class:"sbb-table",children:[r("thead",{children:r("tr",{children:[r("th",{children:"Trip"}),r("th",{children:"2nd class"}),r("th",{children:"1st class"})]})}),r("tbody",{children:e.prices.map(t=>r("tr",{children:[r("td",{style:{fontFamily:"ui-monospace, monospace",fontSize:11},children:[t.tripId.slice(0,12),"…"]}),r("td",{children:t.secondClass?Ae(t.secondClass.amount,t.secondClass.currency):"—"}),r("td",{children:t.firstClass?Ae(t.firstClass.amount,t.firstClass.currency):"—"})]},t.tripId))})]})}),r("div",{class:"sbb-header__meta",style:{marginTop:8},children:"Prices are estimates. Ask for the ticket link to see the final price on SBB.ch."})]}):r("div",{class:"sbb-empty",children:"No price information available."})}function He(e){return`https://swisstrip.app/go?url=${encodeURIComponent(e)}`}function pt({data:e}){const t=e.affiliateLink??e.primaryLink;return r("div",{class:"sbb-ticket-card",children:[r("header",{class:"sbb-header",children:[r("h2",{class:"sbb-header__title",children:"Buy ticket on SBB"}),r("span",{class:"sbb-header__meta",children:oe(e.departureTime)})]}),r("div",{children:[r("div",{class:"sbb-ticket-card__route",children:[e.origin.name," → ",e.destination.name]}),r("div",{class:"sbb-ticket-card__times",children:[S(e.departureTime)," – ",S(e.arrivalTime)]})]}),r("div",{style:{display:"flex",gap:8,flexWrap:"wrap"},children:[r("a",{class:"sbb-button sbb-button--primary",href:He(t),target:"_blank",rel:"noopener noreferrer",children:"Buy on SBB.ch →"}),e.affiliateLink&&e.affiliateLink!==e.primaryLink&&r("a",{class:"sbb-button",href:He(e.primaryLink),target:"_blank",rel:"noopener noreferrer",children:"Direct SBB link"})]}),r("div",{class:"sbb-header__meta",style:{fontSize:11},children:"Opens SBB.ch with this connection pre-filled. On mobile, the SBB app opens directly with your Halbtax/GA applied."})]})}function bt(){const t=document.getElementById("sbb-widget-root")?.getAttribute("data-widget");if(t)return t;const i=N().toolName;return i?{search_stations:"stations-list",search_connections:"connection-list",get_more_connections:"connection-list",get_trip_details:"trip-details",get_prices:"prices-table",get_ticket_link:"ticket-card"}[i]??null:null}let G=0;function Be({tick:e}){const t=N(),n=typeof window<"u"&&window.openai?Object.keys(window.openai).join(", ")||"(none)":"(no window.openai)";return r("details",{class:"sbb-debug",children:[r("summary",{children:["Debug · tick ",e]}),r("div",{children:["window.openai keys: ",r("code",{children:n})]}),r("div",{children:["toolName: ",r("code",{children:String(t.toolName??"undefined")})]}),r("div",{children:["toolOutput: ",r("code",{children:t.toolOutput?"present":"missing"})]})]})}function ft(){const e=bt(),t=N(),n=t.toolOutput,i=t.theme==="dark"?"dark":"light";if(!e)return r("div",{class:"sbb-empty",children:["Widget not initialised.",r(Be,{tick:G})]});if(!n)return r("div",{class:"sbb-empty",children:["Loading…",r(Be,{tick:G})]});switch(e){case"stations-list":return r(ze,{data:n});case"connection-list":return r(at,{data:n,theme:i});case"trip-details":return r(ut,{data:n});case"prices-table":return r(ht,{data:n});case"ticket-card":return r(pt,{data:n})}}function mt(e){const t=N().theme==="dark"?"dark":"light";e.setAttribute("data-theme",t)}function Ee(){const e=document.getElementById("sbb-widget-root");if(!e){console.warn("[sbb-widgets] #sbb-widget-root not found");return}e.classList.add("sbb-root");const t=o=>{G++,console.debug("[sbb-widgets] rerender",{reason:o,tick:G,hasToolOutput:!!N().toolOutput}),mt(e),qe(r(ft,{}),e)};t("initial"),window.addEventListener("openai:set_globals",()=>t("set_globals"));let n=0;const i=window.setInterval(()=>{n++,N().toolOutput?(t("poll"),window.clearInterval(i)):n>=50&&window.clearInterval(i)},100)}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Ee):Ee()})();
|