andy-widget-react 2.3.1 → 3.0.0-next.1

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.2.1
11
+ bun add andy-widget-react@3.0.0-next.1
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,63 @@ 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>` 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
+ | `name` | `string` | Override the Agent's name |
49
+ | `headline` | `string` | Override the status line |
50
+ | `description` | `string` | Override the intro description |
51
+ | `welcomeMessage` | `string` | Override the Greeting |
52
+ | `predefinedQuestions` | `{ order: number, question: string }[]` | Override the Starters |
53
+ | `theme` | `'light' \| 'dark' \| 'auto'` | Override the theme |
54
+ | `brandColor` | `string` | Override the accent (`#RRGGBB`) |
55
+ | `useBrandColor` | `boolean` | `false` uses the neutral accent |
56
+ | `bubbleStyle` | `'icon' \| 'pill'` | Override the Launcher style |
57
+ | `bubbleLabel` | `string` | Override the pill Launcher's label |
58
+ | `logoUrl` | `string` | Override the avatar, also shown on the Launcher |
59
+ | `previewMode` | `boolean` | Draw the override props over the defaults with no configuration fetched (a Widget Preview); messages still reach `agentId` |
60
+ | `embedId` | `string` | Deprecated alias of `agentId`; logs one notice |
61
+ | `mode` | `'support'` | Deprecated: `support` without `agentId`; logs one notice |
62
+ | `tooltip` | `string` | Deprecated and ignored: the 3.x Launcher has no tooltip |
63
+
64
+ The overrides replace the Agent's own values in every language, in Sales Mode only; an empty or invalid
65
+ value leaves the Agent's. The server configuration controls **Powered by Andy**; no prop suppresses it.
67
66
 
68
67
  ## Authenticated Support
69
68
 
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.
69
+ Support requires a configured host installation and a server-provisioned Support Agent.
70
+
71
+ 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
72
 
72
73
  ```tsx
73
74
  <AndyChat
74
- mode='support'
75
+ agentId='your-sales-agent-id'
75
76
  lang='es'
76
77
  support={{
77
78
  installationId: hostInstallationId,
78
- contextKey: `${signedInUserId}:${selectedCompanyId}`,
79
+ contextKey: signedInUserId ? `${signedInUserId}:${selectedCompanyId}` : 'anonymous',
79
80
  getRequesterPass: async () => {
80
- const response = await fetch('/api/andy/requester-pass', { cache: 'no-store' })
81
+ if (!signedInUserId) return null // known signed out: Sales shows without a round trip
82
+ const response = await fetch('/api/andy/requester-pass', { method: 'POST', cache: 'no-store' })
83
+ if (response.status === 401) return null // signed out
81
84
  if (!response.ok) throw new Error('Support authentication unavailable')
82
85
  return (await response.json()).pass
83
86
  }
@@ -85,32 +88,32 @@ Support requires a configured host installation and a server-provisioned Support
85
88
  />
86
89
  ```
87
90
 
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.
91
+ 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
92
 
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.
93
+ - 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.
94
+ - 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.
95
+ - 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.
96
+ - 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.
97
+ - Sales requests never carry `X-Andy-Requester`, and Support requests never carry a Sales session.
95
98
 
96
- ## Advanced exports
99
+ `mode='support'` is a deprecated alias for `support` without `agentId`, and logs one notice.
97
100
 
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`.
101
+ 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
102
 
102
- ## Supported integration path
103
+ 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
104
 
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.
105
+ 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
106
 
107
- ## License
107
+ 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
108
 
109
- MIT
109
+ 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
110
 
111
+ ## Exports
111
112
 
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.
113
+ `AndyChat` (also the default export, and `Andy` as a compatibility alias), its prop types
114
+ (`AndyChatProps`, `SalesAndyChatProps`, `SupportAndyChatProps`, `PredefinedQuestion`), and `getApiBaseUrl`
115
+ and `setApiBaseUrl`. For the element itself, its config normalizer and string table, use `andy-widget-core`.
113
116
 
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.
117
+ ## License
115
118
 
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.
119
+ MIT