@helpai/elements 0.26.0 → 0.28.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
@@ -1,4 +1,4 @@
1
- export { A as Asset, B as BlocksConfig, C as ConnectionConfig, a as ConnectionConfigPartial, H as HandshakeResponse, L as Link, S as ServerConfig, b as SiteConfig, W as WidgetConfig, c as WidgetConfigPartial, d as WidgetSettings, e as WidgetSettingsPartial } from './deployment-2pMWV4oW.js';
1
+ export { A as Asset, B as BlocksConfig, C as ConnectionConfig, a as ConnectionConfigPartial, H as HandshakeResponse, L as Link, S as ServerConfig, b as SiteConfig, W as WidgetConfig, c as WidgetConfigPartial, d as WidgetSettings, e as WidgetSettingsPartial } from './deployment-E-Jyc0nF.js';
2
2
  import 'zod';
3
3
 
4
4
  /**
@@ -146,7 +146,7 @@ interface ConversationWelcome {
146
146
  suggestions?: ConversationSuggestion[];
147
147
  }
148
148
  /**
149
- * Response from `POST /ai-agent/handshake` — the widget's one mount-time
149
+ * Response from `POST /pai/handshake` — the widget's one mount-time
150
150
  * round-trip. Deliberately LIGHT: identity + deployment surface only
151
151
  * (config, agent persona, welcome, page-mode site/blocks, userPrefs).
152
152
  * The conversation THREAD is a separate, lazily-fetched read
@@ -896,14 +896,14 @@ interface PageContext {
896
896
  /**
897
897
  * Override the HTTP endpoints the widget calls. `upload` / `transcribe`
898
898
  * paths are appended to the agent base (`${baseUrl}/api/agent`);
899
- * `submitForm` is appended to the data base (`dataBaseUrl`). Absolute URLs
899
+ * `submitForm` is appended to the data base (`dataApiBaseUrl`). Absolute URLs
900
900
  * also work (useful when the upload endpoint lives on a different origin
901
901
  * like a CDN presign service).
902
902
  */
903
903
  interface Endpoints {
904
- /** File upload endpoint. Default: `'/ai-agent/upload-file'`. */
904
+ /** File upload endpoint. Default: `'/pai/upload-file'`. */
905
905
  upload?: string;
906
- /** Voice transcription endpoint. Default: `'/ai-agent/transcribe-audio'`. */
906
+ /** Voice transcription endpoint. Default: `'/pai/transcribe-audio'`. */
907
907
  transcribe?: string;
908
908
  /**
909
909
  * Form submission endpoint. Default: `'/submit-form'`. When any form
@@ -933,13 +933,14 @@ interface Endpoints {
933
933
  /** Section: anonymous owner-facing usage tracking. */
934
934
  interface TrackingOptions {
935
935
  /**
936
- * Master switch. Default `false` — tracking stays off until the
937
- * deployment (or the embedding page) explicitly turns it on.
936
+ * Master switch. Default `true` — the widget always fires; the data
937
+ * module gates ingestion per deployment server-side. Set `false`
938
+ * (deployment config or init) to silence the client entirely.
938
939
  */
939
940
  enabled?: boolean;
940
941
  /**
941
- * Pixel collector URL. Default: `${dataBaseUrl}/elements/px.gif`
942
- * (e.g. `https://help.ai/api/data/elements/px.gif`).
942
+ * Pixel collector URL. Default: `${dataApiBaseUrl}/pai/elements-px.gif`
943
+ * (e.g. `https://help.ai/api/data/pai/elements-px.gif`).
943
944
  */
944
945
  endpoint?: string;
945
946
  /**
@@ -1015,22 +1016,22 @@ interface ChatWidgetOptions {
1015
1016
  * Agent-API base (no trailing slash) — set it when the
1016
1017
  * `module-help-ai-agent-api` service is reached DIRECTLY (a standalone
1017
1018
  * local module, e.g. `http://localhost:3087`) instead of through the
1018
- * edge. Routes attach as-is (`${agentBaseUrl}/ai-agent/handshake`).
1019
+ * edge. Routes attach as-is (`${agentApiBaseUrl}/pai/handshake`).
1019
1020
  * Precedence: this option > derived from the main origin
1020
1021
  * (`${baseUrl}/api/agent`). Not server-pushable — the handshake already
1021
1022
  * travelled over it.
1022
1023
  */
1023
- agentBaseUrl?: string;
1024
+ agentApiBaseUrl?: string;
1024
1025
  /**
1025
1026
  * Data-API base (no trailing slash) — the `module-help-ai-data-api`
1026
1027
  * service serving content, form definitions, and form submissions at
1027
1028
  * root-level paths (`/content`, `/forms`, `/activity`, `/submit-form`).
1028
1029
  * Set it for a standalone local module (e.g. `http://localhost:3106`).
1029
- * Precedence: this option > server-pushed `config.dataBaseUrl` > derived
1030
+ * Precedence: this option > server-pushed `config.dataApiBaseUrl` > derived
1030
1031
  * from the main origin (`${baseUrl}/api/data`, e.g.
1031
1032
  * `https://help.ai/api/data`).
1032
1033
  */
1033
- dataBaseUrl?: string;
1034
+ dataApiBaseUrl?: string;
1034
1035
  /** Host-asserted, informational end-user context (untrusted; not auth). */
1035
1036
  userContext?: UserContext;
1036
1037
  /** Host-asserted, informational page/visit context (untrusted; `area`, url, …). */
@@ -1085,10 +1086,10 @@ interface ResolvedOptions {
1085
1086
  publicKey?: string;
1086
1087
  aiAgentDeploymentId?: string;
1087
1088
  baseUrl: string;
1088
- /** Resolved agent-API base — see {@link ChatWidgetOptions.agentBaseUrl}. */
1089
- agentBaseUrl: string;
1090
- /** Resolved data-API base — see {@link ChatWidgetOptions.dataBaseUrl}. */
1091
- dataBaseUrl: string;
1089
+ /** Resolved agent-API base — see {@link ChatWidgetOptions.agentApiBaseUrl}. */
1090
+ agentApiBaseUrl: string;
1091
+ /** Resolved data-API base — see {@link ChatWidgetOptions.dataApiBaseUrl}. */
1092
+ dataApiBaseUrl: string;
1092
1093
  userContext?: UserContext;
1093
1094
  pageContext?: PageContext;
1094
1095
  position: Position;
@@ -1187,7 +1188,7 @@ interface ResolvedOptions {
1187
1188
  */
1188
1189
  interface ServerConfig {
1189
1190
  /** Data-API base override — adopted only when the host didn't set one. */
1190
- dataBaseUrl?: string;
1191
+ dataApiBaseUrl?: string;
1191
1192
  presentation?: PresentationOptions;
1192
1193
  behavior?: BehaviorOptions;
1193
1194
  theme?: ThemePreference | ThemeOverrides;
package/index.mjs CHANGED
@@ -476,13 +476,13 @@ var DEFAULT_FEATURES = {
476
476
  };
477
477
  var DEFAULT_FORMS = { list: [], byTrigger: {} };
478
478
  var DEFAULT_TRACKING = {
479
- enabled: false,
479
+ enabled: true,
480
480
  sampleRate: 1
481
481
  };
482
482
  var DEFAULT_ENDPOINTS = {
483
- upload: "/ai-agent/upload-file",
484
- transcribe: "/ai-agent/transcribe-audio",
485
- submitForm: "/submit-form"
483
+ upload: "/pai/upload-file",
484
+ transcribe: "/pai/transcribe-audio",
485
+ submitForm: "/pai/submit-form"
486
486
  };
487
487
  var DEFAULT_LAUNCHER = {
488
488
  variant: "circle",
@@ -525,15 +525,15 @@ function resolveOptions(rawOpts) {
525
525
  const locale = i18n.locale ?? resolveDefaultLocale(i18n.defaultLocale);
526
526
  const availableLocales = i18n.availableLocales ?? [locale];
527
527
  const baseUrl = (opts.baseUrl ?? BRAND.defaultBaseUrl).replace(/\/$/, "");
528
- const agentBaseUrl = (opts.agentBaseUrl ?? `${baseUrl}/api/agent`).replace(/\/$/, "");
529
- const dataBaseUrl = (opts.dataBaseUrl ?? `${baseUrl}/api/data`).replace(/\/$/, "");
528
+ const agentApiBaseUrl = (opts.agentApiBaseUrl ?? `${baseUrl}/api/agent`).replace(/\/$/, "");
529
+ const dataApiBaseUrl = (opts.dataApiBaseUrl ?? `${baseUrl}/api/data`).replace(/\/$/, "");
530
530
  return {
531
531
  widgetId: opts.widgetId ?? "default",
532
532
  publicKey: opts.publicKey,
533
533
  aiAgentDeploymentId: opts.aiAgentDeploymentId,
534
534
  baseUrl,
535
- agentBaseUrl,
536
- dataBaseUrl,
535
+ agentApiBaseUrl,
536
+ dataApiBaseUrl,
537
537
  userContext: sanitizeUserContext(opts.userContext),
538
538
  pageContext: sanitizePageContext(opts.pageContext),
539
539
  position: presentation.position ?? "bottom-right",
@@ -578,7 +578,7 @@ function resolveOptions(rawOpts) {
578
578
  poweredBy: resolvePoweredBy(footer.poweredBy),
579
579
  composer: resolveComposer(opts.composer),
580
580
  modules: resolveModules(opts.modules),
581
- tracking: resolveTracking(opts.tracking, dataBaseUrl),
581
+ tracking: resolveTracking(opts.tracking, dataApiBaseUrl),
582
582
  storage: opts.storage ?? defaultStorage,
583
583
  onMessage: opts.onMessage,
584
584
  onOpen: opts.onOpen,
@@ -611,13 +611,13 @@ function resolveHaptics(overrides) {
611
611
  events: overrides?.events
612
612
  };
613
613
  }
614
- function resolveTracking(overrides, dataBaseUrl) {
614
+ function resolveTracking(overrides, dataApiBaseUrl) {
615
615
  const sampleRate = overrides?.sampleRate ?? DEFAULT_TRACKING.sampleRate;
616
616
  return {
617
617
  enabled: overrides?.enabled ?? DEFAULT_TRACKING.enabled,
618
- // The collector rides the data module — `${dataBaseUrl}/elements/px.gif`
619
- // (e.g. `https://help.ai/api/data/elements/px.gif`).
620
- endpoint: overrides?.endpoint ?? `${dataBaseUrl}/elements/px.gif`,
618
+ // The collector rides the data module — `${dataApiBaseUrl}/pai/elements-px.gif`
619
+ // (e.g. `https://help.ai/api/data/pai/elements-px.gif`).
620
+ endpoint: overrides?.endpoint ?? `${dataApiBaseUrl}/pai/elements-px.gif`,
621
621
  // Clamp instead of reject — a malformed rate must never turn a
622
622
  // disabled tracker on or crash resolve (no Zod on the IIFE path).
623
623
  sampleRate: Math.min(1, Math.max(0, Number.isFinite(sampleRate) ? sampleRate : 1)),
@@ -786,7 +786,8 @@ function mergeServerConfig(user, server) {
786
786
  out[key] = mergeLeaves(sv, uv);
787
787
  }
788
788
  if (server.modules !== void 0 && user.modules === void 0) out.modules = server.modules;
789
- if (server.dataBaseUrl !== void 0 && user.dataBaseUrl === void 0) out.dataBaseUrl = server.dataBaseUrl;
789
+ if (server.dataApiBaseUrl !== void 0 && user.dataApiBaseUrl === void 0)
790
+ out.dataApiBaseUrl = server.dataApiBaseUrl;
790
791
  const userI18n = user.i18n;
791
792
  const serverI18n = server.i18n;
792
793
  if (userI18n || serverI18n) {
@@ -846,8 +847,8 @@ var EMBED_SCALAR_ATTRS = [
846
847
  ["public-key", "publicKey"],
847
848
  ["ai-agent-deployment-id", "aiAgentDeploymentId"],
848
849
  ["base-url", "baseUrl"],
849
- ["agent-base-url", "agentBaseUrl"],
850
- ["data-base-url", "dataBaseUrl"],
850
+ ["agent-api-base-url", "agentApiBaseUrl"],
851
+ ["data-api-base-url", "dataApiBaseUrl"],
851
852
  ["theme", "theme", (v) => v]
852
853
  ];
853
854
  var PRESENTATION_ATTRS = [
@@ -1253,63 +1254,61 @@ function parseWireDate(value) {
1253
1254
  }
1254
1255
  var DEFAULT_PATHS = {
1255
1256
  /** Conversation bootstrap. `POST` → deployment config + per-visitor state. */
1256
- handshake: "/ai-agent/handshake",
1257
+ handshake: "/pai/handshake",
1257
1258
  /** Send a message + stream the reply (SSE). `POST`. */
1258
- streamMessage: "/ai-agent/stream-message",
1259
+ streamMessage: "/pai/stream-message",
1259
1260
  /**
1260
1261
  * Resume an interrupted reply. `GET` (envelope rides as query params).
1261
1262
  * Stateless: the server re-streams the whole reply SSE again from the start —
1262
1263
  * there is NO `Last-Event-ID`. The client reconciles by id (`seenIds`), so
1263
1264
  * replayed events are skipped and only the continuation surfaces.
1264
1265
  */
1265
- streamResume: "/ai-agent/stream-resume",
1266
+ streamResume: "/pai/stream-resume",
1266
1267
  /** Abort the in-flight reply stream. `POST`. */
1267
- cancelStream: "/ai-agent/cancel-stream",
1268
+ cancelStream: "/pai/cancel-stream",
1268
1269
  /** List the visitor's conversations. `GET`. */
1269
- listConversations: "/ai-agent/list-conversations",
1270
+ listConversations: "/pai/list-conversations",
1270
1271
  /** Load one conversation's thread (messages + canContinue + suggestions). `GET ?conversationId=…`. */
1271
- listMessages: "/ai-agent/list-messages",
1272
+ listMessages: "/pai/list-messages",
1272
1273
  /**
1273
1274
  * Persist a user-driven settings change. POST `{ visitorId, userPrefs }` →
1274
1275
  * server persists, returns the merged authoritative copy. Fire-and-forget on
1275
1276
  * the client — a failure leaves the local cache valid; the next
1276
1277
  * `handshake()` reconciles.
1277
1278
  */
1278
- updateSettings: "/ai-agent/update-settings",
1279
+ updateSettings: "/pai/update-settings",
1279
1280
  /**
1280
1281
  * Mark a conversation read. POST `{ visitorId, conversationId }` → the server
1281
1282
  * records `lastReadAt = now` for that (visitor, conversation) and recomputes
1282
1283
  * `unreadCount` (returned on `/list-conversations`) accordingly. Fire-and-forget
1283
1284
  * on the client; a failure just leaves the badge until the next sync.
1284
1285
  */
1285
- markRead: "/ai-agent/mark-read",
1286
- // ── Data API (module-help-ai-data-api, via `dataBaseUrl`) ─────────
1287
- /** All widget content via one filtered endpoint. `GET /content?tags=…`. */
1288
- content: "/content",
1286
+ markRead: "/pai/mark-read",
1287
+ // ── Data API (module-help-ai-data-api, via `dataApiBaseUrl`) ─────────
1288
+ /**
1289
+ * The data module's one ACTIVATION read. `GET
1290
+ * /pai/bootstrap?visitorId=…&conversationId=…` →
1291
+ * `{ forms, formSubmissions }`: the deployment's resolved form
1292
+ * definitions plus the visitor's recorded submissions for the envelope's
1293
+ * conversation (chronological — they rebuild the timeline markers).
1294
+ * Also re-read with an explicit `conversationId` selector on a
1295
+ * history-pane thread switch. A failure is treated as "no forms, no
1296
+ * records" (non-fatal) — the chat works regardless.
1297
+ */
1298
+ bootstrap: "/pai/bootstrap",
1289
1299
  /**
1290
- * Resolved form definitions for the deployment. `GET /forms`
1291
- * `{ forms: FormDef[] }`. Fetched once at boot (in parallel with
1292
- * handshake); form gating waits for it. A failure is treated as
1293
- * "no forms" (non-fatal).
1300
+ * All widget content via one filtered endpoint content stays OUT of the
1301
+ * bootstrap because its reads are query-driven (`tags` / `categories` /
1302
+ * `ids` / `search` + pagination). `GET /pai/content?tags=…`.
1294
1303
  */
1295
- forms: "/forms",
1304
+ content: "/pai/content",
1296
1305
  /**
1297
1306
  * Form submission (the event-driven forms engine). POST `{ visitorId,
1298
1307
  * conversationId, formId, trigger, values, skipped? }` → record the form's answers
1299
1308
  * immediately, keyed by the same `visitorId` + `conversationId` the chat uses.
1300
1309
  * Overridable via `endpoints.submitForm`. Fire-and-forget; 404 is ignored.
1301
1310
  */
1302
- submitForm: "/submit-form",
1303
- /**
1304
- * Visitor interaction records for a conversation. `GET
1305
- * /activity?visitorId=…&conversationId=…` →
1306
- * `{ formSubmissions: FormSubmissionRecord[] }` (chronological). Replaces
1307
- * the former `formSubmissions` echo on the handshake / list-messages;
1308
- * deliberately generic — future visitor interaction records ride the same
1309
- * endpoint. A failure (e.g. 404 `AI_AGENT_PUBLIC_ACCESS_NOT_FOUND` when the
1310
- * deployment doesn't resolve) is treated as "no records" (non-fatal).
1311
- */
1312
- activity: "/activity"
1311
+ submitForm: "/pai/submit-form"
1313
1312
  };
1314
1313
  var CONTEXT_PARAM = "context";
1315
1314
  function buildSendMessageRequest(params) {
@@ -1578,7 +1577,7 @@ var AgentTransport = class {
1578
1577
  }
1579
1578
  // ---- Data API (content / forms — module-help-ai-data-api) --------------
1580
1579
  //
1581
- // The DATA surfaces live on `dataBaseUrl` (default `${baseUrl}/api/data`)
1580
+ // The DATA surfaces live on `dataApiBaseUrl` (default `${baseUrl}/api/data`)
1582
1581
  // with ROOT-level paths — same auth headers + envelope, same retry
1583
1582
  // behavior. One endpoint for every content surface (Home / Help / News /
1584
1583
  // docs); callers pass filters; a thrown StreamError (e.g. 404 on an older
@@ -1598,38 +1597,26 @@ var AgentTransport = class {
1598
1597
  return { ...res, items };
1599
1598
  }
1600
1599
  /**
1601
- * Fetch the deployment's resolved form definitions. `GET /forms`
1602
- * (data-API). Replaces the former `config.forms` push on the handshake
1603
- * called once at boot, in parallel with `handshake`; form gating
1604
- * (pre-chat etc.) waits for it. Callers treat a thrown StreamError as
1605
- * "no forms" (non-fatal).
1606
- */
1607
- async listForms() {
1608
- log4.debug("listForms \u2192");
1609
- const res = await this.getJson(this.dataUrl(DEFAULT_PATHS.forms), "listForms");
1610
- const forms = res.forms ?? [];
1611
- log4.debug("listForms \u2190", { count: forms.length });
1612
- return { forms };
1613
- }
1614
- /**
1615
- * Fetch the visitor's recorded activity for a conversation — currently the
1616
- * form submissions that rebuild the collapsed "form submitted / skipped"
1617
- * timeline markers on resume. `GET /activity` (data-API); the
1618
- * envelope carries `visitorId` / `conversationId` as query params.
1619
- * `conversationId` here is an optional resource selector (a thread that may
1620
- * differ from the active conversation — the history-pane switch); when
1621
- * omitted, the envelope's active conversation applies. Callers treat a
1622
- * thrown StreamError (e.g. 404 on a deployment that doesn't resolve) as
1623
- * "no activity" (non-fatal).
1600
+ * The data module's ONE activation read. `GET /pai/bootstrap` (data-API)
1601
+ * the deployment's resolved form definitions + the visitor's recorded
1602
+ * form submissions for the envelope's conversation. The handshake
1603
+ * (agent-API) is completely independent of these surfaces.
1604
+ *
1605
+ * `conversationId` is an optional resource selector (a thread that may
1606
+ * differ from the active conversation — the history-pane switch re-reads
1607
+ * that thread's submissions); when omitted, the envelope's active
1608
+ * conversation applies. Callers treat a thrown StreamError (e.g. 404 on a
1609
+ * deployment that doesn't resolve) as "no forms, no records" (non-fatal).
1624
1610
  */
1625
- async getActivity(conversationId) {
1626
- const url = new URL(this.dataUrl(DEFAULT_PATHS.activity));
1611
+ async bootstrap(conversationId) {
1612
+ const url = new URL(this.dataUrl(DEFAULT_PATHS.bootstrap));
1627
1613
  if (conversationId) url.searchParams.set("conversationId", conversationId);
1628
- log4.debug("getActivity \u2192", { conversationId: conversationId ?? this.conversationId });
1629
- const res = await this.getJson(url.toString(), "getActivity");
1614
+ log4.debug("bootstrap \u2192", { conversationId: conversationId ?? this.conversationId });
1615
+ const res = await this.getJson(url.toString(), "bootstrap");
1616
+ const forms = res.forms ?? [];
1630
1617
  const formSubmissions = res.formSubmissions ?? [];
1631
- log4.debug("getActivity \u2190", { count: formSubmissions.length });
1632
- return { formSubmissions };
1618
+ log4.debug("bootstrap \u2190", { forms: forms.length, formSubmissions: formSubmissions.length });
1619
+ return { forms, formSubmissions };
1633
1620
  }
1634
1621
  async saveUserPrefs(userPrefs) {
1635
1622
  log4.debug("saveUserPrefs \u2192", {
@@ -1642,10 +1629,10 @@ var AgentTransport = class {
1642
1629
  return res;
1643
1630
  }
1644
1631
  get uploadPath() {
1645
- return this.opts.endpoints?.upload ?? "/ai-agent/upload-file";
1632
+ return this.opts.endpoints?.upload ?? "/pai/upload-file";
1646
1633
  }
1647
1634
  get transcribePath() {
1648
- return this.opts.endpoints?.transcribe ?? "/ai-agent/transcribe-audio";
1635
+ return this.opts.endpoints?.transcribe ?? "/pai/transcribe-audio";
1649
1636
  }
1650
1637
  get submitFormPath() {
1651
1638
  return this.opts.endpoints?.submitForm ?? DEFAULT_PATHS.submitForm;
@@ -1788,7 +1775,7 @@ var AgentTransport = class {
1788
1775
  }
1789
1776
  return false;
1790
1777
  }
1791
- /** Abort + fire-and-forget POST to `/ai-agent/cancel-stream`. Idempotent. */
1778
+ /** Abort + fire-and-forget POST to `/pai/cancel-stream`. Idempotent. */
1792
1779
  cancelStream(ctrl, conversationId) {
1793
1780
  if (ctrl.signal.aborted) return;
1794
1781
  log4.debug("cancel stream", { conversationId, visitorId: this.visitorId });
@@ -1898,12 +1885,12 @@ var AgentTransport = class {
1898
1885
  return await res.json();
1899
1886
  }
1900
1887
  /**
1901
- * Agent-API URL — resolves a `/ai-agent/*` path against the resolved
1888
+ * Agent-API URL — resolves a `/pai/*` path against the resolved
1902
1889
  * agent module base. Absolute URLs pass through unchanged.
1903
1890
  */
1904
1891
  url(pathOrUrl) {
1905
1892
  if (/^https?:\/\//i.test(pathOrUrl)) return pathOrUrl;
1906
- return `${this.opts.agentBaseUrl}${pathOrUrl}`;
1893
+ return `${this.opts.agentApiBaseUrl}${pathOrUrl}`;
1907
1894
  }
1908
1895
  /**
1909
1896
  * Data-API variant of {@link url} — resolves a root-level path (content /
@@ -1913,7 +1900,7 @@ var AgentTransport = class {
1913
1900
  */
1914
1901
  dataUrl(pathOrUrl) {
1915
1902
  if (/^https?:\/\//i.test(pathOrUrl)) return pathOrUrl;
1916
- return `${this.opts.dataBaseUrl}${pathOrUrl}`;
1903
+ return `${this.opts.dataApiBaseUrl}${pathOrUrl}`;
1917
1904
  }
1918
1905
  get fetchImpl() {
1919
1906
  return this.opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
@@ -6479,8 +6466,8 @@ function App({ options, hostElement, bus }) {
6479
6466
  const [formContext, setFormContext] = useState13({});
6480
6467
  const [transport] = useState13(
6481
6468
  () => new AgentTransport({
6482
- agentBaseUrl: options.agentBaseUrl,
6483
- dataBaseUrl: options.dataBaseUrl,
6469
+ agentApiBaseUrl: options.agentApiBaseUrl,
6470
+ dataApiBaseUrl: options.dataApiBaseUrl,
6484
6471
  auth: createAuth({
6485
6472
  publicKey: options.publicKey,
6486
6473
  aiAgentDeploymentId: options.aiAgentDeploymentId,
@@ -6561,10 +6548,11 @@ function App({ options, hostElement, bus }) {
6561
6548
  },
6562
6549
  [messagesSig]
6563
6550
  );
6551
+ const dataBootRef = useRef9(null);
6564
6552
  const fetchFormMarkers = useCallback6(
6565
6553
  async (conversationId) => {
6566
6554
  try {
6567
- const { formSubmissions: subs } = await transport.getActivity(conversationId);
6555
+ const { formSubmissions: subs } = await (conversationId ? transport.bootstrap(conversationId) : dataBootRef.current ?? transport.bootstrap());
6568
6556
  const lastIndexByForm = /* @__PURE__ */ new Map();
6569
6557
  subs.forEach((rec, i) => lastIndexByForm.set(rec.formId, i));
6570
6558
  return subs.filter((rec, i) => !rec.skipped || lastIndexByForm.get(rec.formId) === i).map((rec, i) => ({
@@ -6575,7 +6563,7 @@ function App({ options, hostElement, bus }) {
6575
6563
  values: rec.values
6576
6564
  }));
6577
6565
  } catch (err) {
6578
- log16.debug("getActivity failed \u2014 no form markers (non-fatal)", { err });
6566
+ log16.debug("bootstrap failed \u2014 no form markers (non-fatal)", { err });
6579
6567
  return [];
6580
6568
  }
6581
6569
  },
@@ -6764,12 +6752,13 @@ function App({ options, hostElement, bus }) {
6764
6752
  }, []);
6765
6753
  useEffect17(() => {
6766
6754
  if (!activated) return;
6755
+ dataBootRef.current = transport.bootstrap();
6767
6756
  void (async () => {
6768
6757
  try {
6769
- const res = await transport.listForms();
6770
- setRemoteForms(resolveForms(res.forms));
6758
+ const res = await dataBootRef.current;
6759
+ setRemoteForms(resolveForms((res ?? { forms: [] }).forms));
6771
6760
  } catch (err) {
6772
- log16.debug("listForms failed \u2014 treating as no forms", { err });
6761
+ log16.debug("bootstrap failed \u2014 treating as no forms", { err });
6773
6762
  } finally {
6774
6763
  setFormsReady(true);
6775
6764
  }
@@ -7154,6 +7143,20 @@ function App({ options, hostElement, bus }) {
7154
7143
  },
7155
7144
  [transport, messagesSig, conversationIdSig, bus, options, persistence, refreshUnread, fetchFormMarkers]
7156
7145
  );
7146
+ const pendingOpenFormRef = useRef9(null);
7147
+ const openForm = useCallback6(
7148
+ (id) => {
7149
+ if (typeof id !== "string") return;
7150
+ if (formsReady) forms.fire("manual", id);
7151
+ else pendingOpenFormRef.current = id;
7152
+ },
7153
+ [formsReady, forms]
7154
+ );
7155
+ useEffect17(() => {
7156
+ if (!formsReady || !pendingOpenFormRef.current) return;
7157
+ forms.fire("manual", pendingOpenFormRef.current);
7158
+ pendingOpenFormRef.current = null;
7159
+ }, [formsReady, forms]);
7157
7160
  useEffect17(() => {
7158
7161
  const unsub = bindHostCommands(hostElement, {
7159
7162
  open: handleOpen,
@@ -7161,10 +7164,10 @@ function App({ options, hostElement, bus }) {
7161
7164
  expand: handleExpand,
7162
7165
  fullscreen: handleFullscreen,
7163
7166
  popout: handlePopOut,
7164
- openForm: (id) => forms.fire("manual", typeof id === "string" ? id : void 0)
7167
+ openForm
7165
7168
  });
7166
7169
  return unsub;
7167
- }, [hostElement, handleOpen, handleClose, handleExpand, handleFullscreen, handlePopOut, forms]);
7170
+ }, [hostElement, handleOpen, handleClose, handleExpand, handleFullscreen, handlePopOut, openForm]);
7168
7171
  const effectiveOptions = useMemo3(
7169
7172
  () => applyOptionOverrides(options, activeLocale, activeThemeMode, activeTextSize),
7170
7173
  [options, activeLocale, activeThemeMode, activeTextSize]
package/package.json CHANGED
@@ -80,5 +80,5 @@
80
80
  ],
81
81
  "type": "module",
82
82
  "types": "./index.d.ts",
83
- "version": "0.26.0"
83
+ "version": "0.28.0"
84
84
  }
package/schema.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as Asset, B as BlocksConfig, C as ConnectionConfig, a as ConnectionConfigPartial, E as Endpoints, H as HandshakeResponse, L as Link, P as PAGE_AREA_SUGGESTIONS, f as PageContext, S as ServerConfig, b as SiteConfig, U as UserContext, W as WidgetConfig, c as WidgetConfigPartial, d as WidgetSettings, e as WidgetSettingsPartial, g as assetSchema, h as blocksConfigSchema, i as connectionConfigPartialSchema, j as connectionConfigSchema, k as cssColorSchema, l as cssLengthSchema, m as endpointsSchema, n as handshakeResponseSchema, o as linkSchema, p as localeSchema, q as pageContextSchema, s as serverConfigSchema, r as siteConfigSchema, u as userContextSchema, t as uuid7Schema, w as widgetConfigPartialSchema, v as widgetConfigSchema, x as widgetSettingsPartialSchema, y as widgetSettingsSchema } from './deployment-2pMWV4oW.js';
1
+ export { A as Asset, B as BlocksConfig, C as ConnectionConfig, a as ConnectionConfigPartial, E as Endpoints, H as HandshakeResponse, L as Link, P as PAGE_AREA_SUGGESTIONS, f as PageContext, S as ServerConfig, b as SiteConfig, U as UserContext, W as WidgetConfig, c as WidgetConfigPartial, d as WidgetSettings, e as WidgetSettingsPartial, g as assetSchema, h as blocksConfigSchema, i as connectionConfigPartialSchema, j as connectionConfigSchema, k as cssColorSchema, l as cssLengthSchema, m as endpointsSchema, n as handshakeResponseSchema, o as linkSchema, p as localeSchema, q as pageContextSchema, s as serverConfigSchema, r as siteConfigSchema, u as userContextSchema, t as uuid7Schema, w as widgetConfigPartialSchema, v as widgetConfigSchema, x as widgetSettingsPartialSchema, y as widgetSettingsSchema } from './deployment-E-Jyc0nF.js';
2
2
  import { z } from 'zod';
3
3
 
4
4
  /**
package/schema.json CHANGED
@@ -32,14 +32,14 @@
32
32
  "minLength": 1,
33
33
  "maxLength": 2048
34
34
  },
35
- "agentBaseUrl": {
36
- "description": "Full agent-API base — set it to reach a STANDALONE `module-help-ai-agent-api` directly (local module on its own port, e.g. `http://localhost:3087`; routes attach as-is: `/ai-agent/handshake`). Precedence: this option > derived from the main origin (`${baseUrl}/api/agent`). Not server-pushable.",
35
+ "agentApiBaseUrl": {
36
+ "description": "Full agent-API base — set it to reach a STANDALONE `module-help-ai-agent-api` directly (local module on its own port, e.g. `http://localhost:3087`; routes attach as-is: `/pai/handshake`). Precedence: this option > derived from the main origin (`${baseUrl}/api/agent`). Not server-pushable.",
37
37
  "type": "string",
38
38
  "minLength": 1,
39
39
  "maxLength": 2048
40
40
  },
41
- "dataBaseUrl": {
42
- "description": "Full data-API base (e.g. `https://help.ai/api/data`, or a standalone local module like `http://localhost:3106`) — the service serving content, form definitions (`GET /forms`), and form submissions at root-level paths. Precedence: this option > server-pushed `config.dataBaseUrl` > derived from the main origin (`${baseUrl}/api/data`).",
41
+ "dataApiBaseUrl": {
42
+ "description": "Full data-API base (e.g. `https://help.ai/api/data`, or a standalone local module like `http://localhost:3106`) — the service serving content, form definitions (`GET /forms`), and form submissions at root-level paths. Precedence: this option > server-pushed `config.dataApiBaseUrl` > derived from the main origin (`${baseUrl}/api/data`).",
43
43
  "type": "string",
44
44
  "minLength": 1,
45
45
  "maxLength": 2048
@@ -166,19 +166,19 @@
166
166
  "type": "object",
167
167
  "properties": {
168
168
  "upload": {
169
- "default": "/ai-agent/upload-file",
169
+ "default": "/pai/upload-file",
170
170
  "type": "string",
171
171
  "minLength": 1,
172
172
  "maxLength": 2048
173
173
  },
174
174
  "transcribe": {
175
- "default": "/ai-agent/transcribe-audio",
175
+ "default": "/pai/transcribe-audio",
176
176
  "type": "string",
177
177
  "minLength": 1,
178
178
  "maxLength": 2048
179
179
  },
180
180
  "submitForm": {
181
- "default": "/submit-form",
181
+ "default": "/pai/submit-form",
182
182
  "description": "Form submission endpoint. The widget POSTs each completed form's values here (fire-and-forget), keyed by the same visitorId + conversationId as the conversation; the payload carries `formId` + `trigger` so the backend can route. Optional — a 404 is ignored.",
183
183
  "type": "string",
184
184
  "minLength": 1,
@@ -191,11 +191,11 @@
191
191
  "submitForm"
192
192
  ],
193
193
  "additionalProperties": {},
194
- "description": "HTTP endpoint overrides. `upload` / `transcribe` paths are appended to the agent base (`${baseUrl}/api/agent`), `submitForm` to the data base (`dataBaseUrl`); absolute URLs are accepted too.",
194
+ "description": "HTTP endpoint overrides. `upload` / `transcribe` paths are appended to the agent base (`${baseUrl}/api/agent`), `submitForm` to the data base (`dataApiBaseUrl`); absolute URLs are accepted too.",
195
195
  "examples": [
196
196
  {
197
- "upload": "/ai-agent/upload-file",
198
- "transcribe": "/ai-agent/transcribe-audio"
197
+ "upload": "/pai/upload-file",
198
+ "transcribe": "/pai/transcribe-audio"
199
199
  },
200
200
  {
201
201
  "upload": "https://help.ai/uploads/presign"
@@ -1867,11 +1867,11 @@
1867
1867
  "type": "object",
1868
1868
  "properties": {
1869
1869
  "enabled": {
1870
- "description": "Master switch. Default `false` — no hits are sent until the deployment turns tracking on.",
1870
+ "description": "Master switch. Default `true` — the widget always fires; the data module gates ingestion per deployment server-side. Set `false` to silence the client entirely.",
1871
1871
  "type": "boolean"
1872
1872
  },
1873
1873
  "endpoint": {
1874
- "description": "Pixel collector URL. Default: `${dataBaseUrl}/elements/px.gif` (e.g. `https://help.ai/api/data/elements/px.gif`). Must be a full URL.",
1874
+ "description": "Pixel collector URL. Default: `${dataApiBaseUrl}/pai/elements-px.gif` (e.g. `https://help.ai/api/data/pai/elements-px.gif`). Must be a full URL.",
1875
1875
  "type": "string",
1876
1876
  "maxLength": 2048,
1877
1877
  "format": "uri"
@@ -3272,11 +3272,11 @@
3272
3272
  "type": "object",
3273
3273
  "properties": {
3274
3274
  "enabled": {
3275
- "description": "Master switch. Default `false` — no hits are sent until the deployment turns tracking on.",
3275
+ "description": "Master switch. Default `true` — the widget always fires; the data module gates ingestion per deployment server-side. Set `false` to silence the client entirely.",
3276
3276
  "type": "boolean"
3277
3277
  },
3278
3278
  "endpoint": {
3279
- "description": "Pixel collector URL. Default: `${dataBaseUrl}/elements/px.gif` (e.g. `https://help.ai/api/data/elements/px.gif`). Must be a full URL.",
3279
+ "description": "Pixel collector URL. Default: `${dataApiBaseUrl}/pai/elements-px.gif` (e.g. `https://help.ai/api/data/pai/elements-px.gif`). Must be a full URL.",
3280
3280
  "type": "string",
3281
3281
  "maxLength": 2048,
3282
3282
  "format": "uri"
@@ -3305,7 +3305,7 @@
3305
3305
  }
3306
3306
  ]
3307
3307
  },
3308
- "dataBaseUrl": {
3308
+ "dataApiBaseUrl": {
3309
3309
  "type": "string",
3310
3310
  "minLength": 1,
3311
3311
  "maxLength": 2048