@v-office/website-chat 0.0.0-stage → 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 +54 -2
- package/dist/catalog-RXKmEmMW.js +183 -0
- package/dist/catalog.d.ts +303 -0
- package/dist/catalog.js +3 -0
- package/dist/icons-B5PAY3aU.js +145 -0
- package/dist/index.d.ts +111 -0
- package/dist/index.js +577 -0
- package/dist/panel-D8pKi4RZ.js +1159 -0
- package/dist/protocol-Bmb_uxVQ.d.ts +46 -0
- package/dist/protocol-BuNqZAMt.js +12 -0
- package/instructions/CHANGELOG.md +7 -0
- package/instructions/MIGRATION.md +7 -0
- package/instructions/versions/1.0.0/CHANGELOG.md +37 -0
- package/instructions/versions/1.0.0/MIGRATION.md +51 -0
- package/package.json +65 -3
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Spec } from "@json-render/core";
|
|
2
|
+
//#region src/protocol.d.ts
|
|
3
|
+
/** The languages the chat speaks; the widget's `locale` picks one. */
|
|
4
|
+
declare const CHAT_LOCALES: readonly ["de", "en"];
|
|
5
|
+
type ChatLocale = (typeof CHAT_LOCALES)[number];
|
|
6
|
+
/** The path both requests go to, below the service's endpoint. */
|
|
7
|
+
declare const CHAT_PATH = "/v1/chat";
|
|
8
|
+
/** Longest visitor message the service takes. */
|
|
9
|
+
declare const MAX_MESSAGE_CHARS = 2000;
|
|
10
|
+
/** How long the service keeps a conversation after its last message. The widget forgets its own copy
|
|
11
|
+
* after the same time, so it never shows a conversation the service no longer knows. */
|
|
12
|
+
declare const SESSION_TTL_S: number;
|
|
13
|
+
/** `GET <endpoint>/v1/chat`. */
|
|
14
|
+
interface ChatAvailability {
|
|
15
|
+
readonly available: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** `POST <endpoint>/v1/chat`. */
|
|
18
|
+
interface ChatRequest {
|
|
19
|
+
/** The session the service answered with; `null` for the first message. */
|
|
20
|
+
readonly sessionId: string | null;
|
|
21
|
+
readonly message: string;
|
|
22
|
+
readonly locale: ChatLocale;
|
|
23
|
+
/** The widget's package version: the service offers only components it can render. */
|
|
24
|
+
readonly clientVersion: string;
|
|
25
|
+
}
|
|
26
|
+
/** Why the chat cannot answer: switched off, its budget spent, a reply still running, too many
|
|
27
|
+
* messages, or anything else. The widget shows its fallback (search and contact links). */
|
|
28
|
+
type ChatUnavailableReason = "off" | "budget" | "busy" | "limit" | "error";
|
|
29
|
+
/** One server-sent event (`event: <type>`, `data: <json>`), in order. */
|
|
30
|
+
type ChatEvent = {
|
|
31
|
+
readonly type: "session";
|
|
32
|
+
readonly sessionId: string;
|
|
33
|
+
} | {
|
|
34
|
+
readonly type: "text";
|
|
35
|
+
readonly delta: string;
|
|
36
|
+
} | {
|
|
37
|
+
readonly type: "ui";
|
|
38
|
+
readonly spec: Spec;
|
|
39
|
+
} | {
|
|
40
|
+
readonly type: "done";
|
|
41
|
+
} | {
|
|
42
|
+
readonly type: "unavailable";
|
|
43
|
+
readonly reason: ChatUnavailableReason;
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { ChatLocale as a, MAX_MESSAGE_CHARS as c, ChatEvent as i, SESSION_TTL_S as l, CHAT_PATH as n, ChatRequest as o, ChatAvailability as r, ChatUnavailableReason as s, CHAT_LOCALES as t };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/protocol.ts
|
|
2
|
+
/** The languages the chat speaks; the widget's `locale` picks one. */
|
|
3
|
+
const CHAT_LOCALES = ["de", "en"];
|
|
4
|
+
/** The path both requests go to, below the service's endpoint. */
|
|
5
|
+
const CHAT_PATH = "/v1/chat";
|
|
6
|
+
/** Longest visitor message the service takes. */
|
|
7
|
+
const MAX_MESSAGE_CHARS = 2e3;
|
|
8
|
+
/** How long the service keeps a conversation after its last message. The widget forgets its own copy
|
|
9
|
+
* after the same time, so it never shows a conversation the service no longer knows. */
|
|
10
|
+
const SESSION_TTL_S = 7200;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { SESSION_TTL_S as i, CHAT_PATH as n, MAX_MESSAGE_CHARS as r, CHAT_LOCALES as t };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Changelog: 1.0.0
|
|
2
|
+
|
|
3
|
+
The first release: the AI chat of a v-office website. A visitor asks for a stay; the chat searches the
|
|
4
|
+
agency's rentals, shows them as cards with the PMS's prices, and links each stay to its rental page with
|
|
5
|
+
the dates and party filled in, where the site's own Quote and checkout take over. The chat never books
|
|
6
|
+
and has no form of its own.
|
|
7
|
+
|
|
8
|
+
## Added
|
|
9
|
+
|
|
10
|
+
- `WebsiteChat`, rendered in a Shadow DOM so the site's CSS and the chat's cannot affect each other. It
|
|
11
|
+
asks the chat service whether the website's chat is on and renders nothing otherwise.
|
|
12
|
+
- An entry pill in the corner of every page, frosted glass with a ring running round it until the
|
|
13
|
+
visitor has asked something. On a phone it is one tap; on a wide screen the visitor types into it.
|
|
14
|
+
Once a conversation exists it offers to continue it.
|
|
15
|
+
- The panel loads on the first open: a card at the screen's edge over the dimmed page, a sheet from
|
|
16
|
+
the bottom on a phone. Start suggestions, a waiting indicator, results side by side where there is
|
|
17
|
+
room, a button for a new conversation.
|
|
18
|
+
- The conversation follows the visitor from page to page within the tab, for as long as the chat
|
|
19
|
+
service keeps it (two hours after the last message), so a link from the chat to a rental page
|
|
20
|
+
does not lose it.
|
|
21
|
+
- A start step: nothing is sent to the AI provider before the visitor reads what the chat does and
|
|
22
|
+
presses "Start chat". A message typed into the entry pill waits there until then.
|
|
23
|
+
- Looks: three template themes (`classic`, `soft`, `minimal`), the site's `primary` and `secondary`
|
|
24
|
+
colours, the pill and panel on the `right` or `left`, the site's font, and `--chat-top` /
|
|
25
|
+
`--chat-width` for a sticky header and a wider panel.
|
|
26
|
+
- Copy in German and English (`DEFAULT_COPY`), each string overridable through `copy`.
|
|
27
|
+
- `./catalog`: the components the chat service places and the wire protocol. Sites do not import it.
|
|
28
|
+
- Rentals: `RentalCard` (photo gallery, rating, facts, the visitor's wishes the search that found it applied),
|
|
29
|
+
`RentalCarousel` (several cards side by side, swipeable), `Compare` (two or three rentals column
|
|
30
|
+
by column), `ReviewSummary` (the PMS's rating, grade, category ratings and a few review texts),
|
|
31
|
+
`RentalFacts` (a rental's facts in the PMS's groups), `RentalMap` (where it is; the map loads
|
|
32
|
+
from OpenFreeMap only when the visitor taps it).
|
|
33
|
+
- Stays: `StayQuote`, `PriceBreakdown` (the quote's lines and total), `AlternativeStays` (other
|
|
34
|
+
free periods as tappable choices), `AvailabilityCalendar` (free and taken days by month),
|
|
35
|
+
`PriceCalendar` (the total at the arrivals around the asked one, cheapest marked).
|
|
36
|
+
- Actions: `StayLink`, `ContactLink`, `QuickReplies` (short answers a visitor taps to send).
|
|
37
|
+
Every figure in them comes from the PMS; the AI places them by id only.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Migration: 1.0.0
|
|
2
|
+
|
|
3
|
+
A new package: nothing to migrate. To add the chat to a site:
|
|
4
|
+
|
|
5
|
+
## 1. Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pnpm add --save-exact @v-office/website-chat@1.0.0
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Its peers are React `^19.2.3` and `@v-office/website-headless` 1.1 or later, which a site with the
|
|
12
|
+
platform components has.
|
|
13
|
+
|
|
14
|
+
## 2. Render it once, in the layout
|
|
15
|
+
|
|
16
|
+
```astro
|
|
17
|
+
---
|
|
18
|
+
import { WebsiteChat } from "@v-office/website-chat";
|
|
19
|
+
---
|
|
20
|
+
<WebsiteChat
|
|
21
|
+
client:idle
|
|
22
|
+
endpoint={import.meta.env.PUBLIC_CHAT_ENDPOINT}
|
|
23
|
+
locale="de"
|
|
24
|
+
searchPath="/suche"
|
|
25
|
+
contactPath="/kontakt"
|
|
26
|
+
/>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- `endpoint` is the AI Studio chat service of the site's environment. AI Studio's builds set
|
|
30
|
+
`PUBLIC_CHAT_ENDPOINT` to it: pass it as shown and keep no value in the site's `.env`. Without it
|
|
31
|
+
(a build outside AI Studio) the widget renders nothing.
|
|
32
|
+
- `searchPath` and `contactPath` are the site's own routes: the chat links a rental without a page to the
|
|
33
|
+
search, and sends a visitor who wants to write to the contact page.
|
|
34
|
+
- Optional: `theme` (`"classic"`, `"soft"`, `"minimal"`), `colors={{ primary, secondary }}`,
|
|
35
|
+
`position` (`"right"` or `"left"`), `copy` (overrides of single fields of `DEFAULT_COPY`: a string, or the `suggestions` list).
|
|
36
|
+
- A site with a sticky header sets its height as `--chat-top` on an element around the widget (for
|
|
37
|
+
example `:root { --chat-top: 72px; }`), so the panel and the dimmed page start below the header.
|
|
38
|
+
- With Astro's `<ClientRouter />`, add `transition:persist="website-chat"` so a reply still being
|
|
39
|
+
written keeps going across page transitions. The panel closes on a page change either way, as on a
|
|
40
|
+
full page load, and the next page offers to continue the conversation.
|
|
41
|
+
|
|
42
|
+
## 3. Consent
|
|
43
|
+
|
|
44
|
+
The chat sends what a visitor types to an AI provider, so nothing is sent before the visitor reads
|
|
45
|
+
what that means and presses the chat's own "Start chat" button. The chat does not read the site's
|
|
46
|
+
consent manager; nothing to configure there.
|
|
47
|
+
|
|
48
|
+
## 4. Switch it on
|
|
49
|
+
|
|
50
|
+
The chat stays hidden until an agent switches it on for the website in AI Studio (website settings,
|
|
51
|
+
"Website chat"). Switching it off hides it again without a rebuild.
|
package/package.json
CHANGED
|
@@ -1,6 +1,68 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@v-office/website-chat",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "The AI chat of v-office websites: a launcher and a lazily loaded chat panel in a Shadow DOM, talking to the AI Studio chat service, and the json-render catalog (./catalog) the service places its rental cards, stays and links from. Styled through CSS custom properties and curated template themes; consumers need no Tailwind",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/vofficeGmbh/ai-studio.git",
|
|
9
|
+
"directory": "packages/website-chat"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"instructions"
|
|
15
|
+
],
|
|
16
|
+
"type": "module",
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": "./dist/index.js",
|
|
21
|
+
"./catalog": "./dist/catalog.js",
|
|
22
|
+
"./package.json": "./package.json"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@json-render/core": "0.21.0",
|
|
29
|
+
"@json-render/react": "0.21.0",
|
|
30
|
+
"maplibre-gl": "^5.24.0",
|
|
31
|
+
"zod": "^4.3.6"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "26.5.1",
|
|
35
|
+
"@types/react": "19.3.0",
|
|
36
|
+
"@types/react-dom": "19.3.0",
|
|
37
|
+
"@v-office/website-headless": "1.1.1",
|
|
38
|
+
"@v-office/website-sdk": "2.34.0",
|
|
39
|
+
"jsdom": "30.0.1",
|
|
40
|
+
"oxfmt": "0.67.0",
|
|
41
|
+
"oxlint": "1.82.0",
|
|
42
|
+
"oxlint-plugin-react-doctor": "0.9.14",
|
|
43
|
+
"react": "19.3.0",
|
|
44
|
+
"react-dom": "19.3.0",
|
|
45
|
+
"tsdown": "0.23.0",
|
|
46
|
+
"typescript": "7.0.2",
|
|
47
|
+
"vitest": "5.0.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@v-office/website-headless": ">=1.1.0 <2",
|
|
51
|
+
"react": "^19.2.3",
|
|
52
|
+
"react-dom": "^19.2.3"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": "^22.0.0 || ^24.0.0 || ^25.0.0 || >=26.0.0"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsdown",
|
|
59
|
+
"dev": "tsdown --watch",
|
|
60
|
+
"typecheck": "tsc --noEmit",
|
|
61
|
+
"lint": "oxlint .",
|
|
62
|
+
"lint:fix": "oxlint --fix .",
|
|
63
|
+
"fmt": "oxfmt",
|
|
64
|
+
"fmt:check": "oxfmt --check",
|
|
65
|
+
"check": "pnpm run typecheck && pnpm run lint && pnpm run fmt:check",
|
|
66
|
+
"test": "vitest run && node --test test/dist.node.mjs"
|
|
67
|
+
}
|
|
6
68
|
}
|