@v-office/website-chat 0.0.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,55 @@
1
1
  # @v-office/website-chat
2
2
 
3
- Placeholder that holds the name on npm until the first release.
3
+ The AI chat of a v-office website. A visitor asks for a stay; the chat searches the agency's rentals,
4
+ shows them as cards with the PMS's prices, and links each stay to its rental page with the dates and party
5
+ filled in. It never books and has no form of its own.
6
+
7
+ **Peers:** React `^19.2.3`, `@v-office/website-headless` `>=1.1.0 <2`. Sites pin exact versions.
8
+
9
+ ## Entry points
10
+
11
+ | Import | Contents |
12
+ | :------------------------------- | :-------------------------------------------------------------- |
13
+ | `@v-office/website-chat` | `WebsiteChat`, `DEFAULT_COPY`, `CHAT_THEMES`, `CHAT_LOCALES` |
14
+ | `@v-office/website-chat/catalog` | the json-render catalog and wire protocol, for the chat service |
15
+
16
+ ## Adding the chat to a site
17
+
18
+ Render `WebsiteChat` once in the layout as a client island; see `instructions/versions/1.0.0/MIGRATION.md`.
19
+
20
+ ```astro
21
+ <WebsiteChat client:idle endpoint={import.meta.env.PUBLIC_CHAT_ENDPOINT} locale="de"
22
+ searchPath="/suche" contactPath="/kontakt" />
23
+ ```
24
+
25
+ | Prop | Required | Meaning |
26
+ | :------------ | :------- | :----------------------------------------------------------------------- |
27
+ | `endpoint` | yes | `import.meta.env.PUBLIC_CHAT_ENDPOINT`, which AI Studio's builds set |
28
+ | `locale` | yes | `"de"` or `"en"` |
29
+ | `searchPath` | yes | the site's search, for a rental without a page and when the chat is down |
30
+ | `contactPath` | yes | the site's contact page |
31
+ | `theme` | no | `classic` (default), `soft` or `minimal` |
32
+ | `colors` | no | `{ primary, secondary }`, any CSS colour (buttons; visitor messages) |
33
+ | `position` | no | the entry pill and the panel on the `right` (default) or `left` |
34
+ | `copy` | no | overrides of single fields of `DEFAULT_COPY` (strings, `suggestions`) |
35
+
36
+ The chat stays hidden until an agent switches it on for the website in AI Studio.
37
+
38
+ A site with a sticky header sets `--chat-top` (its height) on any element around the widget, such as
39
+ `:root`: the dimmed page and the panel start below it. `--chat-width` widens the panel on wide screens
40
+ (default `600px`).
41
+
42
+ The service places these components in replies: `RentalCard` (photo gallery, rating, the wishes the
43
+ search that found it applied), `RentalCarousel`, `Compare`, `StayQuote`, `PriceBreakdown`,
44
+ `AlternativeStays`, `AvailabilityCalendar`, `PriceCalendar`, `ReviewSummary`, `RentalFacts`,
45
+ `RentalMap`, `StayLink`, `ContactLink` and `QuickReplies`. They all read the PMS's data by id; none takes a price, a URL or
46
+ free text from the AI (QuickReplies' short answers excepted). `RentalMap` loads its map (MapLibre,
47
+ OpenFreeMap tiles) only when the visitor taps it.
48
+
49
+ ## Development
50
+
51
+ ```sh
52
+ pnpm check && pnpm build && pnpm test
53
+ ```
54
+
55
+ See `AGENTS.md` and `docs/internal/releasing/overview.md`.
@@ -0,0 +1,183 @@
1
+ import { defineCatalog } from "@json-render/core";
2
+ import { schema } from "@json-render/react/schema";
3
+ import { z } from "zod";
4
+ //#region src/state.ts
5
+ /** See {@link StateKey}. */
6
+ const stateKey = (id) => id.replaceAll("~", "~0").replaceAll("/", "~1");
7
+ /** See {@link StatePath}. */
8
+ const statePath = (section, id) => `/${section}/${stateKey(id)}`;
9
+ //#endregion
10
+ //#region src/catalog.ts
11
+ const id = z.string().min(1).max(200);
12
+ /** A rental, with the stay to show for it when there is one. */
13
+ const offer = z.object({
14
+ rentalId: id,
15
+ stayId: id.nullable()
16
+ });
17
+ /** Every component of the chat. `Stack` is the service's root; the others the model places. */
18
+ const chatCatalog = defineCatalog(schema, {
19
+ components: {
20
+ Stack: {
21
+ props: z.object({}),
22
+ slots: ["default"],
23
+ description: "Stacks what the reply shows. Placed by the service, never by the model."
24
+ },
25
+ RentalCard: {
26
+ props: offer,
27
+ description: "One rental with its photos, rating and facts; with a stayId also that stay's dates, price and a booking button."
28
+ },
29
+ RentalCarousel: {
30
+ props: z.object({ items: z.array(offer).min(2).max(8) }),
31
+ description: "Several rentals side by side, swipeable, each as a RentalCard. Use it for search results instead of several RentalCards."
32
+ },
33
+ StayQuote: {
34
+ props: z.object({ stayId: id }),
35
+ description: "One priced stay: the rental, the dates, the party, the total and a booking button."
36
+ },
37
+ PriceBreakdown: {
38
+ props: z.object({ stayId: id }),
39
+ description: "What a quoted stay's total is made of (nights, cleaning, pets, …), line by line. Only for a stay from quote_stay."
40
+ },
41
+ AlternativeStays: {
42
+ props: z.object({
43
+ rentalId: id,
44
+ stayIds: z.array(id).min(1).max(6)
45
+ }),
46
+ description: "Free periods of one rental as tappable choices with their prices: other dates when the asked ones are taken, or the periods a flexible search found."
47
+ },
48
+ AvailabilityCalendar: {
49
+ props: z.object({
50
+ rentalId: id,
51
+ stayId: id.nullable()
52
+ }),
53
+ description: "A rental's month calendar of free and taken days, with a stay's dates marked when there is one. Only after get_availability."
54
+ },
55
+ PriceCalendar: {
56
+ props: z.object({ rentalId: id }),
57
+ description: "One rental's total for the same length of stay at the arrivals around the asked one, cheapest marked; tapping one asks for it. Only after price_calendar."
58
+ },
59
+ ReviewSummary: {
60
+ props: z.object({ rentalId: id }),
61
+ description: "A rental's guest rating as the booking system sums it up, its category ratings and a few review texts. Only after get_reviews."
62
+ },
63
+ RentalFacts: {
64
+ props: z.object({
65
+ rentalId: id,
66
+ groups: z.array(z.string().trim().min(1).max(80)).min(1).max(4)
67
+ }),
68
+ description: "The facts of one rental in the groups get_rental listed (by their label, such as Haustiere or Lage), for a question about pets, the kitchen or the surroundings."
69
+ },
70
+ RentalMap: {
71
+ props: z.object({ rentalId: id }),
72
+ description: "Where one rental is: a map the visitor loads with a tap, and a link to its page."
73
+ },
74
+ Compare: {
75
+ props: z.object({ items: z.array(offer).min(2).max(3) }),
76
+ description: "Two or three rentals side by side: rating, rooms, highlights, the stay and its price."
77
+ },
78
+ StayLink: {
79
+ props: z.object({
80
+ rentalId: id,
81
+ stayId: id.nullable()
82
+ }),
83
+ description: "A button to the rental's page on this website, with the stay filled in, to book there."
84
+ },
85
+ ContactLink: {
86
+ props: z.object({}),
87
+ description: "A link to this website's contact page."
88
+ },
89
+ QuickReplies: {
90
+ props: z.object({ options: z.array(z.string().trim().min(1).max(40)).min(1).max(4) }),
91
+ description: "Up to four short answers the visitor can tap to send as their next message (\"Nur mit Sauna\", \"Andere Termine\"). Never a fact or a price."
92
+ }
93
+ },
94
+ actions: {}
95
+ });
96
+ /** The components the model may place; `Stack` is the service's. */
97
+ const PLACEABLE_COMPONENTS = [
98
+ "RentalCard",
99
+ "RentalCarousel",
100
+ "StayQuote",
101
+ "PriceBreakdown",
102
+ "AlternativeStays",
103
+ "AvailabilityCalendar",
104
+ "PriceCalendar",
105
+ "ReviewSummary",
106
+ "RentalFacts",
107
+ "RentalMap",
108
+ "Compare",
109
+ "StayLink",
110
+ "ContactLink",
111
+ "QuickReplies"
112
+ ];
113
+ /** The package version each component was added in. A minor adds components (and optional props, which an
114
+ * older renderer ignores); the service offers a widget only what its version has. */
115
+ const COMPONENT_SINCE = {
116
+ Stack: "1.0.0",
117
+ RentalCard: "1.0.0",
118
+ RentalCarousel: "1.0.0",
119
+ StayQuote: "1.0.0",
120
+ PriceBreakdown: "1.0.0",
121
+ AlternativeStays: "1.0.0",
122
+ AvailabilityCalendar: "1.0.0",
123
+ PriceCalendar: "1.0.0",
124
+ ReviewSummary: "1.0.0",
125
+ RentalFacts: "1.0.0",
126
+ RentalMap: "1.0.0",
127
+ Compare: "1.0.0",
128
+ StayLink: "1.0.0",
129
+ ContactLink: "1.0.0",
130
+ QuickReplies: "1.0.0"
131
+ };
132
+ const versionOf = (version) => {
133
+ const match = /^(\d+)\.(\d+)\.(\d+)/.exec(version);
134
+ return match ? [
135
+ Number(match[1]),
136
+ Number(match[2]),
137
+ Number(match[3])
138
+ ] : null;
139
+ };
140
+ /** See {@link ComponentsFor}. */
141
+ const componentsFor = (clientVersion) => {
142
+ const client = versionOf(clientVersion);
143
+ if (!client) return [];
144
+ return PLACEABLE_COMPONENTS.filter((name) => {
145
+ const since = versionOf(COMPONENT_SINCE[name]);
146
+ if (since[0] !== client[0]) return false;
147
+ return since[1] < client[1] || since[1] === client[1] && since[2] <= client[2];
148
+ });
149
+ };
150
+ /** See {@link ParseItem}. */
151
+ const parseItem = (item, allowed) => {
152
+ if (typeof item !== "object" || item === null) return null;
153
+ const { type, props } = item;
154
+ const name = allowed.find((candidate) => candidate === type);
155
+ if (!name) return null;
156
+ const parsed = chatCatalog.data.components[name].props.safeParse(props ?? {});
157
+ return parsed.success ? {
158
+ type: name,
159
+ props: parsed.data
160
+ } : null;
161
+ };
162
+ /** See {@link ChatSpec}. */
163
+ const chatSpec = (items, state) => {
164
+ const keys = items.map((_, index) => `item-${index}`);
165
+ return {
166
+ root: "root",
167
+ elements: {
168
+ root: {
169
+ type: "Stack",
170
+ props: {},
171
+ children: keys
172
+ },
173
+ ...Object.fromEntries(items.map((item, index) => [keys[index], {
174
+ type: item.type,
175
+ props: { ...item.props },
176
+ children: []
177
+ }]))
178
+ },
179
+ state: { ...state }
180
+ };
181
+ };
182
+ //#endregion
183
+ export { componentsFor as a, statePath as c, chatSpec as i, PLACEABLE_COMPONENTS as n, parseItem as o, chatCatalog as r, stateKey as s, COMPONENT_SINCE as t };
@@ -0,0 +1,303 @@
1
+ import { a as ChatLocale, c as MAX_MESSAGE_CHARS, i as ChatEvent, l as SESSION_TTL_S, n as CHAT_PATH, o as ChatRequest, r as ChatAvailability, s as ChatUnavailableReason, t as CHAT_LOCALES } from "./protocol-Bmb_uxVQ.js";
2
+ import { Spec } from "@json-render/core";
3
+ import { z } from "zod";
4
+ import { Party } from "@v-office/website-headless";
5
+ //#region src/state.d.ts
6
+ /** One photo of a rental, as the PMS serves it. */
7
+ interface ChatImage {
8
+ readonly src: string;
9
+ /** The PMS's description; empty when it has none. */
10
+ readonly alt: string;
11
+ }
12
+ /** A rental as the chat shows it: facts from the PMS, never from the model. */
13
+ interface ChatRental {
14
+ readonly id: string;
15
+ readonly name: string;
16
+ /** Its first photos (at most 8), in the PMS's order; empty without any. */
17
+ readonly images: readonly ChatImage[];
18
+ /** Where it is, as the PMS names the place. */
19
+ readonly place: string | null;
20
+ /** Short facts the PMS highlights ("Sauna", "4 Gäste"). */
21
+ readonly highlights: readonly string[];
22
+ /** The review summary as the PMS formats it ("4,8", "36"); `null` without reviews. */
23
+ readonly rating: {
24
+ readonly value: string;
25
+ readonly count: string;
26
+ } | null;
27
+ /** The rooms as the PMS sums them up ("3 Schlafzimmer"); empty when unknown. */
28
+ readonly rooms: readonly string[];
29
+ /** Where it is, as the PMS publishes it; absent or `null` without coordinates. */
30
+ readonly location?: {
31
+ readonly lat: number;
32
+ readonly lng: number;
33
+ } | null;
34
+ }
35
+ /** A stay of one rental for one party, priced by the PMS. */
36
+ interface ChatStay {
37
+ readonly id: string;
38
+ readonly rentalId: string;
39
+ /** `YYYY-MM-DD`. */
40
+ readonly start: string;
41
+ /** `YYYY-MM-DD`, after `start`. */
42
+ readonly end: string;
43
+ readonly party: Party;
44
+ /** The total as the SDK formats it ("1.234,00 €"); `null` when the PMS gave none. */
45
+ readonly total: string | null;
46
+ /** Whether the PMS can book this stay as asked. */
47
+ readonly bookable: boolean;
48
+ /** The total's lines as the PMS's quote lists them ("Endreinigung", "120,00 €"); empty when only
49
+ * the total is known (a search result). */
50
+ readonly lines: readonly {
51
+ readonly label: string;
52
+ readonly amount: string;
53
+ }[];
54
+ }
55
+ /** A day of a rental's calendar: bookable, taken, or outside what can be booked (past, closed). */
56
+ type ChatDayStatus = "free" | "booked" | "closed";
57
+ /** A rental's calendar for a stretch of days, as the PMS answered it. */
58
+ interface ChatCalendar {
59
+ /** `YYYY-MM-DD`, the first day asked for. */
60
+ readonly from: string;
61
+ /** `YYYY-MM-DD`, the last day asked for. */
62
+ readonly through: string;
63
+ /** Every day from `from` through `through`. */
64
+ readonly days: Readonly<Record<string, ChatDayStatus>>;
65
+ }
66
+ /** One stay length's totals for the arrivals around the asked one, as the PMS priced them. */
67
+ interface ChatPriceCalendar {
68
+ readonly nights: number;
69
+ /** In date order. A taken or unbookable arrival has no stay. */
70
+ readonly options: readonly {
71
+ readonly start: string;
72
+ readonly end: string;
73
+ readonly stayId: string | null;
74
+ /** The total relative to the dearest option, 0 to 1, for the bar; `null` when unknown. */
75
+ readonly level: number | null;
76
+ }[];
77
+ /** The arrival the visitor asked for. */
78
+ readonly asked: string;
79
+ /** The cheapest option's stay, only where it saves: below the asked stay, or below another option
80
+ * when the asked one has no price. `null` otherwise (equal totals, the asked stay already the
81
+ * cheapest, nothing priced): `null` does not mean nothing is bookable. */
82
+ readonly cheapest: string | null;
83
+ }
84
+ /** A rental's reviews as the PMS summarises them, with a few of their texts. */
85
+ interface ChatReviews {
86
+ /** As the PMS formats them ("4,8", "36"). */
87
+ readonly rating: string;
88
+ readonly count: string;
89
+ /** The PMS's verbal grade ("Hervorragend"); empty when it has none. */
90
+ readonly grade: string;
91
+ readonly categories: readonly {
92
+ readonly label: string;
93
+ readonly rating: string;
94
+ }[];
95
+ /** At most three, shortened, without the reviewer's name: newest first where the PMS dates its
96
+ * reviews (v10), otherwise in its order. */
97
+ readonly excerpts: readonly {
98
+ readonly text: string;
99
+ }[];
100
+ }
101
+ /** One group of a rental's facts as the PMS lists them ("Küche", "Lage"). */
102
+ interface ChatFactGroup {
103
+ readonly label: string;
104
+ readonly items: readonly string[];
105
+ }
106
+ /** The state of one spec: everything its components read, keyed by the raw id. */
107
+ interface ChatState {
108
+ readonly rentals: Readonly<Record<string, ChatRental>>;
109
+ readonly stays: Readonly<Record<string, ChatStay>>;
110
+ /** A rental's page on this website in the visitor's language; absent without one. */
111
+ readonly pages: Readonly<Record<string, string>>;
112
+ /** A rental's calendar, by rental id; only for rentals whose calendar was asked for. */
113
+ readonly availability: Readonly<Record<string, ChatCalendar>>;
114
+ /** A rental's price calendar, by rental id (PriceCalendar). */
115
+ readonly priceCalendars: Readonly<Record<string, ChatPriceCalendar>>;
116
+ /** A rental's reviews, by rental id (ReviewSummary). */
117
+ readonly reviews: Readonly<Record<string, ChatReviews>>;
118
+ /** A rental's fact groups, by rental id (RentalFacts). */
119
+ readonly facts: Readonly<Record<string, readonly ChatFactGroup[]>>;
120
+ /** The visitor's wishes the latest search that found a rental applied ("Sauna", "Haustiere
121
+ * erlaubt"), as the PMS labels its filters, by rental id: the rental has each. With dates or
122
+ * without; absent when that search applied none. */
123
+ readonly wishes: Readonly<Record<string, readonly string[]>>;
124
+ }
125
+ /** An id as one JSON Pointer token (RFC 6901): a v10 rental id may contain `/` or `~`, which would
126
+ * otherwise change the path a component reads. State stays keyed by the raw id; only paths escape it. */
127
+ type StateKey = (id: string) => string;
128
+ /** The pointer a component reads one entry from (`/rentals/<escaped id>`). */
129
+ type StatePath = (section: keyof ChatState, id: string) => string;
130
+ /** See {@link StateKey}. */
131
+ export declare const stateKey: StateKey;
132
+ /** See {@link StatePath}. */
133
+ export declare const statePath: StatePath;
134
+ //#endregion
135
+ //#region src/catalog.d.ts
136
+ /** Every component of the chat. `Stack` is the service's root; the others the model places. */
137
+ export declare const chatCatalog: import("@json-render/core").Catalog<{
138
+ spec: import("@json-render/core").SchemaType<"object", {
139
+ root: import("@json-render/core").SchemaType<"string", unknown>;
140
+ elements: import("@json-render/core").SchemaType<"record", import("@json-render/core").SchemaType<"object", {
141
+ type: import("@json-render/core").SchemaType<"ref", string>;
142
+ props: import("@json-render/core").SchemaType<"propsOf", string>;
143
+ children: import("@json-render/core").SchemaType<"array", import("@json-render/core").SchemaType<"string", unknown>>;
144
+ slots: {
145
+ optional: true;
146
+ kind: "record";
147
+ inner?: import("@json-render/core").SchemaType<"array", import("@json-render/core").SchemaType<"string", unknown>> | undefined;
148
+ };
149
+ visible: {
150
+ optional: true;
151
+ kind: "any";
152
+ inner?: unknown;
153
+ };
154
+ repeat: {
155
+ optional: true;
156
+ kind: "any";
157
+ inner?: unknown;
158
+ };
159
+ }>>;
160
+ }>;
161
+ catalog: import("@json-render/core").SchemaType<"object", {
162
+ components: import("@json-render/core").SchemaType<"map", {
163
+ props: import("@json-render/core").SchemaType<"zod", unknown>;
164
+ slots: import("@json-render/core").SchemaType<"array", import("@json-render/core").SchemaType<"string", unknown>>;
165
+ description: import("@json-render/core").SchemaType<"string", unknown>;
166
+ example: import("@json-render/core").SchemaType<"any", unknown>;
167
+ }>;
168
+ actions: import("@json-render/core").SchemaType<"map", {
169
+ params: import("@json-render/core").SchemaType<"zod", unknown>;
170
+ description: import("@json-render/core").SchemaType<"string", unknown>;
171
+ }>;
172
+ }>;
173
+ }, {
174
+ components: {
175
+ Stack: {
176
+ props: z.ZodObject<{}, z.core.$strip>;
177
+ slots: string[];
178
+ description: string;
179
+ };
180
+ RentalCard: {
181
+ props: z.ZodObject<{
182
+ rentalId: z.ZodString;
183
+ stayId: z.ZodNullable<z.ZodString>;
184
+ }, z.core.$strip>;
185
+ description: string;
186
+ };
187
+ RentalCarousel: {
188
+ props: z.ZodObject<{
189
+ items: z.ZodArray<z.ZodObject<{
190
+ rentalId: z.ZodString;
191
+ stayId: z.ZodNullable<z.ZodString>;
192
+ }, z.core.$strip>>;
193
+ }, z.core.$strip>;
194
+ description: string;
195
+ };
196
+ StayQuote: {
197
+ props: z.ZodObject<{
198
+ stayId: z.ZodString;
199
+ }, z.core.$strip>;
200
+ description: string;
201
+ };
202
+ PriceBreakdown: {
203
+ props: z.ZodObject<{
204
+ stayId: z.ZodString;
205
+ }, z.core.$strip>;
206
+ description: string;
207
+ };
208
+ AlternativeStays: {
209
+ props: z.ZodObject<{
210
+ rentalId: z.ZodString;
211
+ stayIds: z.ZodArray<z.ZodString>;
212
+ }, z.core.$strip>;
213
+ description: string;
214
+ };
215
+ AvailabilityCalendar: {
216
+ props: z.ZodObject<{
217
+ rentalId: z.ZodString;
218
+ stayId: z.ZodNullable<z.ZodString>;
219
+ }, z.core.$strip>;
220
+ description: string;
221
+ };
222
+ PriceCalendar: {
223
+ props: z.ZodObject<{
224
+ rentalId: z.ZodString;
225
+ }, z.core.$strip>;
226
+ description: string;
227
+ };
228
+ ReviewSummary: {
229
+ props: z.ZodObject<{
230
+ rentalId: z.ZodString;
231
+ }, z.core.$strip>;
232
+ description: string;
233
+ };
234
+ RentalFacts: {
235
+ props: z.ZodObject<{
236
+ rentalId: z.ZodString;
237
+ groups: z.ZodArray<z.ZodString>;
238
+ }, z.core.$strip>;
239
+ description: string;
240
+ };
241
+ RentalMap: {
242
+ props: z.ZodObject<{
243
+ rentalId: z.ZodString;
244
+ }, z.core.$strip>;
245
+ description: string;
246
+ };
247
+ Compare: {
248
+ props: z.ZodObject<{
249
+ items: z.ZodArray<z.ZodObject<{
250
+ rentalId: z.ZodString;
251
+ stayId: z.ZodNullable<z.ZodString>;
252
+ }, z.core.$strip>>;
253
+ }, z.core.$strip>;
254
+ description: string;
255
+ };
256
+ StayLink: {
257
+ props: z.ZodObject<{
258
+ rentalId: z.ZodString;
259
+ stayId: z.ZodNullable<z.ZodString>;
260
+ }, z.core.$strip>;
261
+ description: string;
262
+ };
263
+ ContactLink: {
264
+ props: z.ZodObject<{}, z.core.$strip>;
265
+ description: string;
266
+ };
267
+ QuickReplies: {
268
+ props: z.ZodObject<{
269
+ options: z.ZodArray<z.ZodString>;
270
+ }, z.core.$strip>;
271
+ description: string;
272
+ };
273
+ };
274
+ actions: {};
275
+ }>;
276
+ export type ChatComponent = keyof typeof chatCatalog.data.components;
277
+ /** The components the model may place; `Stack` is the service's. */
278
+ export declare const PLACEABLE_COMPONENTS: readonly ["RentalCard", "RentalCarousel", "StayQuote", "PriceBreakdown", "AlternativeStays", "AvailabilityCalendar", "PriceCalendar", "ReviewSummary", "RentalFacts", "RentalMap", "Compare", "StayLink", "ContactLink", "QuickReplies"];
279
+ export type PlaceableComponent = (typeof PLACEABLE_COMPONENTS)[number];
280
+ /** The package version each component was added in. A minor adds components (and optional props, which an
281
+ * older renderer ignores); the service offers a widget only what its version has. */
282
+ export declare const COMPONENT_SINCE: Readonly<Record<ChatComponent, string>>;
283
+ /** One component the model asked to show, as the service's `show` tool takes it. */
284
+ export interface ChatItem {
285
+ readonly type: PlaceableComponent;
286
+ readonly props: Readonly<Record<string, unknown>>;
287
+ }
288
+ /** The placeable components a widget of `clientVersion` renders: same major, added at or before it.
289
+ * An unreadable version gets none, so an unknown widget is never sent what it cannot draw. */
290
+ type ComponentsFor = (clientVersion: string) => PlaceableComponent[];
291
+ /** An item's props checked against its component (json-render checks props only for one-component
292
+ * catalogs). `null` when the type is not allowed or the props do not fit. */
293
+ type ParseItem = (item: unknown, allowed: readonly PlaceableComponent[]) => ChatItem | null;
294
+ /** The spec of one reply: the items stacked under the service's root, and the state they read. */
295
+ type ChatSpec = (items: readonly ChatItem[], state: ChatState) => Spec;
296
+ /** See {@link ComponentsFor}. */
297
+ export declare const componentsFor: ComponentsFor;
298
+ /** See {@link ParseItem}. */
299
+ export declare const parseItem: ParseItem;
300
+ /** See {@link ChatSpec}. */
301
+ export declare const chatSpec: ChatSpec;
302
+ //#endregion
303
+ export { CHAT_LOCALES, CHAT_PATH, type ChatAvailability, type ChatCalendar, type ChatDayStatus, type ChatEvent, type ChatFactGroup, type ChatImage, type ChatLocale, type ChatPriceCalendar, type ChatRental, type ChatRequest, type ChatReviews, type ChatState, type ChatStay, type ChatUnavailableReason, MAX_MESSAGE_CHARS, SESSION_TTL_S };
@@ -0,0 +1,3 @@
1
+ import { i as SESSION_TTL_S, n as CHAT_PATH, r as MAX_MESSAGE_CHARS, t as CHAT_LOCALES } from "./protocol-BuNqZAMt.js";
2
+ import { a as componentsFor, c as statePath, i as chatSpec, n as PLACEABLE_COMPONENTS, o as parseItem, r as chatCatalog, s as stateKey, t as COMPONENT_SINCE } from "./catalog-RXKmEmMW.js";
3
+ export { CHAT_LOCALES, CHAT_PATH, COMPONENT_SINCE, MAX_MESSAGE_CHARS, PLACEABLE_COMPONENTS, SESSION_TTL_S, chatCatalog, chatSpec, componentsFor, parseItem, stateKey, statePath };