@helpai/elements 1.1.14 → 1.2.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/index.d.ts CHANGED
@@ -41,7 +41,7 @@ interface ClientStorage {
41
41
  * populated {@link Strings} map. UI components then read `strings.send` as a
42
42
  * normal property access — no per-render lookup, no per-render allocation.
43
43
  */
44
- type StringKey = "launcherOpen" | "launcherLabel" | "panelTitle" | "composerPlaceholder" | "send" | "stop" | "attach" | "micStart" | "micStop" | "micUnsupported" | "expand" | "collapse" | "fullscreen" | "exitFullscreen" | "popOut" | "resizeHandle" | "scrollToBottom" | "close" | "moreActions" | "soundOn" | "soundOff" | "language" | "theme" | "themeAuto" | "themeLight" | "themeDark" | "textSize" | "textSizeSmall" | "textSizeNormal" | "textSizeLarge" | "history" | "historyTitle" | "historyEmpty" | "historyLoading" | "historyBack" | "historyContinue" | "loadMoreConversations" | "conversationLoading" | "loadPreviousMessages" | "conversationClosed" | "startNewConversation" | "talkToOperator" | "connectingOperator" | "noOperatorAvailable" | "chattingWithOperator" | "cancelOperatorRequest" | "dateToday" | "dateYesterday" | "dateLastWeek" | "dateOlder" | "newConversation" | "dropZone" | "attachmentTooLarge" | "attachmentTooMany" | "attachmentMimeRejected" | "errorRetry" | "errorGeneric" | "errorRateLimited" | "loading" | "thinking" | "thoughts" | "toolResult" | "sources" | "feedbackUp" | "feedbackDown" | "feedbackThanks" | "copy" | "copied" | "collapseSidebar" | "expandSidebar" | "formSubmit" | "formSkip" | "formSubmitted" | "formSkipped" | "formFillOut" | "formRequired" | "formInvalidEmail" | "formInvalidTel" | "formInvalidUrl" | "formInvalidNumber" | "formTooShort" | "formTooLong" | "formNumberTooSmall" | "formNumberTooLarge" | "formPatternMismatch" | "formChooseAtLeast" | "formChooseAtMost" | "formOther" | "formOtherPlaceholder" | "inputRequired" | "inputBadge" | "inputAnswered" | "inputSkipped" | "inputSubmit" | "inputSubmitHint" | "inputSkip" | "showOptions" | "hideOptions" | "qtypeText" | "qtypeEmail" | "qtypePhone" | "qtypeNumber" | "qtypeDate" | "qtypeChooseOne" | "qtypeChooseAny" | "qtypeBoolean" | "confirmYes" | "confirmNo" | "approve" | "reject" | "approvalPrompt" | "approvalBody" | "approvalYourResponse" | "approvalEditHint" | "approvalSubmitting" | "edit" | "toolParameters" | "statusAwaiting" | "statusResponded" | "statusCompleted" | "statusDenied" | "statusError" | "statusRunning" | "statusSuperseded" | "tabHome" | "tabConversations" | "tabHelp" | "tabNews" | "modulesEmpty" | "moduleBack" | "contentLoading" | "homeGreeting" | "homeGreetingNamed" | "homeGreetingLead" | "homeSearchPlaceholder" | "homeContentTitle" | "homeStatus" | "helpTitle" | "helpSearchPlaceholder" | "helpEmpty" | "helpLoading" | "helpSearchEmpty" | "newsTitle" | "newsEmpty" | "newsLoading" | "newsBack" | "newsPublishedAt";
44
+ type StringKey = "launcherOpen" | "launcherLabel" | "panelTitle" | "composerPlaceholder" | "send" | "stop" | "queueMessage" | "removeQueuedMessage" | "compactingContext" | "attach" | "micStart" | "micStop" | "micUnsupported" | "expand" | "collapse" | "fullscreen" | "exitFullscreen" | "popOut" | "resizeHandle" | "scrollToBottom" | "close" | "moreActions" | "soundOn" | "soundOff" | "language" | "theme" | "themeAuto" | "themeLight" | "themeDark" | "textSize" | "textSizeSmall" | "textSizeNormal" | "textSizeLarge" | "history" | "historyTitle" | "historyEmpty" | "historyLoading" | "historyBack" | "historyContinue" | "loadMoreConversations" | "conversationLoading" | "loadPreviousMessages" | "conversationClosed" | "startNewConversation" | "talkToOperator" | "connectingOperator" | "noOperatorAvailable" | "chattingWithOperator" | "cancelOperatorRequest" | "dateToday" | "dateYesterday" | "dateLastWeek" | "dateOlder" | "newConversation" | "dropZone" | "attachmentTooLarge" | "attachmentTooMany" | "attachmentMimeRejected" | "errorRetry" | "errorGeneric" | "errorRateLimited" | "loading" | "thinking" | "thoughts" | "toolResult" | "sources" | "feedbackUp" | "feedbackDown" | "feedbackThanks" | "copy" | "copied" | "collapseSidebar" | "expandSidebar" | "formSubmit" | "formSkip" | "formSubmitted" | "formSkipped" | "formFillOut" | "formRequired" | "formInvalidEmail" | "formInvalidTel" | "formInvalidUrl" | "formInvalidNumber" | "formTooShort" | "formTooLong" | "formNumberTooSmall" | "formNumberTooLarge" | "formPatternMismatch" | "formChooseAtLeast" | "formChooseAtMost" | "formOther" | "formOtherPlaceholder" | "inputRequired" | "inputBadge" | "inputAnswered" | "inputSkipped" | "inputSubmit" | "inputSubmitHint" | "inputSkip" | "showOptions" | "hideOptions" | "qtypeText" | "qtypeEmail" | "qtypePhone" | "qtypeNumber" | "qtypeDate" | "qtypeChooseOne" | "qtypeChooseAny" | "qtypeBoolean" | "confirmYes" | "confirmNo" | "approve" | "reject" | "approvalPrompt" | "approvalBody" | "approvalYourResponse" | "approvalEditHint" | "approvalSubmitting" | "edit" | "toolParameters" | "statusAwaiting" | "statusResponded" | "statusCompleted" | "statusDenied" | "statusError" | "statusRunning" | "statusSuperseded" | "tabHome" | "tabConversations" | "tabHelp" | "tabNews" | "modulesEmpty" | "moduleBack" | "contentLoading" | "homeGreeting" | "homeGreetingNamed" | "homeGreetingLead" | "homeSearchPlaceholder" | "homeContentTitle" | "homeStatus" | "helpTitle" | "helpSearchPlaceholder" | "helpEmpty" | "helpLoading" | "helpSearchEmpty" | "newsTitle" | "newsEmpty" | "newsLoading" | "newsBack" | "newsPublishedAt";
45
45
  /** A partial map for one locale — what overrides look like on the wire. */
46
46
  type LocaleStrings = Partial<Record<StringKey, string>>;
47
47
  /**
@@ -942,7 +942,7 @@ interface ChatWidgetOptions {
942
942
  /**
943
943
  * Agent-API base (no trailing slash) — set it when the
944
944
  * `module-help-ai-agent-api` service is reached DIRECTLY (a standalone
945
- * local module, e.g. `http://localhost:3087`) instead of through the
945
+ * local module, e.g. `http://localhost:3111`) instead of through the
946
946
  * edge. Routes attach as-is (`${agentApiBaseUrl}/pai/handshake`).
947
947
  * Precedence: this option > derived from the main origin
948
948
  * (`${baseUrl}/api/agent`). Not server-pushable — the handshake already
@@ -953,7 +953,7 @@ interface ChatWidgetOptions {
953
953
  * Data-API base (no trailing slash) — the `module-help-ai-data-api`
954
954
  * service serving content, form definitions, and form submissions under
955
955
  * `/pai/*` (`content`, `bootstrap`, `submit-form`).
956
- * Set it for a standalone local module (e.g. `http://localhost:3106`).
956
+ * Set it for a standalone local module (e.g. `http://localhost:3105`).
957
957
  * Precedence: this option > server-pushed `config.dataApiBaseUrl` > derived
958
958
  * from the main origin (`${baseUrl}/api/data`, e.g.
959
959
  * `https://help.ai/api/data`).
@@ -1110,42 +1110,6 @@ interface ResolvedOptions {
1110
1110
  onClose?: ChatWidgetOptions["onClose"];
1111
1111
  onError?: ChatWidgetOptions["onError"];
1112
1112
  }
1113
- /**
1114
- * Shape of the server-pushed `config` object in `HandshakeResponse`.
1115
- *
1116
- * Matches a subset of {@link ChatWidgetOptions} — anything the server can
1117
- * reasonably dictate (UI, behaviour, routing). Callbacks (`onMessage` etc.)
1118
- * and the public key are deliberately excluded — those are client concerns.
1119
- *
1120
- * Form definitions no longer ride this config: the widget fetches them from
1121
- * the data-API (`GET /pai/bootstrap`). A stale backend still pushing
1122
- * `config.forms` is ignored.
1123
- */
1124
- interface ServerConfig$1 {
1125
- /** Data-API base override — adopted only when the host didn't set one. */
1126
- dataApiBaseUrl?: string;
1127
- /**
1128
- * Storage-schema version — the deployment-owned force-reset lever, pushed ONLY
1129
- * via the handshake (deliberately not an embed attribute / `init` option).
1130
- * Pushing a new value abandons every client's prior storage namespace
1131
- * (visitor id, conversation, prefs, panel state, caches) on next load. The
1132
- * widget stashes it and the next mount folds `.v<version>` into every key.
1133
- */
1134
- storageVersion?: string;
1135
- presentation?: PresentationOptions;
1136
- behavior?: BehaviorOptions;
1137
- theme?: ThemePreference | ThemeOverrides;
1138
- launcher?: LauncherOptions;
1139
- header?: HeaderOptions;
1140
- composer?: ComposerOptions;
1141
- feedback?: FeedbackOptions;
1142
- i18n?: I18nOptions;
1143
- footer?: FooterOptions;
1144
- features?: FeatureFlags;
1145
- modules?: ModulesOptions;
1146
- tracking?: TrackingOptions;
1147
- endpoints?: Endpoints;
1148
- }
1149
1113
  //#endregion
1150
1114
  //#region src/core/logger.d.ts
1151
1115
  /**
@@ -1181,362 +1145,6 @@ interface LogEntry {
1181
1145
  payload?: unknown;
1182
1146
  }
1183
1147
  //#endregion
1184
- //#region src/core/persistence.d.ts
1185
- /** Drag-resized panel dimensions. Persisted only when resize is enabled. */
1186
- interface WidgetSize {
1187
- width: number;
1188
- height: number;
1189
- }
1190
- /**
1191
- * User-changeable preferences. Sent to the backend on every request as a
1192
- * `userPrefs` field so the server can detect drift (e.g. user changed
1193
- * locale on another tab) and reconcile.
1194
- *
1195
- * Every field is optional — an unset key inherits the server / page-owner
1196
- * default. Empty object `{}` means "no preference recorded yet."
1197
- */
1198
- interface UserPrefs {
1199
- /** BCP-47 tag picked from the language switcher. */
1200
- locale?: string;
1201
- /** Drag-resized panel dimensions. */
1202
- widgetSize?: WidgetSize;
1203
- /** Sound on/off toggle (icon button). */
1204
- soundMuted?: boolean;
1205
- /** Theme picked from the theme switcher. */
1206
- themeMode?: "auto" | "light" | "dark";
1207
- /** Text size picked from the text-size switcher. */
1208
- textSize?: "small" | "normal" | "large";
1209
- }
1210
- //#endregion
1211
- //#region src/stream/types.d.ts
1212
- /** A 👍/👎 reaction on a rateable (assistant/operator) message; `null` clears a prior choice. */
1213
- type FeedbackValue = "up" | "down" | null;
1214
- //#endregion
1215
- //#region src/stream/protocol.d.ts
1216
- /**
1217
- * Who is driving replies in a conversation — the widget mirrors the backend `controlMode`.
1218
- * - `ai-agent`: the AI agent answers (normal operation).
1219
- * - `awaiting_operator`: operator-control requested, the AI no longer answers — the turn routes to the
1220
- * operator — while waiting in the operator queue.
1221
- * - `operator`: a workspace operator took over and is replying.
1222
- *
1223
- * Carried on `HandshakeResponse.controlState`, `LoadConversationResponse.controlState` (resume +
1224
- * history-switch), and the `data-control-state` stream part (on the reply stream). Absent / unknown →
1225
- * treated as `"ai-agent"`.
1226
- */
1227
- type ControlMode = "ai-agent" | "awaiting_operator" | "operator";
1228
- /**
1229
- * The control-state snapshot the widget reads to render composer/typing/banner state. The optional
1230
- * `operatorAvailable` (set on the operator-request response + the awaiting terminal part) tells the
1231
- * widget whether to show "connecting…" or the async-capture ("leave your details") copy.
1232
- */
1233
- interface ControlState {
1234
- controlMode: ControlMode;
1235
- /** Monotonic state version: orders received snapshots and fences request/cancel retries to their observed cycle. */
1236
- controlRevision?: number;
1237
- /**
1238
- * The operator's 2-letter initials (operator mode only) — shown in the bubble chrome + banner. The
1239
- * visitor never sees the full name (privacy); the backend derives the initials. `assignedOperatorId`
1240
- * also rides the wire but the widget doesn't render it, so it isn't modeled here.
1241
- */
1242
- assignedOperatorInitials?: string;
1243
- /** Whether anyone was in the operator pool when operator-control was requested (awaiting mode advisory). */
1244
- operatorAvailable?: boolean;
1245
- }
1246
- /** One-shot bot persona shown in the panel header. */
1247
- interface ConversationAgent {
1248
- name: string;
1249
- /** Image URL or data URI. When omitted, initials render from `name`. */
1250
- avatar?: string;
1251
- /** Subtitle ("AI Assistant", "Support team", …). */
1252
- title?: string;
1253
- /** Presence indicator. Default: `'online'`. */
1254
- status?: "online" | "away" | "offline";
1255
- }
1256
- /** A clickable quick-reply chip. */
1257
- interface ConversationSuggestion {
1258
- id: string;
1259
- /** What the chip displays. */
1260
- label: string;
1261
- /** What actually gets sent when clicked. Defaults to `label`. */
1262
- text?: string;
1263
- }
1264
- /** Welcome payload pushed into the message list on first open. */
1265
- interface ConversationWelcome {
1266
- messages?: Array<{
1267
- id: string;
1268
- role: "assistant" | "system";
1269
- text: string;
1270
- }>;
1271
- suggestions?: ConversationSuggestion[];
1272
- }
1273
- /**
1274
- * Response from `POST /pai/handshake` — the widget's one mount-time
1275
- * round-trip. Deliberately LIGHT: identity + deployment surface only
1276
- * (config, agent persona, welcome, page-mode site/blocks, userPrefs).
1277
- * The conversation THREAD is a separate, lazily-fetched read
1278
- * (`GET /conversation`) that only runs once the widget is activated
1279
- * (opened) — a closed launcher costs the page exactly one request.
1280
- *
1281
- * The `userPrefs` field (when present) is the server's authoritative
1282
- * copy of per-visitor preferences — the client should adopt it and update
1283
- * its local cache. Lets a user picking French on their phone see the
1284
- * widget in French when they open it on their laptop (assuming the same
1285
- * `visitorId`, e.g. via authenticated conversation — out of scope for v1).
1286
- */
1287
- interface HandshakeResponse$1 {
1288
- /**
1289
- * Public runtime conversation id. The widget mints this UUIDv7 and the backend
1290
- * validates that it belongs to the public deployment + visitor.
1291
- */
1292
- conversationId: string;
1293
- visitorId?: string;
1294
- /** Bot persona in the panel header (name, avatar, status). */
1295
- agent?: ConversationAgent;
1296
- /** Initial assistant messages + quick-reply chips. */
1297
- welcome?: ConversationWelcome;
1298
- /**
1299
- * Deployment-wide widget configuration the dashboard admin saved
1300
- * (mode / theme / launcher / actions / composer / features / …).
1301
- * Client adopts as defaults; customer's `init({...})` still wins
1302
- * per-field. Same for every visitor of this deployment.
1303
- */
1304
- config?: ServerConfig$1;
1305
- /** Page-mode site config (logo, title). Backend ships it whenever the deployment renders the page-shell sidebar. */
1306
- site?: Record<string, unknown>;
1307
- /** Page-mode sidebar blocks (navigation, link cards). Backend ships it whenever the deployment renders the page-shell sidebar. */
1308
- blocks?: Record<string, unknown>;
1309
- /** Current control state — seeds the composer/typing/banner state on connect. Absent → `ai-agent`. */
1310
- controlState?: ControlState;
1311
- /**
1312
- * Server's authoritative copy of the visitor's preferences. When present,
1313
- * client adopts it (overrides local cache) and re-applies it to the UI
1314
- * (locale, panel size, sound mute). Absent → client keeps its cache.
1315
- */
1316
- userPrefs?: UserPrefs;
1317
- /**
1318
- * Optional rebind metadata. When the server returns a `visitorId` /
1319
- * `conversationId` different from what the client sent, this block tells
1320
- * the client WHY — useful for telemetry and the `visitorRebound` /
1321
- * `conversationRebound` events fired into the host page. Server is free to
1322
- * omit it: the client detects rebinding by comparing request vs
1323
- * response ids regardless.
1324
- *
1325
- * Common reasons: `"conflict"` (the id collided with an existing
1326
- * record), `"expired"` (the id is too old to be re-used), `"invalid"`
1327
- * (malformed / not a UUIDv7). Custom strings are passed through to
1328
- * listeners verbatim.
1329
- */
1330
- rebind?: {
1331
- visitorId?: string;
1332
- conversationId?: string;
1333
- };
1334
- }
1335
- //#endregion
1336
- //#region src/core/events.d.ts
1337
- /**
1338
- * Payload shape per event. Keyed by event name; use `void` for events that
1339
- * carry no data.
1340
- *
1341
- * **Every user-visible action fires here.** Subscribe via
1342
- * `chat.on("eventName", fn)` to add analytics, side effects, or audit
1343
- * trails without forking the widget. The same names also stream to the
1344
- * structured logger at `info` level when `debug` is enabled.
1345
- */
1346
- interface EventMap {
1347
- /** Panel opened (floating / modal / drawer). */
1348
- open: void;
1349
- /** Panel closed. */
1350
- close: void;
1351
- /** Expanded mode toggled (1.5× size). Payload is the new state. */
1352
- expand: boolean;
1353
- /** Fullscreen mode toggled. Payload is the new state. */
1354
- fullscreen: boolean;
1355
- /** End-user dragged the resize grip — payload is the resolved size. */
1356
- resize: {
1357
- width: number;
1358
- height: number;
1359
- };
1360
- /** A message was exchanged. Fires for user, assistant, and operator messages. */
1361
- message: {
1362
- role: string;
1363
- text: string;
1364
- };
1365
- /** User submitted a message (fires before the request is sent). */
1366
- send: {
1367
- text: string;
1368
- attachmentCount: number;
1369
- };
1370
- /** User cancelled an in-flight stream. */
1371
- stop: void;
1372
- /** Clear / new-conversation requested. */
1373
- clear: void;
1374
- /** User picked a chat from the history pane / sidebar. */
1375
- selectConversation: {
1376
- conversationId: string;
1377
- };
1378
- /** User clicked a suggested-message chip. */
1379
- suggestion: {
1380
- text: string;
1381
- };
1382
- /** History pane toggled. Payload is the resulting view. */
1383
- toggleHistory: {
1384
- view: "chat" | "history";
1385
- };
1386
- /** A form (intake, CSAT, …) was completed or skipped. */
1387
- formSubmit: {
1388
- formId: string;
1389
- values: Record<string, string>;
1390
- skipped: boolean;
1391
- };
1392
- /** User answered an ask-questions tool request (re-POST follows). */
1393
- toolResult: {
1394
- toolCallId: string;
1395
- };
1396
- /** User approved / rejected a gated tool call (re-POST follows). */
1397
- toolDecision: {
1398
- toolCallId: string;
1399
- approved: boolean;
1400
- };
1401
- /**
1402
- * User gave feedback on a rateable reply (AI or operator). `value` is `"up"` / `"down"`, or
1403
- * `null` when they cleared a prior choice. `messageId` is the backend message
1404
- * id. Also POSTed best-effort to `/pai/message-feedback`; a host listener can
1405
- * mirror it to analytics.
1406
- */
1407
- messageFeedback: {
1408
- messageId: string;
1409
- value: FeedbackValue;
1410
- };
1411
- /** A content list (news / help / home block) rendered. */
1412
- contentView: {
1413
- section: string;
1414
- tags?: string;
1415
- count: number;
1416
- };
1417
- /** An article / content item was opened. */
1418
- contentOpen: {
1419
- contentId: string;
1420
- tags?: string;
1421
- };
1422
- /** The help search ran. Length + hit count only — never the query text. */
1423
- contentSearch: {
1424
- queryLength: number;
1425
- hitCount: number;
1426
- };
1427
- /** An opened article was read (dwell threshold passed). Fires once per open. */
1428
- contentRead: {
1429
- contentId: string;
1430
- };
1431
- /** A link inside an opened article was followed. */
1432
- contentLinkClick: {
1433
- contentId: string;
1434
- };
1435
- /** Files attached (drag-drop, file picker, paste). */
1436
- attach: {
1437
- count: number;
1438
- totalBytes: number;
1439
- };
1440
- /** An attachment was removed before send. */
1441
- removeAttachment: {
1442
- id: string;
1443
- };
1444
- /** Voice recording started. */
1445
- voiceStart: void;
1446
- /** Voice recording stopped and was sent for transcription. */
1447
- voiceStop: {
1448
- durationMs: number;
1449
- };
1450
- /** Voice recording cancelled (e.g. user released outside the button). */
1451
- voiceCancel: void;
1452
- /** End-user picked a different UI locale. Payload is the new BCP-47 tag. */
1453
- localeChange: string;
1454
- /** End-user picked a different theme mode (`auto` / `light` / `dark`). */
1455
- themeChange: ThemePreference;
1456
- /** End-user picked a different text size (`small` / `normal` / `large`). */
1457
- textSizeChange: TextSize;
1458
- /** End-user toggled the global sound mute. */
1459
- soundToggle: {
1460
- muted: boolean;
1461
- };
1462
- /** Page-mode sidebar collapsed / expanded. */
1463
- sidebarToggle: {
1464
- collapsed: boolean;
1465
- };
1466
- /** Pre-engagement launcher callout dismissed. */
1467
- calloutDismiss: void;
1468
- /** An unhandled error occurred somewhere in the transport or UI. */
1469
- error: unknown;
1470
- /** Connect bootstrap succeeded. Payload is the typed server response. */
1471
- handshake: HandshakeResponse$1;
1472
- /**
1473
- * Server rebound the `visitorId` — e.g. the client-minted id
1474
- * conflicted with an existing record, was expired, or otherwise
1475
- * rejected, and the server returned a fresh one in the
1476
- * `/handshake` response. The widget has already adopted the new
1477
- * id and persisted it; this event is informational so host pages
1478
- * can re-link analytics / external systems that pinned the
1479
- * previous value.
1480
- *
1481
- * `reason` is the server's explanation, when provided
1482
- * (`rebind.visitorId` in the handshake response). Common values:
1483
- * `"conflict"` / `"expired"` / `"invalid"`. May be `undefined` if
1484
- * the server didn't include a `rebind` block.
1485
- */
1486
- visitorRebound: {
1487
- previous: string;
1488
- current: string;
1489
- reason?: string;
1490
- };
1491
- /**
1492
- * Server rebound the `conversationId` — same shape and semantics as
1493
- * `visitorRebound` but for the conversation-thread id. Fires when
1494
- * the server's response carries a different `conversationId` than the
1495
- * client sent.
1496
- */
1497
- conversationRebound: {
1498
- previous: string;
1499
- current: string;
1500
- reason?: string;
1501
- };
1502
- }
1503
- type EventName = keyof EventMap;
1504
- //#endregion
1505
- //#region src/ui/host-mode.d.ts
1506
- type HostMode = "page" | "standalone" | "inline" | "modal" | "drawer" | "fullscreen" | "expanded" | "open" | "closed";
1507
- //#endregion
1508
- //#region src/boot.d.ts
1509
- /**
1510
- * Determine what `data-mode` the host should start at — matching what App's
1511
- * mount-time `useEffect` will produce on its first render. Used for the initial
1512
- * paint in both entry points (and `mount()`'s iframe sizing); after that, App
1513
- * owns `data-mode` for the lifetime of the instance.
1514
- *
1515
- * `resolveInitialPanelState` is the one source of truth for "what does the first
1516
- * render look like" — App.tsx uses it too. If these two paths ever pick
1517
- * different initial states, an iframe physically resizes between mount and App's
1518
- * first effect (the closed→open→closed flicker this pins against).
1519
- */
1520
- declare function resolveInitialHostMode(options: ResolvedOptions): HostMode;
1521
- //#endregion
1522
- //#region src/core/hooks.d.ts
1523
- /** Wildcard that matches every widget id / every event name. */
1524
- declare const HOOK_WILDCARD = "*";
1525
- /**
1526
- * Unified lifecycle callback signature. `data` is `unknown` — narrow it
1527
- * via the `event` discriminator using {@link EventMap} if needed:
1528
- *
1529
- * ```ts
1530
- * HelpAI.hook("*", "*", (inst, event, data) => {
1531
- * if (event === "message") {
1532
- * const msg = data as EventMap["message"]; // { role, text }
1533
- * // ...
1534
- * }
1535
- * });
1536
- * ```
1537
- */
1538
- type HookListener = (instance: ChatWidgetInstance, event: EventName, data: unknown) => void;
1539
- //#endregion
1540
1148
  //#region src/schema/primitives.d.ts
1541
1149
  /** A single image asset (logo, hero, icon). */
1542
1150
  declare const assetSchema: z.ZodObject<{
@@ -3484,20 +3092,194 @@ declare const handshakeResponseSchema: z.ZodObject<{
3484
3092
  conversationId: z.ZodString;
3485
3093
  userPrefs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
3486
3094
  rebind: z.ZodOptional<z.ZodObject<{
3487
- visitorId: z.ZodOptional<z.ZodEnum<{
3488
- conflict: "conflict";
3489
- expired: "expired";
3490
- invalid: "invalid";
3491
- }>>;
3492
- conversationId: z.ZodOptional<z.ZodEnum<{
3493
- conflict: "conflict";
3494
- expired: "expired";
3495
- invalid: "invalid";
3496
- }>>;
3497
- }, z.core.$loose>>;
3095
+ conversationId: z.ZodString;
3096
+ }, z.core.$strict>>;
3498
3097
  }, z.core.$loose>;
3499
3098
  type HandshakeResponse = z.infer<typeof handshakeResponseSchema>;
3500
3099
  //#endregion
3100
+ //#region src/stream/types.d.ts
3101
+ /** A 👍/👎 reaction on a rateable (assistant/operator) message; `null` clears a prior choice. */
3102
+ type FeedbackValue = "up" | "down" | null;
3103
+ //#endregion
3104
+ //#region src/core/events.d.ts
3105
+ /**
3106
+ * Payload shape per event. Keyed by event name; use `void` for events that
3107
+ * carry no data.
3108
+ *
3109
+ * **Every user-visible action fires here.** Subscribe via
3110
+ * `chat.on("eventName", fn)` to add analytics, side effects, or audit
3111
+ * trails without forking the widget. The same names also stream to the
3112
+ * structured logger at `info` level when `debug` is enabled.
3113
+ */
3114
+ interface EventMap {
3115
+ /** Panel opened (floating / modal / drawer). */
3116
+ open: void;
3117
+ /** Panel closed. */
3118
+ close: void;
3119
+ /** Expanded mode toggled (1.5× size). Payload is the new state. */
3120
+ expand: boolean;
3121
+ /** Fullscreen mode toggled. Payload is the new state. */
3122
+ fullscreen: boolean;
3123
+ /** End-user dragged the resize grip — payload is the resolved size. */
3124
+ resize: {
3125
+ width: number;
3126
+ height: number;
3127
+ };
3128
+ /** A message was exchanged. Fires for user, assistant, and operator messages. */
3129
+ message: {
3130
+ role: string;
3131
+ text: string;
3132
+ };
3133
+ /** User submitted a message (fires before the request is sent). */
3134
+ send: {
3135
+ text: string;
3136
+ attachmentCount: number;
3137
+ };
3138
+ /** User cancelled an in-flight stream. */
3139
+ stop: void;
3140
+ /** Clear / new-conversation requested. */
3141
+ clear: void;
3142
+ /** User picked a chat from the history pane / sidebar. */
3143
+ selectConversation: {
3144
+ conversationId: string;
3145
+ };
3146
+ /** User clicked a suggested-message chip. */
3147
+ suggestion: {
3148
+ text: string;
3149
+ };
3150
+ /** History pane toggled. Payload is the resulting view. */
3151
+ toggleHistory: {
3152
+ view: "chat" | "history";
3153
+ };
3154
+ /** A form (intake, CSAT, …) was completed or skipped. */
3155
+ formSubmit: {
3156
+ formId: string;
3157
+ values: Record<string, string>;
3158
+ skipped: boolean;
3159
+ };
3160
+ /** User answered an ask-questions tool request (re-POST follows). */
3161
+ toolResult: {
3162
+ toolCallId: string;
3163
+ };
3164
+ /** User approved / rejected a gated tool call (re-POST follows). */
3165
+ toolDecision: {
3166
+ toolCallId: string;
3167
+ approved: boolean;
3168
+ };
3169
+ /**
3170
+ * User gave feedback on a rateable reply (AI or operator). `value` is `"up"` / `"down"`, or
3171
+ * `null` when they cleared a prior choice. `messageId` is the backend message
3172
+ * id. Also POSTed best-effort to `/pai/message-feedback`; a host listener can
3173
+ * mirror it to analytics.
3174
+ */
3175
+ messageFeedback: {
3176
+ messageId: string;
3177
+ value: FeedbackValue;
3178
+ };
3179
+ /** A content list (news / help / home block) rendered. */
3180
+ contentView: {
3181
+ section: string;
3182
+ tags?: string;
3183
+ count: number;
3184
+ };
3185
+ /** An article / content item was opened. */
3186
+ contentOpen: {
3187
+ contentId: string;
3188
+ tags?: string;
3189
+ };
3190
+ /** The help search ran. Length + hit count only — never the query text. */
3191
+ contentSearch: {
3192
+ queryLength: number;
3193
+ hitCount: number;
3194
+ };
3195
+ /** An opened article was read (dwell threshold passed). Fires once per open. */
3196
+ contentRead: {
3197
+ contentId: string;
3198
+ };
3199
+ /** A link inside an opened article was followed. */
3200
+ contentLinkClick: {
3201
+ contentId: string;
3202
+ };
3203
+ /** Files attached (drag-drop, file picker, paste). */
3204
+ attach: {
3205
+ count: number;
3206
+ totalBytes: number;
3207
+ };
3208
+ /** An attachment was removed before send. */
3209
+ removeAttachment: {
3210
+ id: string;
3211
+ };
3212
+ /** Voice recording started. */
3213
+ voiceStart: void;
3214
+ /** Voice recording stopped and was sent for transcription. */
3215
+ voiceStop: {
3216
+ durationMs: number;
3217
+ };
3218
+ /** Voice recording cancelled (e.g. user released outside the button). */
3219
+ voiceCancel: void;
3220
+ /** End-user picked a different UI locale. Payload is the new BCP-47 tag. */
3221
+ localeChange: string;
3222
+ /** End-user picked a different theme mode (`auto` / `light` / `dark`). */
3223
+ themeChange: ThemePreference;
3224
+ /** End-user picked a different text size (`small` / `normal` / `large`). */
3225
+ textSizeChange: TextSize;
3226
+ /** End-user toggled the global sound mute. */
3227
+ soundToggle: {
3228
+ muted: boolean;
3229
+ };
3230
+ /** Page-mode sidebar collapsed / expanded. */
3231
+ sidebarToggle: {
3232
+ collapsed: boolean;
3233
+ };
3234
+ /** Pre-engagement launcher callout dismissed. */
3235
+ calloutDismiss: void;
3236
+ /** An unhandled error occurred somewhere in the transport or UI. */
3237
+ error: unknown;
3238
+ /** Connect bootstrap succeeded. Payload is the typed server response. */
3239
+ handshake: HandshakeResponse;
3240
+ /** Server replaced the requested conversationId and the widget adopted it. */
3241
+ conversationRebound: {
3242
+ previous: string;
3243
+ current: string;
3244
+ };
3245
+ }
3246
+ type EventName = keyof EventMap;
3247
+ //#endregion
3248
+ //#region src/ui/host-mode.d.ts
3249
+ type HostMode = "page" | "standalone" | "inline" | "modal" | "drawer" | "fullscreen" | "expanded" | "open" | "closed";
3250
+ //#endregion
3251
+ //#region src/boot.d.ts
3252
+ /**
3253
+ * Determine what `data-mode` the host should start at — matching what App's
3254
+ * mount-time `useEffect` will produce on its first render. Used for the initial
3255
+ * paint in both entry points (and `mount()`'s iframe sizing); after that, App
3256
+ * owns `data-mode` for the lifetime of the instance.
3257
+ *
3258
+ * `resolveInitialPanelState` is the one source of truth for "what does the first
3259
+ * render look like" — App.tsx uses it too. If these two paths ever pick
3260
+ * different initial states, an iframe physically resizes between mount and App's
3261
+ * first effect (the closed→open→closed flicker this pins against).
3262
+ */
3263
+ declare function resolveInitialHostMode(options: ResolvedOptions): HostMode;
3264
+ //#endregion
3265
+ //#region src/core/hooks.d.ts
3266
+ /** Wildcard that matches every widget id / every event name. */
3267
+ declare const HOOK_WILDCARD = "*";
3268
+ /**
3269
+ * Unified lifecycle callback signature. `data` is `unknown` — narrow it
3270
+ * via the `event` discriminator using {@link EventMap} if needed:
3271
+ *
3272
+ * ```ts
3273
+ * HelpAI.hook("*", "*", (inst, event, data) => {
3274
+ * if (event === "message") {
3275
+ * const msg = data as EventMap["message"]; // { role, text }
3276
+ * // ...
3277
+ * }
3278
+ * });
3279
+ * ```
3280
+ */
3281
+ type HookListener = (instance: ChatWidgetInstance, event: EventName, data: unknown) => void;
3282
+ //#endregion
3501
3283
  //#region src/index.d.ts
3502
3284
  /**
3503
3285
  * Handle returned by {@link mount} / {@link init}. All methods are safe to call