@accurix/centrinfo-widget 5.0.0 → 5.1.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
@@ -17,7 +17,7 @@ Zero-JS, via `data-*` on the script:
17
17
 
18
18
  ```html
19
19
  <script
20
- src="https://cdn.accurixtech.com/centrinfo/js/sdk-centrinfo-widget-v1.0.0/centrinfo-widget.js"
20
+ src="https://cdn.accurixtech.com/centrinfo/js/sdk-centrinfo-widget-v5.0.0/centrinfo-widget.js"
21
21
  data-token="pub_8f3k…"
22
22
  defer
23
23
  ></script>
@@ -27,7 +27,7 @@ Or call `init` yourself:
27
27
 
28
28
  ```html
29
29
  <script
30
- src="https://cdn.accurixtech.com/centrinfo/js/sdk-centrinfo-widget-v1.0.0/centrinfo-widget.js"
30
+ src="https://cdn.accurixtech.com/centrinfo/js/sdk-centrinfo-widget-v5.0.0/centrinfo-widget.js"
31
31
  defer
32
32
  ></script>
33
33
  <script>
@@ -45,26 +45,30 @@ pnpm add @accurix/centrinfo-widget
45
45
  import { init } from '@accurix/centrinfo-widget';
46
46
  const widget = init({ token: 'pub_8f3k…' });
47
47
  // widget.open() / .close() / .toggle() / .destroy()
48
+ // widget.show() / .hide() (aliases) / .identify(user) / .update(user) / .clear()
49
+ // widget.shutdown() (alias .logout()) on host-app logout
48
50
  ```
49
51
 
50
52
  ## Config
51
53
 
52
- | Option | Type | Default | Notes |
53
- | ------------------------------------------------------------- | ----------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------- |
54
- | `token` **(required)** | string | — | The org's `pub_*` token. It _is_ the org identity. |
55
- | `analyticsContextToken` | string | — | Server-signed governed analytics context. It must expire within 15 minutes and be scoped to this public widget token. |
56
- | `identityToken` | string | — | Short-lived customer identity JWT. Authenticated history is scoped to its verified external user ID. |
57
- | `getIdentityToken` | function | — | Returns a fresh customer identity JWT before authenticated requests. Prefer this for expiring tokens. |
58
- | `apiBaseUrl` | string | prod API | Override for staging / self-host. |
59
- | `accentColor` | string | brand green | Any CSS color — drives the launcher, header, user bubbles & send button (a darker shade for the gradient is derived automatically). |
60
- | `themeTokens` | object | — | Enterprise theme tokens for chat surfaces: accent, background, surface, text, muted text, border, shadow, radius, and font family. |
61
- | `launcherIcon` | string | chat glyph | Image URL (e.g. the org's logo) shown in the launcher bubble. |
62
- | `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | `auto` follows the host's `prefers-color-scheme`; `light`/`dark` force it. |
63
- | `openByDefault` | boolean | `false` | Open the panel on load. |
64
- | `zIndex` | number | very high | Stacking against the host page. |
65
- | `demo` | boolean | `false` | Use the built-in mock transport — **no backend/token needed**. |
66
- | `configRefreshSeconds` | number | `30` | While the panel is open, refresh token branding/actions from `bootstrap`; set `0` to disable. |
67
- | `onOpen` / `onClose` / `onMessage` / `onAction` / `onHandoff` | function | — | Event hooks. |
54
+ | Option | Type | Default | Notes |
55
+ | ------------------------------------------------------------- | ----------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
56
+ | `token` **(required)** | string | — | The org's `pub_*` token. It _is_ the org identity. |
57
+ | `analyticsContextToken` | string | — | Server-signed governed analytics context. It must expire within 15 minutes and be scoped to this public widget token. |
58
+ | `identityToken` | string | — | Short-lived customer identity JWT. Authenticated history is scoped to its verified external user ID. |
59
+ | `getIdentityToken` | function | — | Returns a fresh customer identity JWT before authenticated requests. Prefer this for expiring tokens. |
60
+ | `apiBaseUrl` | string | prod API | Override for staging / self-host. |
61
+ | `accentColor` | string | brand green | Any CSS color — drives the launcher, header, user bubbles & send button (a darker shade for the gradient is derived automatically). |
62
+ | `themeTokens` | object | — | Enterprise theme tokens for chat surfaces: accent, background, surface, text, muted text, border, shadow, radius, and font family. |
63
+ | `launcherIcon` | string | chat glyph | Image URL (e.g. the org's logo) shown in the launcher bubble. |
64
+ | `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | `auto` follows the host's `prefers-color-scheme`; `light`/`dark` force it. |
65
+ | `locale` / `dir` | string / `'ltr' \| 'rtl' \| 'auto'` | browser / `'auto'` | `dir` follows the locale (Arabic, Hebrew, Persian, Urdu... render right-to-left) unless forced. |
66
+ | `openByDefault` | boolean | `false` | Open the panel on load. |
67
+ | `zIndex` | number | very high | Stacking against the host page. |
68
+ | `demo` | boolean | `false` | Use the built-in mock transport — **no backend/token needed**. |
69
+ | `configRefreshSeconds` | number | `30` | While the panel is open, refresh token branding/actions from `bootstrap`; set `0` to disable. |
70
+ | `onOpen` / `onClose` / `onMessage` / `onAction` / `onHandoff` | function | — | Event hooks. |
71
+ | `onOpenAnalyticsSource` | function | — | Receives a cited insight or Liveboard tile from a signed analytics answer. The host must check access before opening it. |
68
72
 
69
73
  ```ts
70
74
  init({
@@ -84,6 +88,60 @@ init({
84
88
  });
85
89
  ```
86
90
 
91
+ ### Analytics labels
92
+
93
+ Analytics answers (KPI, chart, table, details, explanation) read their wording
94
+ from `labels.analytics`, also available per locale in `translations`. Any subset
95
+ overrides the English defaults; `{count}`-style placeholders are kept.
96
+
97
+ ```ts
98
+ init({
99
+ token: 'pub_8f3k...',
100
+ locale: 'fr',
101
+ labels: {
102
+ analytics: {
103
+ liveMetric: 'Indicateur',
104
+ resultDetails: 'Détails du résultat',
105
+ chartType: 'Type de graphique',
106
+ chooseChartType: 'Choisir le type de graphique',
107
+ download: 'Télécharger',
108
+ downloadData: 'Télécharger ces données',
109
+ expandChart: 'Agrandir le graphique',
110
+ expandTable: 'Agrandir le tableau',
111
+ restoreView: 'Revenir à l’assistant',
112
+ aboutResult: 'À propos de ce résultat',
113
+ notSet: 'Non défini',
114
+ noValue: 'Aucune valeur',
115
+ rowMany: '{count} lignes',
116
+ zoomIn: 'Zoom avant',
117
+ zoomOut: 'Zoom arrière',
118
+ zoomReset: 'Réinitialiser le zoom',
119
+ explanation: { feedbackPrompt: 'Cette réponse vous a-t-elle aidé ?', evidence: 'Preuve' },
120
+ },
121
+ },
122
+ });
123
+ ```
124
+
125
+ Keys: `resultDetails`, `liveMetric`, `currentValue`, `noMatchTitle`, `noMatchBody`,
126
+ `chartType`, `chooseChartType`, `aggregate`, `aggregateTitle`, `aggregateCharge`,
127
+ `chartFallback`, `chartLine`/`chartBar`/`chartStackedBar` (+ `...Hint`),
128
+ `aggregationSum`/`Avg`/`Min`/`Max`/`Count`/`CountDistinct`, `download`,
129
+ `downloadData`, `expandTable`, `expandChart`, `restoreView`, `aboutResult`,
130
+ `aboutPeriod`/`aboutResults`/`aboutChecked`/`aboutTimezone`/`aboutSourceData`/`aboutFilters`,
131
+ `rowOne`/`rowMany`, `filtersOne`/`filtersMany`/`filtersApplied`, `notSet`, `noValue`,
132
+ `yes`, `no`, `chartValues`, `chartTitle`, `seriesLimited`, `summaryLatest`,
133
+ `summaryNoTrend`, `summaryHighest`, `summaryNoComparison`, `zoomControls`,
134
+ `zoomIn`, `zoomOut`, `zoomReset`, `zoomResetShort`, `zoomNone`, `zoomAllOne`,
135
+ `zoomAllMany`, `zoomRange`, `inProgress`, `inProgressLegend`, `updatedAt`,
136
+ `liveData`, `viewData`, `hideData`, `newContent`, `governedResult`, and
137
+ `explanation` (the explanation panel's copy: `eyebrow`, `limits`, `evidence`,
138
+ `feedbackPrompt`, `region`, `expand`, `collapse`, ...). Not yet translatable: the
139
+ wording of the comparison-basis badge, the sentences the explanation builder
140
+ derives from data, and the table toolbar.
141
+
142
+ Numbers, currency, percent and dates are formatted with `locale`, the column
143
+ metadata (`currencyCode`, `formatPattern`, `grain`) and the result `timezone`.
144
+
87
145
  Persona (agent name/avatar/greeting), the voice toggle, and which lead-gen
88
146
  actions appear all come from the token via `GET /public-chat/bootstrap` — not
89
147
  from the snippet. Open widgets refresh that bootstrap data every 30 seconds, so
@@ -113,6 +171,17 @@ browser or device after the identity token is verified. Anonymous history is
113
171
  stored only according to the widget's `persistence` option and cannot be
114
172
  loaded through authenticated history.
115
173
 
174
+ If an authenticated analytics answer carries a cited insight or tile ID, pass
175
+ `onOpenAnalyticsSource` to show **Open source Liveboard** next to an answer
176
+ with one cited source, and **Open source** inside its citation. Resolve the
177
+ target with `centrinfo.liveboards.resolveSource({ kind, id })` before opening
178
+ it. That method returns only published boards assigned to the signed SDK
179
+ application; the destination checks the viewer's row access again. Current
180
+ general questions and anonymous answers do not show a source link. The
181
+ callback also receives `appliedFilters`; a host can restore only those
182
+ matching the board's published templates, using
183
+ `centrinfo.liveboards.createViewToken(boardId, state)`.
184
+
116
185
  Call `widget.shutdown()` on host-app logout when the page may be shared. It
117
186
  removes the local transcript and resets the mounted widget to an anonymous
118
187
  session. Retained server history is not deleted and returns only when the same
@@ -121,6 +190,10 @@ verified customer signs in again.
121
190
  When business data chat is enabled for a widget token, responses follow a
122
191
  visitor-safe presentation contract:
123
192
 
193
+ The chart's **Aggregate** menu asks a new governed follow-up for the chosen
194
+ measure and calculation. The answer appears in the conversation and may incur
195
+ normal query charges.
196
+
124
197
  - a normal knowledge, RAG, or web-search answer remains text;
125
198
  - a single live value may add a KPI and a comparison or timeline may add an
126
199
  expandable chart;
@@ -131,6 +204,9 @@ visitor-safe presentation contract:
131
204
  the written answer remains available instead;
132
205
  - charts include a visible text summary, contained tap/hover details, and an
133
206
  accessible expanded view that restores the conversation when closed.
207
+ - when the result includes it, a collapsed **About this result** panel shows
208
+ the reporting period, row count, checked time, timezone, freshness, and
209
+ number of active filters without exposing internal model or query IDs.
134
210
 
135
211
  For customer-specific analytics, create the signed context on the host
136
212
  application's server and pass only the resulting short-lived token as
@@ -158,9 +234,42 @@ matching public widget token. Sign this payload only on the host application's
158
234
  server; never expose the signing secret or mint analytics context tokens in
159
235
  browser code.
160
236
 
161
- `data-*` attributes for the script install: `data-token`, `data-api-base`,
162
- `data-accent`, `data-theme`, `data-open`, `data-demo`,
163
- `data-config-refresh`.
237
+ ### Other options
238
+
239
+ `persistence` (`local` | `session` | `none`), `attachments`, `sound`, `starters`,
240
+ `labels`, `translations`, `agentName`, `agentAvatarUrl`, `gifApiKey`,
241
+ `styleNonce`, `preview`, `user`, `alignment`, `horizontalPadding`,
242
+ `verticalPadding`, `hideDefaultLauncher`, `customLauncherSelector`,
243
+ `sessionDurationMinutes`, `proactiveMessage`, `proactiveDelaySeconds`,
244
+ `proactiveOnPaths`, `csat`. See `src/types.ts` (`WidgetConfig`) for each.
245
+
246
+ ### Events
247
+
248
+ - `onOpen()` / `onClose()` (aliases `onShow` / `onHide`)
249
+ - `onMessage({ role: 'user' | 'assistant', content })`
250
+ - `onAction(actionId: string)`
251
+ - `onHandoff()` (a live person was offered)
252
+ - `onUnreadChange(count)`
253
+ - `onOpenAnalyticsSource({ kind, id, appliedFilters? })`
254
+
255
+ ### Script attributes
256
+
257
+ `data-token`, `data-api-base`, `data-accent`, `data-agent-name`,
258
+ `data-agent-avatar-url`, `data-launcher-icon`, `data-gif-api-key`,
259
+ `data-theme`, `data-sound` (`false` disables), `data-open`, `data-demo`,
260
+ `data-preview`, `data-alignment` (`left`), `data-horizontal-padding`,
261
+ `data-vertical-padding`, `data-hide-launcher`, `data-custom-launcher-selector`,
262
+ `data-style-nonce`, `data-session-duration`, `data-config-refresh`,
263
+ `data-proactive-message`, `data-proactive-delay`, `data-csat` (`false`
264
+ disables), `data-user` (JSON). Source: `src/cdn/data-attributes.ts`.
265
+
266
+ ### Identity tokens, rate limits, explanations
267
+
268
+ `getIdentityToken` is called single-flight and its token is reused until 60
269
+ seconds before `exp`; issue short-lived tokens with a readable `exp`. API `429`
270
+ responses carry `Retry-After` and CORS headers. Analytics explanations that are
271
+ still `pending` are polled via `GET /public-chat/analytics-explanations/:id`
272
+ for up to about 45 seconds (`EXPLANATION_POLL_CAP_MS`) with a retry path.
164
273
 
165
274
  ## Environment
166
275
 
@@ -190,6 +299,41 @@ Open `http://localhost:3005/?demo`, open the widget, and use any of these starte
190
299
 
191
300
  Remove `?demo` to test the real public-chat API and the organization’s published analytics configuration.
192
301
 
302
+ ## What is stored locally
303
+
304
+ With the default `persistence: 'local'` the widget keeps, per token and visitor
305
+ (`centrinfo:session:*`, `centrinfo:visitor:*`, `centrinfo:chat:*`,
306
+ `centrinfo:history:*`):
307
+
308
+ - the session id, the visitor's name/email/phone once given, and a history index;
309
+ - a **lean transcript**: message text, ids, sources, suggested replies and
310
+ feedback, capped by the token's message cap and retention (30 days by default).
311
+
312
+ Analytics results are **not** stored: rows, filters, explanations and chart
313
+ data are dropped before writing, and a reloaded answer shows a short "ask again"
314
+ note instead. Entries written by older versions are slimmed on the next load.
315
+ Writes happen at most once per second (plus on tab hide), and a full or blocked
316
+ storage only costs the local copy of the chat. Use `persistence: 'none'` to
317
+ store nothing.
318
+
319
+ ## Lazy files and CSP
320
+
321
+ The CDN script is ~100 KB gzip. Two sibling files are fetched on demand,
322
+ relative to the script's own URL, and are published next to it by `publish:cdn`:
323
+
324
+ | File | Loaded when | ~gzip |
325
+ | ---------------------------- | ------------------------------------- | ------ |
326
+ | `centrinfo-widget-charts.js` | the first chart is drawn (ECharts) | 190 KB |
327
+ | `centrinfo-widget-dev.js` | only with `demo` or `preview` enabled | 5 KB |
328
+
329
+ The existing embed snippet is unchanged. Requirements: the files must be served
330
+ from the same origin as the script with `Access-Control-Allow-Origin` (they load
331
+ as ES modules), and a strict CSP needs that origin in `script-src` (already
332
+ there for the script itself). `connect-src` is unchanged (your API base only).
333
+ If the chart file is blocked, charts degrade to their text summary. The npm
334
+ package splits the same code into dynamic-import chunks that your bundler
335
+ handles automatically.
336
+
193
337
  ## Release Artifacts
194
338
 
195
339
  `build:npm` uses tsdown to emit the npm package entrypoints:
@@ -201,12 +345,13 @@ Remove `?demo` to test the real public-chat API and the organization’s publish
201
345
  `build:cdn` uses Vite to emit the browser script and then writes a manifest:
202
346
 
203
347
  - `dist/cdn/centrinfo-widget.js`
204
- - `dist/cdn/manifest.json`
348
+ - `dist/cdn/centrinfo-widget-charts.js` and `dist/cdn/centrinfo-widget-dev.js` (lazy)
349
+ - `dist/cdn/manifest.json` (sizes and SRI for all files)
205
350
 
206
- Canonical v1 CDN URL:
351
+ Canonical CDN URL (version from `dist/cdn/manifest.json` `cdnPath`):
207
352
 
208
353
  ```text
209
- https://cdn.accurixtech.com/centrinfo/js/sdk-centrinfo-widget-v1.0.0/centrinfo-widget.js
354
+ https://cdn.accurixtech.com/centrinfo/js/sdk-centrinfo-widget-v5.0.0/centrinfo-widget.js
210
355
  ```
211
356
 
212
357
  ### Publishing CDN assets
@@ -233,7 +378,7 @@ Optional environment:
233
378
 
234
379
  ## Status
235
380
 
236
- v1 in progress — chat, streaming (SSE), citations, suggested-reply chips,
237
- session memory, handoff CTA, lead-gen actions, voice input, theming.
238
- Backend `GET /public-chat/bootstrap` is pending (the only backend work);
239
- the client falls back to sensible defaults until it lands.
381
+ Chat, streaming (SSE), citations, suggested-reply chips, session memory,
382
+ handoff and live human takeover, lead-gen actions, voice, attachments,
383
+ analytics answers and theming are implemented. Persona, voice and actions
384
+ come from `GET /public-chat/bootstrap`.