andy-widget-react 2.3.2 → 3.0.0-next.10

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
@@ -5,13 +5,14 @@ The official React Widget for Andy. Its canonical source is
5
5
 
6
6
  ## Install
7
7
 
8
- Pin an exact reviewed release:
8
+ Pin an exact reviewed release. 3.0 prereleases are on the npm `next` tag:
9
9
 
10
10
  ```bash
11
- bun add andy-widget-react@2.3.2
11
+ bun add andy-widget-react@3.0.0-next.10
12
12
  ```
13
13
 
14
- React and React DOM 18 or 19 are required peer dependencies.
14
+ React and React DOM 18 or 19 are peer dependencies. `andy-widget-core` (the `<andy-chat>` element) comes with
15
+ it as a dependency at the same exact version; the wrapper never inlines it.
15
16
 
16
17
  ## Use
17
18
 
@@ -23,61 +24,80 @@ import { AndyChat, setApiBaseUrl } from 'andy-widget-react'
23
24
  setApiBaseUrl('https://app.andypartner.com/api')
24
25
 
25
26
  export function SupportWidget() {
26
- return <AndyChat embedId='your-agent-id' />
27
+ return <AndyChat agentId='your-agent-id' />
27
28
  }
28
29
  ```
29
30
 
30
- `embedId` is the non-secret Andy Agent ID. The Widget fetches its effective configuration from
31
- `GET /api/chatbot/:embedId` and sends visitor messages to `POST /api/messages`. The browser sends
32
- the embedding page's `Origin`; Andy enforces the Agent's exact allowed-origin configuration.
31
+ `AndyChat` renders one `<andy-chat>` element and hands it its props. `agentId` is the non-secret Andy Agent
32
+ ID: the Widget fetches its configuration from `GET /api/chatbot/:agentId` and streams replies from
33
+ `POST /api/chat/stream`. The browser sends the embedding page's `Origin`; Andy enforces the Agent's allowed
34
+ origins. Server rendering draws an empty host `<div>`; the element mounts on the client.
33
35
 
34
- The launcher starts closed. If the Agent ID is invalid or configuration cannot be loaded, the
35
- Widget renders no launcher and does not affect the host page. Message failures remain inside the
36
- Widget as a short, language-aware retry message.
36
+ The Launcher starts closed. If the Agent ID is invalid or its configuration cannot be loaded, nothing shows
37
+ and the host page is unaffected.
37
38
 
38
39
  ## Props
39
40
 
40
41
  | Prop | Type | Purpose |
41
42
  | --- | --- | --- |
42
- | `embedId` | `string` | Required Agent ID outside preview mode |
43
- | `tooltip` | `string` | Optional launcher tooltip |
44
- | `name` | `string` | Override the configured Agent name |
45
- | `headline` | `string` | Override the configured headline |
46
- | `description` | `string` | Override the configured description |
47
- | `welcomeMessage` | `string` | Override the configured first message |
48
- | `bubbleLabel` | `string` | Override the configured pill label |
49
- | `lang` | `'en' \| 'es'` | Language for the Widget's own chrome (placeholder, starter-question title, error and handoff text). Overrides the Agent's `defaultLang`, so a Spanish Agent on an English page still renders English chrome |
50
- | `predefinedQuestions` | `{ order: number, question: string }[]` | Override the configured starter questions |
51
- | `theme` | `'light' \| 'dark' \| 'auto'` | Override the configured theme |
52
- | `orientation` | `'left' \| 'right'` | Override the configured position |
53
- | `brandColor` | `string` | Override the configured six-digit hex color |
54
- | `bubbleStyle` | `'icon' \| 'pill'` | Override the configured launcher style |
55
- | `useBrandColor` | `boolean` | Override configured brand-color use |
56
- | `logoUrl` | `string` | Override the configured logo |
57
- | `previewMode` | `boolean` | Render local prop-based preview configuration |
58
- | `initialOpen` | `boolean` | Opt into an initially open Widget; defaults to `false` |
59
-
60
- The server configuration controls **Powered by Andy** visibility. Consumers cannot suppress it
61
- with a prop. FAQ entries render only when the API supplies both a question and an answer; the
62
- current question-only response safely exposes no incomplete FAQ. Visitor-information and lead
63
- capture are disabled in this release because there is no durable public submission boundary.
64
-
65
- This release intentionally has no Widget analytics or event callback API. Use Andy's existing
66
- conversation analytics rather than observing the Shadow DOM.
43
+ | `agentId` | `string` | The Sales Agent ID, shown to anonymous Visitors |
44
+ | `support` | `SupportOptions` | Support Mode for signed-in Requesters (see [Authenticated Support](#authenticated-support)) |
45
+ | `lang` | `'en' \| 'es'` | The Widget's language, over the page's `<html lang>`, the browser's language and the Agent's `defaultLang` |
46
+ | `initialOpen` | `boolean` | Start with the panel open; defaults to `false` |
47
+ | `orientation` | `'left' \| 'right'` | The Launcher's side |
48
+ | `nudge` | `{ id: string, message: string, draft?: string, delayMs?: number } \| null` | A bubble above the closed Launcher, in Sales and Support Mode (see [Nudge](#nudge)) |
49
+ | `name` | `string` | Override the Agent's name |
50
+ | `welcomeMessage` | `string` | Override the Greeting |
51
+ | `predefinedQuestions` | `{ order: number, question: string }[]` | Override the Starters |
52
+ | `theme` | `'light' \| 'dark' \| 'auto'` | Override the theme |
53
+ | `brandColor` | `string` | Override the accent (`#RRGGBB`) |
54
+ | `useBrandColor` | `boolean` | `false` uses the neutral accent |
55
+ | `bubbleStyle` | `'icon' \| 'pill'` | Override the Launcher style |
56
+ | `bubbleLabel` | `string` | Override the pill Launcher's label |
57
+ | `logoUrl` | `string` | Override the avatar, also shown on the Launcher |
58
+ | `previewMode` | `boolean` | Draw the override props over the defaults with no configuration fetched (a Widget Preview); messages still reach `agentId` |
59
+ | `embedId` | `string` | Deprecated alias of `agentId`; logs one notice |
60
+ | `mode` | `'support'` | Deprecated: `support` without `agentId`; logs one notice |
61
+ | `tooltip` | `string` | Deprecated and ignored: the 3.x Launcher has no tooltip |
62
+ | `headline` | `string` | Deprecated and ignored: the panel shows only the name and the Greeting, with no status line |
63
+ | `description` | `string` | Deprecated and ignored: the panel shows no intro description |
64
+
65
+ The overrides replace the Agent's own values in the Widget's language, in Sales Mode only; an empty or invalid
66
+ value leaves the Agent's. The server configuration controls **Powered by Andy**; no prop suppresses it.
67
+
68
+ ## Nudge
69
+
70
+ `nudge` asks the user something from a bubble above the closed Launcher, for example feedback on a new page:
71
+
72
+ ```tsx
73
+ <AndyChat
74
+ support={support}
75
+ nudge={{ id: 'visualizaciones-feedback-1', message: '¿Hay algo que mejorarías de esta visualización?', draft: 'Mejoraría ' }}
76
+ />
77
+ ```
78
+
79
+ - It shows `delayMs` after the Launcher appears (default 1,500 ms), only while the panel is closed, on the Launcher's side.
80
+ - Clicking it opens the panel with `draft` in an empty composer; nothing is sent until the user sends it.
81
+ - It shows on every page that passes it. Once its × is clicked, or the bubble opens the panel, it stays hidden for the rest of the browser session (`sessionStorage`, per `id`). A new session (a new tab or a reopened browser) shows it again, and so does a new `id`.
82
+ - `null`, or a different `id`, updates it in place without remounting the Widget. The same `id` with new text only changes the text.
67
83
 
68
84
  ## Authenticated Support
69
85
 
70
- Support requires a configured host installation and a server-provisioned Support Agent. Use the accepted core/React package pair; this source addition is unpublished until the coordinated release is approved.
86
+ Support requires a configured host installation and a server-provisioned Support Agent.
87
+
88
+ One Widget serves both: its Widget Mode comes from identity. A Visitor gets Sales Mode with `agentId`; a signed-in Requester whose `getRequesterPass` returns a pass gets Support Mode. Without `agentId` (a Support-only host) nothing shows until a Requester is verified.
71
89
 
72
90
  ```tsx
73
91
  <AndyChat
74
- mode='support'
92
+ agentId='your-sales-agent-id'
75
93
  lang='es'
76
94
  support={{
77
95
  installationId: hostInstallationId,
78
- contextKey: `${signedInUserId}:${selectedCompanyId}`,
96
+ contextKey: signedInUserId ? `${signedInUserId}:${selectedCompanyId}` : 'anonymous',
79
97
  getRequesterPass: async () => {
80
- const response = await fetch('/api/andy/requester-pass', { cache: 'no-store' })
98
+ if (!signedInUserId) return null // known signed out: Sales shows without a round trip
99
+ const response = await fetch('/api/andy/requester-pass', { method: 'POST', cache: 'no-store' })
100
+ if (response.status === 401) return null // signed out
81
101
  if (!response.ok) throw new Error('Support authentication unavailable')
82
102
  return (await response.json()).pass
83
103
  }
@@ -85,32 +105,32 @@ Support requires a configured host installation and a server-provisioned Support
85
105
  />
86
106
  ```
87
107
 
88
- That host endpoint signs on the server from the authenticated user/company; never put a signing key in the browser. Change `contextKey` whenever identity/company changes, and unmount on sign-out. The SDK aborts and clears old private state. The pass remains in memory and is sent only in `X-Andy-Requester`. Expired/unknown-key refusals renew once; other failures stop inside the panel. `apiBaseUrl` may explicitly select the reviewed Andy API origin; normal production defaults to Andy.
89
-
90
- Provider branding and links, greeting/questions and reply promise come from Andy. When the host `lang` differs from the Agent default language, Support uses a localized default greeting and omits the Agent’s untranslated suggested questions. Existing conversation messages keep their original language. Custom hooks can pass `lang` in their Support options. There is no `embedId`, visitor identity form or Sales action in this mode. Sending the team form consents to attach the frozen conversation; its retry preserves the request key and receipt. Mis solicitudes stays inside the panel and displays the Requester's public human thread. The panel fills phones. Vanilla Support is frozen.
91
-
92
- For a custom React presentation, `useAndyChat({ mode: 'support', support })` returns `{ mode, state, controller }`. The controller exposes `send`, `escalate`, `submit`, `showRequests`, `inspect`, `back` and `newConversation`; it has the same consent, abort and retry semantics as the mounted panel. Do not use Sales presentation helpers with this result. Ticket replies and explicit reopens use the private human Requester operations, never the AI route.
108
+ That host endpoint signs on the server from the authenticated user/company; never put a signing key in the browser. The installation ID is public and is never a credential: without a pass there is no Support Mode. Identity comes only from the pass, never from name or email props.
93
109
 
94
- The panel captures its displayed `lang` on the first consented open as the ticket's Reply Email preference. A retry keeps that original choice even if the host changes language. Custom presentations call `controller.submit(subject, body, 'es' | 'en')` with their displayed language; omission defaults to Spanish. This copy preference never enters the signed pass or provider configuration.
110
+ - Change `contextKey` on sign-in, sign-out and every user, workspace or organization switch. Each change starts a fresh panel; reopening the panel is not an identity change.
111
+ - Return `null` from `getRequesterPass` while nobody is signed in. At mount a rejection also counts as signed out; during a session it shows Retry or the expired session, which keeps a half-written request.
112
+ - Signing in tears down Sales and forgets the tab's Visitor session, so the anonymous transcript is never shown to the Requester or attached to a request, and does not come back after signing out.
113
+ - Signing out, a new `contextKey`, a renewed pass that names another account, or `getRequesterPass` returning `null` destroys all Support state: chat, drafts, requests and unread count. When the tab becomes visible again the Widget asks for a pass once more, so a sign-out or account switch in another tab reaches it.
114
+ - Sales requests never carry `X-Andy-Requester`, and Support requests never carry a Sales session.
95
115
 
96
- ## Advanced exports
116
+ `mode='support'` is a deprecated alias for `support` without `agentId`, and logs one notice.
97
117
 
98
- The package also exports `useAndyChat`, individual presentation components, its public TypeScript
99
- types, design tokens, `getApiBaseUrl`, and `setApiBaseUrl`. `Andy` remains a compatibility alias
100
- for `AndyChat`; new integrations should use `AndyChat`.
118
+ The pass remains in memory and is sent only in `X-Andy-Requester`. Expired/unknown-key refusals renew once; other failures stop inside the panel. `apiBaseUrl` may explicitly select the reviewed Andy API origin; normal production defaults to Andy.
101
119
 
102
- ## Supported integration path
120
+ Provider branding and links, greeting/questions and reply promise come from Andy. When the host `lang` differs from the Agent default language, Support uses a localized default greeting and omits the Agent’s untranslated suggested questions. Existing conversation messages keep their original language. There is no `embedId`, visitor identity form or Sales action in this mode. The panel is the 3.x `<andy-chat>` shell in Support Mode: Chat and Mis solicitudes tabs with an unread count, the team form as a sheet over the chat, the receipt as a card in the thread, and each request's public human thread with Reply, Reabrir and Es otro problema. Sending the team form consents to attach the frozen conversation; its retry preserves the request key and receipt. When Andy's AI allowance is spent, the chat says so and offers Talk to the team. It follows the system light or dark theme and fills phones. `orientation` picks the Launcher's side; `tooltip` is ignored (the 3.x Launcher has none). Plain HTML hosts get the same Widget through the browser bundle's `window.AndyChat.configure` (see `andy-widget-vanilla`).
103
121
 
104
- Use the React package directly. Do not use an iframe, a floating `@latest` dependency, or Andy's
105
- legacy hosted `/widget.js` redirect for new integrations.
122
+ The panel captures its displayed `lang` on the first consented open as the ticket's Reply Email preference. A retry keeps that original choice even if the host changes language. This copy preference never enters the signed pass or provider configuration.
106
123
 
107
- ## License
124
+ To handle a Reply Email link, pass the host URL's ticket parameter as `support.ticketId` after normal host sign-in. The widget opens that request only after Andy authorizes the current Requester/company. On another company or user, keep changing `contextKey`; on sign-out, unmount. Never supply an old pass as URL data.
108
125
 
109
- MIT
126
+ The human thread follows replies and status changes without a page reload. Private polling runs every three seconds while subscribed and pauses in hidden documents. The launcher and My requests show unread replies. Opening a visible thread marks only its displayed public entries seen; closing it preserves unread replies. Resolved requests offer Reopen with a message for the same problem, or This is another problem for a fresh consented request. Reply and reopen retries retain their original body and request key.
110
127
 
128
+ ## Exports
111
129
 
112
- To handle a Reply Email link, pass the host URL's ticket parameter as `support.ticketId` after normal host sign-in. The widget opens that request only after Andy authorizes the current Requester/company. On another company or user, keep changing `contextKey`; on sign-out, unmount. Never supply an old pass as URL data.
130
+ `AndyChat` (also the default export, and `Andy` as a compatibility alias), its prop types
131
+ (`AndyChatProps`, `SalesAndyChatProps`, `SupportAndyChatProps`, `PredefinedQuestion`), and `getApiBaseUrl`
132
+ and `setApiBaseUrl`. For the element itself, its config normalizer and string table, use `andy-widget-core`.
113
133
 
114
- The human thread follows replies and status changes without a page reload. Private polling runs every three seconds while subscribed and pauses in hidden documents. The launcher and My requests show unread replies. Opening a visible thread marks only its displayed public entries seen; closing it preserves unread replies. Resolved requests offer Reopen with a message for the same problem, or This is another problem for a fresh consented request. Reply and reopen retries retain their original body and request key.
134
+ ## License
115
135
 
116
- Custom presentations also use `controller.reply(body, reopen?)`, `newProblem()` and `refresh()`. Call `setVisible(false)` when a displayed thread is closed or hidden, and `setVisible(true)` when it is being read. Subscription disposal stops automatic refresh. The controller's `unreadCount`, Ticket sequence marks and public entries carry the same behavior as the mounted panel.
136
+ MIT