@aiden-voice/widget 0.7.3 → 0.9.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
@@ -72,6 +72,40 @@ init({
72
72
  short-lived JWT to the page some other way. The widget itself never
73
73
  holds, requests, or sees a secret key under any circumstance.
74
74
 
75
+ Session tokens are short-lived (30 minutes), and a visitor can keep a page
76
+ open much longer before using the chat. The widget renews its session when
77
+ needed: before a request, if the token has run out or will within a minute,
78
+ and once after a `401`, retrying the request once. Conversations continue
79
+ across renewals.
80
+
81
+ - With `publishableKey` it mints a new session itself; nothing to do. Each
82
+ renewal counts toward the key's daily session quota, but only when someone
83
+ uses the chat after the token ran out (there is no background timer).
84
+ - With `sessionToken` it can't mint (that needs your secret key), so pass
85
+ `getSessionToken`: a function that fetches a fresh token from your backend
86
+ the same way you got the first. It is only called when a new token is
87
+ needed, and may return the token or a promise of it:
88
+
89
+ ```js
90
+ window.whooAidenWidget.init({
91
+ sessionToken: initialToken,
92
+ getSessionToken: async () => {
93
+ const response = await fetch('/api/aiden-session', { method: 'POST' })
94
+ return (await response.json()).token
95
+ },
96
+ })
97
+ ```
98
+
99
+ Without it, or when it returns an empty or already expired token, the
100
+ visitor sees "This chat session has expired. Reload the page to continue."
101
+ When it throws or takes longer than 15 seconds, the failure may pass, so the
102
+ visitor sees "Something went wrong, please try again." and can send again,
103
+ which asks `getSessionToken` once more. Either way their message is put back
104
+ in the message box. A page served with an already
105
+ expired `sessionToken` also tries `getSessionToken` before giving up, and
106
+ shows no chat button until it answers (at most 15 seconds: a renewal that
107
+ takes longer counts as failed).
108
+
75
109
  Branding (`color`, `inkColor`, `accentColor`, `name`) follows one rule in
76
110
  both modes: **a value you pass to `init()` always wins**, anything you leave
77
111
  out is filled in from the agent's settings in whoo-aiden, and anything still
@@ -97,6 +131,10 @@ throws synchronously, at call time, if you pass both or neither.
97
131
  | --- | --- | --- |
98
132
  | `publishableKey` | Public key used to mint a session server-side. Mutually exclusive with `sessionToken`. | none (required unless `sessionToken` is set) |
99
133
  | `sessionToken` | A pre-minted session JWT from your own backend. Mutually exclusive with `publishableKey`. | none (required unless `publishableKey` is set) |
134
+ | `getSessionToken` | `sessionToken` mode only: a function returning a fresh session token (or a promise of one) from your backend, called when the current one has run out or is refused. Without it an expired session ends the chat until the page is reloaded. Ignored, with a warning, with `publishableKey` or when not a function. | none |
135
+ | `language` | Language of the widget's own text, as a BCP 47 tag (`'fr'`, `'pt-BR'`, `'zh-CN'`). Without it the widget follows the page's `<html lang>`, then English. See [Language](#language). | the page's language, else `'en'` |
136
+ | `messages` | Replaces individual built-in strings in the active language, e.g. `{ newConversation: 'Start over' }`. See [Language](#language). | none |
137
+ | `contentLanguage` | The language of the conversation's content (replies, the visitor's messages, and your `greeting`, `title`, `name` and image text), as a BCP 47 tag, so screen readers read it with the right voice. Separate from `language`, which only sets the widget's own text; `language` counts only for a page with no `<html lang>`. See [Language](#language). | the page's `<html lang>`, else `language`, else unknown |
100
138
  | `position` | Launcher/panel corner: `'bottom-right'` or `'bottom-left'`. | `'bottom-right'` |
101
139
  | `color` | Primary accent color (any valid CSS color). Overrides the color configured in whoo-aiden; omit it to use that one. | whoo-aiden's, else `'#4f46e5'` |
102
140
  | `inkColor` | Body text color (chat title and replies). Darkened automatically if needed to stay readable. Overrides the color configured in whoo-aiden; omit it to use that one. | whoo-aiden's, else `'#111111'` |
@@ -110,12 +148,66 @@ throws synchronously, at call time, if you pass both or neither.
110
148
  | `emptyStateImageUrl` | Image (e.g. a brand lockup) shown above the greeting while the conversation is empty. `https:` or `data:image/` only. Removed if it fails to load. | none |
111
149
  | `emptyStateImageAlt` | Alt text for `emptyStateImageUrl`. Set it when the image carries meaning (e.g. your brand name); omit it for a purely decorative image. | none (decorative) |
112
150
  | `showFeedback` | Show thumbs up/down controls under each reply so visitors can rate answers (a thumbs-down opens an optional correction form). | `false` (hidden) |
113
- | `zIndex` | Stacking level of the launcher and panel over your page. The default sits above carousels, sticky headers and most overlays, while leaving room above it for a cookie or consent modal. Lower it if one of your own layers should cover the chat (see the accessibility note below). An invalid value logs a warning and uses the default. | `2147483000` |
151
+ | `zIndex` | Stacking level of the launcher and panel over your page. The default sits above carousels, sticky headers and most overlays, while leaving room above it for a cookie or consent modal. Lower it if one of your own layers should cover the chat (see the accessibility note below). While the panel fills the screen (a viewport 400px wide or less, or 420px tall or less), it is a modal dialog in the browser's top layer: it sits above your page's layers whatever `zIndex` says, and the rest of the page, including page-level accessibility toolbars, can't be reached until it closes. A modal dialog your own page opens afterwards sits above it. An invalid value logs a warning and uses the default. | `2147483000` |
114
152
  | `apiBaseUrl` | Override the whoo-aiden API host the widget talks to. | `'https://api.aidenvoice.com'` |
115
153
 
116
154
  ### When something else already owns the corner
117
155
 
118
- Some third-party overlays (accessibility toolbars, chat or cookie widgets) sit at the maximum possible z-index, `2147483647`, in the same corner. No `zIndex` value can beat that: at an equal level, whichever element comes later in the page wins, and those overlays are usually injected after the widget. Move the widget to the other corner with `position: 'bottom-left'` instead.
156
+ Some third-party overlays (accessibility toolbars, chat or cookie widgets) sit at the maximum possible z-index, `2147483647`, in the same corner. No `zIndex` value can beat that: at an equal level, whichever element comes later in the page wins, and those overlays are usually injected after the widget. Move the widget to the other corner with `position: 'bottom-left'` instead. (None of this applies while the panel fills the screen; see `zIndex`.)
157
+
158
+ ## Language
159
+
160
+ The widget's own text (buttons, labels, status and error messages, and what screen readers announce) comes in eleven languages: English (`en`), French (`fr`), Spanish (`es`), Portuguese (`pt`), German (`de`), Italian (`it`), Japanese (`ja`), Simplified Chinese (`zh`), Russian (`ru`), Hindi (`hi`) and Arabic (`ar`).
161
+
162
+ - **How the language is chosen:** the `language` option if you pass one, then your page's `<html lang>`, then English. So a French page gets a French widget without any setup. An unsupported `language` value is ignored with a console warning; an unsupported page language falls back to English silently.
163
+ - **Regional tags** match their language: `fr-CA` is French, any `pt-*` gets Brazilian Portuguese, any `es-*` gets Latin American Spanish. Simplified Chinese matches `zh`, `zh-CN`, `zh-SG` and `zh-Hans`. Traditional Chinese (`zh-TW`, `zh-HK`, `zh-Hant`) is not supported and falls back to English.
164
+ - **Decided once, at `init()`.** If your single-page app changes `<html lang>` later, pass `language` (unmount and `init()` again to switch).
165
+ - **Arabic is right to left:** the panel's layout mirrors (the visitor's messages on the left). The corner set by `position` doesn't change.
166
+ - **Not translated:** the agent's replies (the model answers in whatever language it does), and `greeting`, `title` and `name`, which you write in the language you want. These are marked with the **content language**, not the widget's: `contentLanguage` if you pass it, else your page's `<html lang>` (any language, not just the eleven), else `language` if the page has no `lang`, else unknown. So on a Dutch page the widget's buttons are English, while replies and your Dutch greeting are read with a Dutch voice.
167
+ - **Direction:** each paragraph and list item of a message takes its direction from its own first letter, so an English reply in an Arabic widget, or the reverse, still reads correctly. A paragraph that starts with a Latin name ("Aiden …") in Arabic text is laid out left to right, as the bidi standard decides.
168
+ - **The widget marks its own language** (`lang` and `dir` on its root, naming the variant it ships: `pt-BR`, `es-419`, `zh-Hans`), so screen readers pronounce it correctly even on a page in another language.
169
+ - **Upgrading from a version before 0.8.0:** a page whose `<html lang>` is one of these languages now gets the widget in that language, where it was English before. Pass `language: 'en'` to keep it in English; replies and your own text keep your page's language for screen readers either way.
170
+
171
+ **Changing the wording.** `messages` replaces any built-in string in the active language. Write overrides in that language, or set `language` to the language of your overrides. `chatWith` takes `{name}`, the agent's name. Unknown keys, and values that aren't non-blank strings (invisible characters such as a zero-width space count as blank), are ignored with a console warning. Overrides are marked with the widget's language: an override in another language (an English brand phrase in a French widget) is read with the widget's voice.
172
+
173
+ ```js
174
+ window.whooAidenWidget.init({
175
+ publishableKey: 'pk_live_…',
176
+ language: 'es',
177
+ messages: { newConversation: 'Empezar de nuevo' },
178
+ })
179
+ ```
180
+
181
+ | Key | English | Where |
182
+ |---|---|---|
183
+ | `openChat` | Open chat | launcher name, closed |
184
+ | `closeChat` | Close chat | launcher name while open, header ✕ |
185
+ | `chatWith` | Chat with {name} | panel title and dialog name (unless `title` is set) |
186
+ | `newConversation` | New conversation | header button |
187
+ | `conversation` | Conversation | message list region name |
188
+ | `you` | You | screen-reader speaker label on the visitor's messages |
189
+ | `message` | Message | message box label |
190
+ | `send` | Send | composer button |
191
+ | `lookingItUp` | Looking that up for you… | slow-reply notice |
192
+ | `goodResponse` | Good response | thumbs-up name |
193
+ | `badResponse` | Bad response | thumbs-down name |
194
+ | `additionalFeedback` | Additional feedback | feedback text field label |
195
+ | `feedbackPlaceholder` | What was wrong? (optional) | feedback text field placeholder |
196
+ | `feedbackCategory` | Feedback category | feedback select label |
197
+ | `selectReason` | Select a reason (optional) | feedback select first option |
198
+ | `categoryFactual` | Factual error | feedback option |
199
+ | `categoryIncomplete` | Incomplete | feedback option |
200
+ | `categoryTone` | Off tone | feedback option |
201
+ | `categoryOther` | Other | feedback option |
202
+ | `submit` | Submit | feedback form button |
203
+ | `cancel` | Cancel | feedback form button |
204
+ | `feedbackThanks` | Thanks for the feedback | feedback status |
205
+ | `feedbackFailed` | Couldn't send feedback | feedback status |
206
+ | `conversationCleared` | Conversation cleared | screen-reader announcement |
207
+ | `genericError` | Something went wrong, please try again. | error alert |
208
+ | `sessionExpired` | This chat session has expired. Reload the page to continue. | error alert |
209
+
210
+ **About the translations:** they were machine-drafted and cross-checked by independent AI agents (back-translation, critique, and rendering checks), not reviewed by native speakers. [docs/translation-verification.md](docs/translation-verification.md) records every check. If any wording reads wrong, override it with `messages`, and please tell us.
119
211
 
120
212
  ## Theming
121
213
 
@@ -441,9 +533,10 @@ responsibility:
441
533
  accent for links in replies) get the same treatment: each is darkened
442
534
  just enough to stay readable on the reply bubble. See
443
535
  `docs/accessibility-report.md` for details.
444
- - **Page language:** the widget renders inside your page's DOM and
445
- inherits language from your document's `<html lang>` attribute; there is
446
- no separate widget-level locale override.
536
+ - **Page language:** set `<html lang>` correctly. The widget follows it (or
537
+ your `language` option, which wins) and marks its own `lang` and `dir`, so
538
+ screen readers pronounce it correctly even when it differs from your page.
539
+ See [Language](#language).
447
540
  - **Don't hide the mount point:** don't place the widget's container (or
448
541
  move it, via your own script) inside an element with `aria-hidden="true"`
449
542
  or `inert` — that hides it from assistive technology regardless of the
@@ -473,19 +566,32 @@ The widget distinguishes two deliberately different error tiers:
473
566
  broken-looking ever appears on the page.
474
567
  - **Failures once the widget is already visible and in an active chat**
475
568
  (a network error, an SSE connection dropping mid-stream, an error
476
- response from the server, a session that runs out while the page is open)
477
- show a short, non-technical inline message in the chat panel itself (e.g.
478
- "Something went wrong, please try again"), leaving any partial response
479
- already rendered in place above it.
569
+ response from the server) show a short, non-technical inline message in the
570
+ chat panel itself (e.g. "Something went wrong, please try again"), leaving
571
+ any partial response already rendered in place above it. A session that
572
+ runs out while the page is open is renewed (see Usage); when the session is
573
+ refused the panel says "This chat session has expired. Reload the page to
574
+ continue." instead. When renewing fails for a reason that may pass (offline,
575
+ the key's daily limit, `getSessionToken` throwing or taking over 15
576
+ seconds), it says "Something went wrong, please try again", because a reload
577
+ wouldn't help. Either way the visitor's message goes back into the message
578
+ box, and leaves the transcript (so a retry doesn't show it twice). Closing
579
+ the panel cancels a pending reply silently; the message is handed back only
580
+ if it never reached the server (the widget was still renewing the session).
581
+ A session refused after the widget is already showing (the start-up check
582
+ outlived its 3-second wait) no longer removes it: the panel says the session
583
+ expired instead.
480
584
 
481
585
  How a bad `sessionToken` is caught at start-up, without the widget ever
482
586
  holding a key to check its signature:
483
587
 
484
- - If the token is a JWT whose `exp` has already passed, `init()` treats it as
485
- an init failure straight away, with no network request. A token the widget
588
+ - If the token is a JWT whose `exp` has already passed, `init()` asks
589
+ `getSessionToken` for a new one when you passed it, and otherwise treats it
590
+ as an init failure straight away, with no network request. A token the widget
486
591
  can't read (not a JWT, no `exp`) is never rejected locally.
487
592
  - Otherwise, when the widget looks up the agent's branding with the token
488
- (see above), a `401` or `403` answer is an init failure too. That lookup is
593
+ (see above), a `403` answer is an init failure too, and so is a `401` unless
594
+ `getSessionToken` supplies a token the server accepts. That lookup is
489
595
  skipped when you pass every branding value yourself, so in that case only the
490
596
  expiry check applies and a token the server would refuse for another reason
491
597
  fails on the visitor's first message instead.
@@ -1,8 +1,12 @@
1
1
  import { RefObject } from 'preact';
2
- export declare function Composer({ value, onChange, onSend, disabled, inputRef, }: {
2
+ import { WidgetMessages } from '../i18n/messages';
3
+ export declare function isComposing(event: KeyboardEvent): boolean;
4
+ export declare function Composer({ value, onChange, onSend, disabled, inputRef, text, contentLanguage, }: {
3
5
  value: string;
4
6
  onChange: (value: string) => void;
5
7
  onSend: () => void;
6
8
  disabled: boolean;
7
9
  inputRef?: RefObject<HTMLInputElement | null>;
10
+ text?: WidgetMessages;
11
+ contentLanguage?: string;
8
12
  }): import('preact').JSX.Element;
@@ -1,6 +1,7 @@
1
1
  import { RefObject } from 'preact';
2
+ import { WidgetMessages } from '../i18n/messages';
2
3
  import { LauncherIcon, LauncherOpenIcon } from '../types';
3
- export declare function Launcher({ isOpen, onClick, iconUrl, icon, openIconUrl, openIcon, buttonRef, }: {
4
+ export declare function Launcher({ isOpen, onClick, iconUrl, icon, openIconUrl, openIcon, buttonRef, text, }: {
4
5
  isOpen: boolean;
5
6
  onClick: () => void;
6
7
  iconUrl?: string;
@@ -8,4 +9,5 @@ export declare function Launcher({ isOpen, onClick, iconUrl, icon, openIconUrl,
8
9
  openIconUrl?: string;
9
10
  openIcon?: LauncherOpenIcon;
10
11
  buttonRef?: RefObject<HTMLButtonElement | null>;
12
+ text?: WidgetMessages;
11
13
  }): import('preact').JSX.Element;
@@ -1,6 +1,7 @@
1
1
  import { RefObject } from 'preact';
2
2
  import { FeedbackCategory, MessageFeedbackState } from '../controller';
3
- export declare function MessageFeedback({ state, containerRef, onThumbsUp, onThumbsDown, onDraftChange, onSubmitDetailed, onCancel, }: {
3
+ import { WidgetMessages } from '../i18n/messages';
4
+ export declare function MessageFeedback({ state, containerRef, onThumbsUp, onThumbsDown, onDraftChange, onSubmitDetailed, onCancel, text, contentLanguage, }: {
4
5
  state: MessageFeedbackState;
5
6
  containerRef?: RefObject<HTMLElement>;
6
7
  onThumbsUp: () => void;
@@ -8,4 +9,6 @@ export declare function MessageFeedback({ state, containerRef, onThumbsUp, onThu
8
9
  onDraftChange: (correction: string, category: '' | FeedbackCategory) => void;
9
10
  onSubmitDetailed: (correction: string, category: '' | FeedbackCategory) => void;
10
11
  onCancel: () => void;
12
+ text?: WidgetMessages;
13
+ contentLanguage?: string;
11
14
  }): import('preact').JSX.Element;
@@ -1,7 +1,8 @@
1
1
  import { FeedbackCategory, Message, MessageFeedbackState } from '../controller';
2
+ import { WidgetMessages } from '../i18n/messages';
2
3
  type DraftChangeHandler = (messageId: string, correction: string, category: '' | FeedbackCategory) => void;
3
4
  type SubmitHandler = (messageId: string, correction: string, category: '' | FeedbackCategory) => void;
4
- export declare function MessageList({ messages, messageFeedback, announcement, emptyStateImage, agentName, showFeedback, isStreaming, isSlowResponse, onThumbsUp, onThumbsDown, onDraftChange, onSubmitDetailed, onCancelFeedback, }: {
5
+ export declare function MessageList({ messages, messageFeedback, announcement, emptyStateImage, agentName, showFeedback, isStreaming, isSlowResponse, onThumbsUp, onThumbsDown, onDraftChange, onSubmitDetailed, onCancelFeedback, text, contentLanguage, languageTag, announcementIsContent, }: {
5
6
  messages: Message[];
6
7
  messageFeedback: Record<string, MessageFeedbackState>;
7
8
  announcement: string | null;
@@ -18,5 +19,9 @@ export declare function MessageList({ messages, messageFeedback, announcement, e
18
19
  onDraftChange?: DraftChangeHandler;
19
20
  onSubmitDetailed: SubmitHandler;
20
21
  onCancelFeedback: (messageId: string) => void;
22
+ text?: WidgetMessages;
23
+ contentLanguage?: string;
24
+ languageTag?: string;
25
+ announcementIsContent?: boolean;
21
26
  }): import('preact').JSX.Element;
22
27
  export {};
package/dist/config.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { WidgetMessages } from './i18n/messages';
1
2
  import { ThemeColorOverrides } from './themeRoles';
2
3
  import { LauncherIcon, LauncherOpenIcon, WidgetConfig } from './types';
3
4
  export declare const DEFAULT_API_BASE_URL = "https://api.aidenvoice.com";
@@ -6,6 +7,8 @@ export declare function resolveZIndex(zIndex: unknown): number;
6
7
  export declare const DEFAULT_AGENT_NAME = "Aiden";
7
8
  export declare function trimmedName(name: unknown): string;
8
9
  export declare function validateConfig(config: WidgetConfig): void;
10
+ export declare function normalizeGetSessionToken(config: WidgetConfig): (() => string | Promise<string>) | undefined;
11
+ export declare function normalizeMessages(value: unknown): Partial<WidgetMessages>;
9
12
  export declare function safeFontFamily(value: unknown): string | undefined;
10
13
  export interface NormalizedTheme {
11
14
  colors: ThemeColorOverrides;
@@ -1,7 +1,11 @@
1
1
  import { NormalizedTheme } from './config';
2
+ import { SupportedLanguage } from './i18n';
3
+ import { WidgetMessages } from './i18n/messages';
2
4
  import { WidgetConfig } from './types';
3
5
  export declare const SLOW_RESPONSE_DELAY_MS = 8000;
4
6
  export declare const BRANDING_LOOKUP_WAIT_MS = 3000;
7
+ export declare const TOKEN_RENEWAL_MARGIN_MS = 60000;
8
+ export declare const RENEWAL_TIMEOUT_MS = 15000;
5
9
  export interface Message {
6
10
  role: 'user' | 'assistant';
7
11
  content: string;
@@ -27,6 +31,7 @@ export interface WidgetState {
27
31
  accentColor: string | null;
28
32
  inkColor: string | null;
29
33
  announcement: string | null;
34
+ announcementIsContent: boolean;
30
35
  isSlowResponse: boolean;
31
36
  draft: string;
32
37
  }
@@ -36,6 +41,11 @@ export declare class WidgetController {
36
41
  private state;
37
42
  private readonly listeners;
38
43
  private sessionToken;
44
+ private sessionTokenExpiresAt;
45
+ private tokenRenewal;
46
+ private renewalGeneration;
47
+ private sendEpoch;
48
+ private readonly getSessionToken;
39
49
  private conversationId;
40
50
  private readonly storageIdentifier;
41
51
  private activeRequestController;
@@ -46,6 +56,11 @@ export declare class WidgetController {
46
56
  readonly emptyStateImageUrl: string | undefined;
47
57
  readonly emptyStateImageAlt: string;
48
58
  readonly showFeedback: boolean;
59
+ readonly text: WidgetMessages;
60
+ readonly language: SupportedLanguage;
61
+ readonly languageTag: string;
62
+ readonly contentLanguage: string;
63
+ readonly dir: 'ltr' | 'rtl';
49
64
  constructor(config: WidgetConfig);
50
65
  getState(): WidgetState;
51
66
  subscribe(listener: Listener): () => void;
@@ -63,5 +78,10 @@ export declare class WidgetController {
63
78
  setFeedbackDraft(messageId: string, correction: string, category: '' | FeedbackCategory): void;
64
79
  cancelFeedback(messageId: string): void;
65
80
  submitFeedback(messageId: string, rating: 'up' | 'down', correction?: string, category?: FeedbackCategory): Promise<void>;
81
+ private currentToken;
82
+ private renewToken;
83
+ private fetchNewToken;
84
+ private obtainToken;
85
+ private withSession;
66
86
  }
67
87
  export {};
@@ -0,0 +1,32 @@
1
+ import { WidgetMessages } from './messages';
2
+ declare const DICTIONARIES: {
3
+ readonly en: WidgetMessages;
4
+ readonly fr: WidgetMessages;
5
+ readonly es: WidgetMessages;
6
+ readonly pt: WidgetMessages;
7
+ readonly de: WidgetMessages;
8
+ readonly it: WidgetMessages;
9
+ readonly ja: WidgetMessages;
10
+ readonly zh: WidgetMessages;
11
+ readonly ru: WidgetMessages;
12
+ readonly hi: WidgetMessages;
13
+ readonly ar: WidgetMessages;
14
+ };
15
+ export type SupportedLanguage = keyof typeof DICTIONARIES;
16
+ export declare const SUPPORTED_LANGUAGES: readonly SupportedLanguage[];
17
+ export declare function messagesFor(language: SupportedLanguage): WidgetMessages;
18
+ export declare function resolveLanguage(option: unknown, pageLang: unknown): {
19
+ language: SupportedLanguage;
20
+ tag: string;
21
+ dir: 'ltr' | 'rtl';
22
+ };
23
+ export declare function resolveContentLanguage(option: unknown, pageLang: unknown, languageOption?: unknown): string;
24
+ export declare function templateParts(template: string): {
25
+ before: string;
26
+ after: string;
27
+ hasName: boolean;
28
+ };
29
+ export declare function format(template: string, values: {
30
+ name: string;
31
+ }): string;
32
+ export type { WidgetMessages };
@@ -0,0 +1,2 @@
1
+ import { WidgetMessages } from '../messages';
2
+ export declare const ar: WidgetMessages;
@@ -0,0 +1,2 @@
1
+ import { WidgetMessages } from '../messages';
2
+ export declare const de: WidgetMessages;
@@ -0,0 +1,2 @@
1
+ import { WidgetMessages } from '../messages';
2
+ export declare const es: WidgetMessages;
@@ -0,0 +1,2 @@
1
+ import { WidgetMessages } from '../messages';
2
+ export declare const fr: WidgetMessages;
@@ -0,0 +1,2 @@
1
+ import { WidgetMessages } from '../messages';
2
+ export declare const hi: WidgetMessages;
@@ -0,0 +1,2 @@
1
+ import { WidgetMessages } from '../messages';
2
+ export declare const it: WidgetMessages;
@@ -0,0 +1,2 @@
1
+ import { WidgetMessages } from '../messages';
2
+ export declare const ja: WidgetMessages;
@@ -0,0 +1,2 @@
1
+ import { WidgetMessages } from '../messages';
2
+ export declare const pt: WidgetMessages;
@@ -0,0 +1,2 @@
1
+ import { WidgetMessages } from '../messages';
2
+ export declare const ru: WidgetMessages;
@@ -0,0 +1,2 @@
1
+ import { WidgetMessages } from '../messages';
2
+ export declare const zh: WidgetMessages;
@@ -0,0 +1,31 @@
1
+ export interface WidgetMessages {
2
+ openChat: string;
3
+ closeChat: string;
4
+ chatWith: string;
5
+ newConversation: string;
6
+ conversation: string;
7
+ you: string;
8
+ message: string;
9
+ send: string;
10
+ lookingItUp: string;
11
+ goodResponse: string;
12
+ badResponse: string;
13
+ additionalFeedback: string;
14
+ feedbackPlaceholder: string;
15
+ feedbackCategory: string;
16
+ selectReason: string;
17
+ categoryFactual: string;
18
+ categoryIncomplete: string;
19
+ categoryTone: string;
20
+ categoryOther: string;
21
+ submit: string;
22
+ cancel: string;
23
+ feedbackThanks: string;
24
+ feedbackFailed: string;
25
+ conversationCleared: string;
26
+ genericError: string;
27
+ sessionExpired: string;
28
+ opensInNewTab: string;
29
+ }
30
+ export declare const ENGLISH: WidgetMessages;
31
+ export declare const MESSAGE_KEYS: (keyof WidgetMessages)[];
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { LauncherIcon, LauncherOpenIcon, WidgetConfig, WidgetHandle, WidgetLayout, WidgetTheme } from './types';
2
2
  export declare function init(config: WidgetConfig): WidgetHandle;
3
+ export { SUPPORTED_LANGUAGES } from './i18n';
4
+ export type { WidgetMessages } from './i18n/messages';
3
5
  export type { ContrastWarning, ResolvedTheme, ThemeInput } from './theme';
4
6
  export { resolveTheme } from './theme';
5
7
  export type { ThemeColorOverrides, ThemeColorRole } from './themeRoles';
@@ -1,2 +1,6 @@
1
1
  import { ComponentChildren } from 'preact';
2
- export declare function renderMarkdown(source: string): ComponentChildren;
2
+ export interface RenderOptions {
3
+ linkCue?: string;
4
+ linkCueLang?: string;
5
+ }
6
+ export declare function renderMarkdown(source: string, options?: RenderOptions): ComponentChildren;
@@ -1 +1,3 @@
1
+ export declare function sessionTokenExp(token: string): number | null;
1
2
  export declare function isExpiredSessionToken(token: string, nowMs?: number): boolean;
3
+ export declare function receivedTokenExpiresAt(token: string, receivedAtMs?: number): number | null;
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { WidgetMessages } from './i18n/messages';
1
2
  export type LauncherIcon = 'chat' | 'message' | 'sparkle';
2
3
  export type LauncherOpenIcon = 'chevron-down' | 'close';
3
4
  export interface WidgetTheme {
@@ -72,6 +73,36 @@ export interface WidgetLayout {
72
73
  export interface WidgetConfig {
73
74
  publishableKey?: string;
74
75
  sessionToken?: string;
76
+ /**
77
+ * `sessionToken` mode only. Called when the session token has run out (or
78
+ * the server refuses it), to get a fresh one from your backend, which mints
79
+ * it the same way as the first. Without it, an expired session ends the
80
+ * chat until the page is reloaded. May return the token or a promise of it.
81
+ * (With `publishableKey` the widget renews its session by itself.)
82
+ */
83
+ getSessionToken?: () => string | Promise<string>;
84
+ /**
85
+ * The language of the widget's own text, as a BCP 47 tag ('fr', 'pt-BR',
86
+ * 'zh-CN'). Without it the widget follows the page's <html lang>, then
87
+ * English. Supported: en, fr, es, pt, de, it, ja, zh (Simplified), ru, hi,
88
+ * ar (right to left). An unsupported value is ignored with a warning.
89
+ */
90
+ language?: string;
91
+ /**
92
+ * Replaces individual built-in strings in whichever language is active,
93
+ * e.g. { newConversation: 'Start over' }. `chatWith` takes {name}.
94
+ * Unknown keys and blank or non-string values are ignored with a warning.
95
+ */
96
+ messages?: Partial<WidgetMessages>;
97
+ /**
98
+ * The language of the conversation's content (replies, the visitor's
99
+ * messages, and your greeting, title, name and image text), as a BCP 47
100
+ * tag, so screen readers read it with the right voice. Defaults to the
101
+ * page's <html lang>, then to `language` when the page has none, else
102
+ * unknown. Separate from `language`, which only sets the widget's own
103
+ * buttons and messages.
104
+ */
105
+ contentLanguage?: string;
75
106
  position?: 'bottom-right' | 'bottom-left';
76
107
  /**
77
108
  * Primary accent color. Overrides the color configured in whoo-aiden, in
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const WIDGET_VERSION = "0.7.3";
1
+ export declare const WIDGET_VERSION = "0.9.0";
@@ -2,3 +2,4 @@ export declare const FULL_SCREEN_QUERY = "(max-width: 400px), (max-height: 420px
2
2
  export declare const FIT_VISIBLE_ATTRIBUTE = "data-fit-visible";
3
3
  export declare function followVisualViewport(panel: HTMLElement): () => void;
4
4
  export declare function lockPageScrollWhileFullScreen(): () => void;
5
+ export declare function modalWhileFullScreen(panel: HTMLDialogElement): () => void;