@accurix/centrinfo-widget 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.
@@ -0,0 +1,309 @@
1
+ import "preact";
2
+
3
+ //#region src/i18n.d.ts
4
+
5
+ /**
6
+ * Every user-visible chrome string in one place. The widget ships English
7
+ * defaults; a host localises by passing `labels` to `Centrinfo.init()` —
8
+ * any subset is merged over the defaults (see `mergeStrings`). The chat
9
+ * *answers* are already multilingual server-side (the RAG mirrors the
10
+ * visitor's language); this covers the surrounding UI that the backend
11
+ * never produces.
12
+ */
13
+ interface WidgetStrings {
14
+ openChat: string;
15
+ closeChat: string;
16
+ muteSounds: string;
17
+ unmuteSounds: string;
18
+ /** Header presence line when the org is reachable. */
19
+ statusOnline: string;
20
+ /** Header presence line when bootstrap was loaded with `offline`. */
21
+ statusOffline: string;
22
+ composerPlaceholder: string;
23
+ send: string;
24
+ emoji: string;
25
+ gifs: string;
26
+ attachFile: string;
27
+ recordVoice: string;
28
+ stopRecording: string;
29
+ stop: string;
30
+ copy: string;
31
+ copied: string;
32
+ retry: string;
33
+ clearChat: string;
34
+ clearChatConfirm: string;
35
+ clearChatConfirmBody: string;
36
+ clearConfirmCta: string;
37
+ /** Header "End conversation" button + its confirm dialog + ended-state copy. */
38
+ endChat: string;
39
+ endChatConfirm: string;
40
+ endChatConfirmBody: string;
41
+ endConfirmCta: string;
42
+ conversationEnded: string;
43
+ startNewChat: string;
44
+ /** Past-conversations history. */
45
+ pastConversations: string;
46
+ viewingPast: string;
47
+ backToChat: string;
48
+ historyEnded: string;
49
+ /** Per-message 👍/👎 feedback. */
50
+ feedbackHelpful: string;
51
+ feedbackNotHelpful: string;
52
+ feedbackThanks: string;
53
+ /** End-of-chat CSAT prompt. */
54
+ csatPrompt: string;
55
+ feedbackCommentPlaceholder: string;
56
+ feedbackSend: string;
57
+ cancel: string;
58
+ newMessages: string;
59
+ poweredBy: string;
60
+ searchGifs: string;
61
+ searchingGifs: string;
62
+ noGifs: string;
63
+ assistantTyping: string;
64
+ emptyReply: string;
65
+ errorGeneric: string;
66
+ errorRateLimit: string;
67
+ attaching: string;
68
+ attachTooLarge: string;
69
+ attachFailed: string;
70
+ /** Handoff card (manual follow-up request). */
71
+ handoffTitle: string;
72
+ handoffName: string;
73
+ handoffEmail: string;
74
+ handoffNotify: string;
75
+ sending: string;
76
+ /** Confirmation after a manual submit. `{email}` is replaced with the address (or removed). */
77
+ handoffShared: string;
78
+ /** Generic action-form success fallback + error. */
79
+ formThanks: string;
80
+ formError: string;
81
+ /** Demo-booking picker. */
82
+ bookingPickTime: string;
83
+ bookingDuration: string;
84
+ /** Confirmation after requesting a demo. `{when}` = the chosen slot. */
85
+ bookingRequested: string;
86
+ /** Confirmation when a real calendar event was created. `{when}` = slot. */
87
+ bookingConfirmed: string;
88
+ /** Shown when the chosen slot was just taken by someone else. */
89
+ bookingSlotTaken: string;
90
+ /** Link-mode (Calendly): prompt + CTA + done note + the meeting link label.
91
+ * `{provider}` = the scheduler label (e.g. "Calendly"). */
92
+ bookingViaProvider: string;
93
+ bookingOpenScheduler: string;
94
+ bookingLinkOpened: string;
95
+ bookingMeetingLink: string;
96
+ /** Preview mode (data-preview): canned reply, action note, top banner. */
97
+ previewReply: string;
98
+ previewActionNote: string;
99
+ previewBanner: string;
100
+ }
101
+ //#endregion
102
+ //#region src/types.d.ts
103
+ /** Public configuration surface passed to `Centrinfo.init()` / <CentrinfoWidget>. */
104
+ interface WidgetConfig {
105
+ /** The org's public chat token (`pub_*`). Required. It IS the org identity. */
106
+ token: string;
107
+ /** API origin. Defaults to the production Centrinfo API. */
108
+ apiBaseUrl?: string;
109
+ /** Brand accent (any CSS color). Overrides the persona/default green. */
110
+ accentColor?: string;
111
+ /** Custom launcher icon — an image URL (e.g. the org's logo). Defaults to a chat glyph. */
112
+ launcherIcon?: string;
113
+ /** Tenor API key — enables the GIF picker. Omit to hide the GIF button. */
114
+ gifApiKey?: string;
115
+ /** Force a theme; otherwise follows the host's `prefers-color-scheme`. */
116
+ theme?: 'light' | 'dark' | 'auto';
117
+ /** Open the panel automatically on first load. */
118
+ openByDefault?: boolean;
119
+ /** Play subtle sound effects (open / send / receive). Default true. Visitors can still mute. */
120
+ sound?: boolean;
121
+ /**
122
+ * Tappable example questions shown under the greeting until the visitor
123
+ * sends their first message. When omitted, the widget falls back to the
124
+ * `starterQuestions` configured on the token (served by bootstrap).
125
+ */
126
+ starters?: string[];
127
+ /**
128
+ * Localise the UI chrome. Any subset of `WidgetStrings` is merged over the
129
+ * English defaults — pass e.g. `{ composerPlaceholder: 'Écrivez…' }`. The
130
+ * chat answers themselves are already multilingual server-side.
131
+ */
132
+ labels?: Partial<WidgetStrings>;
133
+ /**
134
+ * Where the visible transcript is stored across reloads:
135
+ * - `local` (default) — `localStorage`, survives browser restarts (30d TTL).
136
+ * - `session` — `sessionStorage`, cleared when the tab closes (better on
137
+ * shared / kiosk machines so the next visitor can't read prior chats).
138
+ * - `none` — never persisted; the transcript lives only in memory.
139
+ * The backend session id + memory are unaffected — this is purely the
140
+ * locally-rendered history.
141
+ */
142
+ persistence?: 'local' | 'session' | 'none';
143
+ /**
144
+ * Let visitors attach an image / PDF for the assistant to read (extracted
145
+ * server-side via the multimodal endpoint). Default true; set false to hide
146
+ * the attach button entirely.
147
+ */
148
+ attachments?: boolean;
149
+ /** Stacking context against the host page. */
150
+ zIndex?: number;
151
+ /** Use the built-in mock transport (local preview, no backend/token needed). */
152
+ demo?: boolean;
153
+ /**
154
+ * Preview mode. Loads the widget's REAL branding (via the bootstrap read)
155
+ * but answers every chat with a canned sample reply instead of calling the
156
+ * AI — so a developer can test the integration anywhere with just the token,
157
+ * at zero AI cost. Remove this flag (or use the normal embed) to go live.
158
+ */
159
+ preview?: boolean;
160
+ /**
161
+ * Host-app SSO passthrough. When the embedding site has a logged-in
162
+ * user, pass their identity here so the chat session is correlated
163
+ * with them in the org's widget inbox (instead of showing as
164
+ * "Anonymous"). Fully optional — omit for unauthenticated visitors.
165
+ *
166
+ * The widget posts this to `POST /public-chat/identify` once after
167
+ * bootstrap completes. To identify a visitor who logs in MID-SESSION
168
+ * (anonymous chat → sign-in), call `handle.identify(user)` instead.
169
+ * The same `sessionId` survives the identify call, so prior
170
+ * anonymous messages stay attached to the now-known session row.
171
+ *
172
+ * See .claude/PUBLIC_WIDGET_LIBRARY.md "Identified visitors" for
173
+ * what fields to pass + the privacy guidance.
174
+ */
175
+ user?: WidgetUser;
176
+ /** Which side the launcher + panel dock to. Default 'right'. */
177
+ alignment?: 'left' | 'right';
178
+ /** Horizontal distance (px) from the aligned edge. Default 20. */
179
+ horizontalPadding?: number;
180
+ /** Vertical distance (px) from the bottom. Default 20. */
181
+ verticalPadding?: number;
182
+ /** Hide the built-in launcher button — open the widget via `show()` or a
183
+ * `customLauncherSelector`. Default false. */
184
+ hideDefaultLauncher?: boolean;
185
+ /** CSS selector for host-page element(s) that open the widget on click
186
+ * (your own launcher). Listeners are (re)bound automatically. */
187
+ customLauncherSelector?: string;
188
+ /** Auto-logout (wipe local data) after this many minutes of inactivity.
189
+ * 0 / omitted = never. Use on shared / kiosk devices. */
190
+ sessionDurationMinutes?: number;
191
+ /** A message to proactively show (auto-opens the widget) — e.g.
192
+ * "Questions about pricing? I'm here 👋". Omit to disable. */
193
+ proactiveMessage?: string;
194
+ /** Seconds to wait on the page before showing it. Default 5. */
195
+ proactiveDelaySeconds?: number;
196
+ /** Only fire on pages whose path contains one of these substrings.
197
+ * Omitted/empty = every page. e.g. ['/pricing', '/checkout']. */
198
+ proactiveOnPaths?: string[];
199
+ /** Show a "How was this chat?" CSAT rating when the conversation ends.
200
+ * Default true. */
201
+ csat?: boolean;
202
+ /** Event hooks. */
203
+ onOpen?: () => void;
204
+ onClose?: () => void;
205
+ /** Aliases of onOpen/onClose (Intercom naming). Both fire. */
206
+ onShow?: () => void;
207
+ onHide?: () => void;
208
+ /** Fires whenever the unread-message count changes (drive your own badge). */
209
+ onUnreadChange?: (count: number) => void;
210
+ onMessage?: (msg: {
211
+ role: 'user' | 'assistant';
212
+ content: string;
213
+ }) => void;
214
+ onAction?: (action: string) => void;
215
+ onHandoff?: () => void;
216
+ }
217
+ /** A B2B company / account the visitor belongs to (Intercom "Company object").
218
+ * Folded into the session metadata for the staff inbox. */
219
+ interface WidgetCompany {
220
+ id?: string;
221
+ name?: string;
222
+ plan?: string;
223
+ /** Account creation date — epoch seconds/ms or ISO string. */
224
+ createdAt?: number | string;
225
+ monthlySpend?: number;
226
+ /** Any extra company attributes. */
227
+ [key: string]: string | number | boolean | undefined;
228
+ }
229
+ /** Host-app SSO passthrough payload + data attributes. All fields optional. */
230
+ interface WidgetUser {
231
+ /** Host-app's stable user id (UUID, account number, etc.). Strongly recommended. */
232
+ externalId?: string;
233
+ /** Intercom-style alias for `externalId` (whichever you set is used). */
234
+ userId?: string;
235
+ email?: string;
236
+ firstName?: string;
237
+ lastName?: string;
238
+ /** Single-field name when first/last aren't split host-side. */
239
+ name?: string;
240
+ phone?: string;
241
+ /** Account creation date — epoch seconds/ms or ISO string (a data attribute). */
242
+ createdAt?: number | string;
243
+ /** Avatar image URL (the "Avatar object") — surfaced to staff in the inbox. */
244
+ avatarUrl?: string;
245
+ /** The visitor's company / account (B2B "Company object"). */
246
+ company?: WidgetCompany;
247
+ /**
248
+ * Custom data attributes (plan tier, signup date, segment, …). Merged into
249
+ * the session metadata, same privacy caveat as `metadata` below.
250
+ */
251
+ customAttributes?: Record<string, string | number | boolean>;
252
+ /**
253
+ * Arbitrary host-app key/values (plan tier, signup date, custom
254
+ * segments). Surfaced as-is in the org's staff inbox. DO NOT pass
255
+ * sensitive data — the widget script runs on the public web and a
256
+ * determined visitor with devtools could inspect it. Safe: plan
257
+ * tier, signup date, segment. Unsafe: card numbers, SSNs, auth
258
+ * tokens, internal admin flags.
259
+ */
260
+ metadata?: Record<string, string | number | boolean>;
261
+ }
262
+ /** Imperative handle returned by `init()` / `createWidget()`. */
263
+ interface WidgetHandle {
264
+ open: () => void;
265
+ close: () => void;
266
+ toggle: () => void;
267
+ /** Open the panel (alias of `open`, Intercom naming). */
268
+ show: () => void;
269
+ /** Close the panel (alias of `close`, Intercom naming). */
270
+ hide: () => void;
271
+ /** Update the visitor's attributes mid-session (merge). Alias of `identify`. */
272
+ update: (user: WidgetUser) => void;
273
+ /**
274
+ * Identify the visitor mid-session (e.g. after they log in on the
275
+ * host site). The session's prior anonymous messages stay attached
276
+ * — the widget's sessionId is stable across identify. Same merge
277
+ * semantics as boot-time `user`: first-value-wins per field, shallow
278
+ * metadata merge.
279
+ */
280
+ identify: (user: WidgetUser) => void;
281
+ /** Wipe the locally-rendered transcript + start a fresh backend session. */
282
+ clear: () => void;
283
+ /**
284
+ * Logout: erase ALL of this visitor's locally-stored data (identity,
285
+ * transcripts, conversation history) and reset to a fresh anonymous
286
+ * session. Call on host-app logout / shared devices — à la Intercom
287
+ * `shutdown`. `logout` is an alias.
288
+ */
289
+ shutdown: () => void;
290
+ logout: () => void;
291
+ destroy: () => void;
292
+ }
293
+ //#endregion
294
+ //#region src/mount.d.ts
295
+ /** Create + mount a widget. Returns an imperative handle. */
296
+ declare const createWidget: (config: WidgetConfig) => WidgetHandle;
297
+ //#endregion
298
+ //#region src/index.d.ts
299
+ /**
300
+ * Boot the widget. Idempotent — a second `init()` tears down the previous
301
+ * instance first, so calling it twice (e.g. SPA re-render) won't stack widgets.
302
+ */
303
+ declare const init: (config: WidgetConfig) => WidgetHandle;
304
+ declare const Centrinfo: {
305
+ init: (config: WidgetConfig) => WidgetHandle;
306
+ createWidget: (config: WidgetConfig) => WidgetHandle;
307
+ };
308
+ //#endregion
309
+ export { Centrinfo, type WidgetConfig, type WidgetHandle, type WidgetStrings, type WidgetUser, createWidget, init };