@helpai/elements 0.21.0 → 0.22.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/configurator.mjs CHANGED
@@ -20,7 +20,7 @@ var localeSchema = z.string().min(1).max(35).describe("BCP-47 locale tag (e.g. `
20
20
  var uuid7Schema = z.uuidv7().describe("UUID v7 (RFC 9562) \u2014 the single id format for visitor / conversation / message / file / content ids.");
21
21
 
22
22
  // src/schema/widget.ts
23
- import { z as z15 } from "zod";
23
+ import { z as z16 } from "zod";
24
24
 
25
25
  // src/schema/widget/presentation.ts
26
26
  import { z as z3 } from "zod";
@@ -563,11 +563,23 @@ var modulesSchema = z14.array(moduleSchema).max(4).describe(
563
563
  ]
564
564
  });
565
565
 
566
+ // src/schema/widget/tracking.ts
567
+ import { z as z15 } from "zod";
568
+ var trackingSchema = z15.object({
569
+ enabled: z15.boolean().optional().describe("Master switch. Default `false` \u2014 no hits are sent until the deployment turns tracking on."),
570
+ endpoint: z15.url().max(2048).optional().describe("Pixel collector URL. Default: `https://t.<brand domain>/api/ai-elements/px.gif`. Must be a full URL."),
571
+ sampleRate: z15.number().min(0).max(1).optional().describe("Per-visitor sampling 0..1 (decided once per page load, keeping funnels intact). Default `1`.")
572
+ }).loose().describe(
573
+ "Anonymous usage tracking for the widget owner \u2014 GA-style pixel events (open, send, form submit, \u2026) with page / device / locale dimensions. Never includes message content; visitors are identified only by the widget's anonymous visitorId."
574
+ ).meta({
575
+ examples: [{ enabled: true }, { enabled: true, sampleRate: 0.5 }]
576
+ });
577
+
566
578
  // src/schema/widget.ts
567
- var endpointsSchema = z15.object({
568
- upload: z15.string().min(1).max(2048).default("/ai/agent/upload-file"),
569
- transcribe: z15.string().min(1).max(2048).default("/ai/agent/transcribe-audio"),
570
- submitForm: z15.string().min(1).max(2048).default("/ai/agent/submit-form").describe(
579
+ var endpointsSchema = z16.object({
580
+ upload: z16.string().min(1).max(2048).default("/ai/agent/upload-file"),
581
+ transcribe: z16.string().min(1).max(2048).default("/ai/agent/transcribe-audio"),
582
+ submitForm: z16.string().min(1).max(2048).default("/ai/agent/submit-form").describe(
571
583
  "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 \u2014 a 404 is ignored."
572
584
  )
573
585
  }).loose().describe("HTTP endpoint overrides. Paths are appended to baseUrl; absolute URLs are accepted too.").meta({
@@ -577,14 +589,14 @@ var endpointsSchema = z15.object({
577
589
  { submitForm: "https://crm.acme.com/leads" }
578
590
  ]
579
591
  });
580
- var userContextSchema = z15.object({
581
- id: z15.string().min(1).max(200).optional().describe("Host's stable id for the user \u2014 informational context the agent/backend can key on (not auth)."),
582
- email: z15.string().min(1).max(320).optional().describe("User email \u2014 surfaced to the agent for context (optional)."),
583
- name: z15.string().min(1).max(200).optional().describe("Display name \u2014 shown in the Home greeting (`{name}`) and conversation transcripts (optional)."),
584
- plan: z15.string().min(1).max(120).optional().describe("Subscription / pricing tier, e.g. `pro` (optional)."),
585
- role: z15.string().min(1).max(120).optional().describe("The user's role on the host site, e.g. `admin` (optional)."),
586
- phone: z15.string().min(1).max(40).optional().describe("Phone number (optional).")
587
- }).catchall(z15.union([z15.string(), z15.number(), z15.boolean()])).describe(
592
+ var userContextSchema = z16.object({
593
+ id: z16.string().min(1).max(200).optional().describe("Host's stable id for the user \u2014 informational context the agent/backend can key on (not auth)."),
594
+ email: z16.string().min(1).max(320).optional().describe("User email \u2014 surfaced to the agent for context (optional)."),
595
+ name: z16.string().min(1).max(200).optional().describe("Display name \u2014 shown in the Home greeting (`{name}`) and conversation transcripts (optional)."),
596
+ plan: z16.string().min(1).max(120).optional().describe("Subscription / pricing tier, e.g. `pro` (optional)."),
597
+ role: z16.string().min(1).max(120).optional().describe("The user's role on the host site, e.g. `admin` (optional)."),
598
+ phone: z16.string().min(1).max(40).optional().describe("Phone number (optional).")
599
+ }).catchall(z16.union([z16.string(), z16.number(), z16.boolean()])).describe(
588
600
  "Host-asserted end-user context (informational, untrusted \u2014 not authentication). Recognised `id` / `email` / `name` / `plan` / `role` / `phone` plus any extra custom scalar fields forwarded to the agent."
589
601
  ).meta({
590
602
  examples: [{ id: "u_123" }, { id: "u_123", email: "alex@acme.com", name: "Alex Lee", plan: "pro" }]
@@ -600,31 +612,31 @@ var PAGE_AREA_SUGGESTIONS = [
600
612
  "account",
601
613
  "blog"
602
614
  ];
603
- var pageContextSchema = z15.object({
604
- area: z15.string().min(1).max(64).optional().describe(`Host-defined surface the visitor is on. Free-form; suggested: ${PAGE_AREA_SUGGESTIONS.join(" | ")}.`),
605
- url: z15.string().min(1).max(2048).optional().describe("Full page URL. Auto-filled from the host page when omitted."),
606
- path: z15.string().min(1).max(2048).optional().describe("Page path, e.g. `/pricing/enterprise`."),
607
- title: z15.string().min(1).max(300).optional().describe("Human-readable page title.")
608
- }).catchall(z15.union([z15.string(), z15.number(), z15.boolean()])).describe(
615
+ var pageContextSchema = z16.object({
616
+ area: z16.string().min(1).max(64).optional().describe(`Host-defined surface the visitor is on. Free-form; suggested: ${PAGE_AREA_SUGGESTIONS.join(" | ")}.`),
617
+ url: z16.string().min(1).max(2048).optional().describe("Full page URL. Auto-filled from the host page when omitted."),
618
+ path: z16.string().min(1).max(2048).optional().describe("Page path, e.g. `/pricing/enterprise`."),
619
+ title: z16.string().min(1).max(300).optional().describe("Human-readable page title.")
620
+ }).catchall(z16.union([z16.string(), z16.number(), z16.boolean()])).describe(
609
621
  "Host-asserted page/visit context (informational, untrusted). Where the visitor is + the surface (`area`) they're using, plus any custom scalar fields, forwarded to the agent."
610
622
  ).meta({ examples: [{ area: "pricing", path: "/pricing" }, { area: "help-desk" }] });
611
- var connectionConfigSchema = z15.object({
612
- widgetId: z15.string().min(1).max(80).default("default").describe(
623
+ var connectionConfigSchema = z16.object({
624
+ widgetId: z16.string().min(1).max(80).default("default").describe(
613
625
  "Stable per-instance id used to namespace localStorage keys. Set this when mounting more than one widget on the same page so their conversation state doesn't collide."
614
626
  ),
615
- publicKey: z15.string().min(1).max(200).optional().describe(
627
+ publicKey: z16.string().min(1).max(200).optional().describe(
616
628
  "Workspace-scoped public key (`agent_pk_\u2026`) issued from the dashboard. Sent on every API call as the `x-public-key` header."
617
629
  ),
618
- aiAgentDeploymentId: z15.string().min(1).max(200).optional().describe(
630
+ aiAgentDeploymentId: z16.string().min(1).max(200).optional().describe(
619
631
  "Deployment UUID from the dashboard. Picks which agent / settings bundle answers this mount. Sent as `x-ai-agent-deployment-id`."
620
632
  ),
621
- baseUrl: z15.string().min(1).max(2048).optional().describe(
633
+ baseUrl: z16.string().min(1).max(2048).optional().describe(
622
634
  "Full backend origin (e.g. `https://help.ai/api`). Set this to point at your staging / self-hosted / custom backend. Default: the brand's `defaultBaseUrl` baked at build time."
623
635
  ),
624
636
  userContext: userContextSchema.optional(),
625
637
  pageContext: pageContextSchema.optional(),
626
638
  endpoints: endpointsSchema.optional(),
627
- debug: z15.union([z15.boolean(), z15.enum(["off", "error", "warn", "info", "debug", "trace"])]).optional().describe(
639
+ debug: z16.union([z16.boolean(), z16.enum(["off", "error", "warn", "info", "debug", "trace"])]).optional().describe(
628
640
  'Console log verbosity. `false` / `"off"` silences everything (default in production). `true` \u2192 `"debug"`. Levels `error` / `warn` / `info` / `debug` / `trace` gate output additively. Use `"trace"` to capture per-chunk SSE frames + every state transition. Also toggleable at runtime via `chat.setDebug(level)` or `?<brand>-debug=trace` in the page URL \u2014 the URL beats this option, this option beats the persisted `localStorage` value.'
629
641
  )
630
642
  }).loose().describe(
@@ -644,7 +656,7 @@ var connectionConfigSchema = z15.object({
644
656
  }
645
657
  ]
646
658
  });
647
- var widgetSettingsSchema = z15.object({
659
+ var widgetSettingsSchema = z16.object({
648
660
  presentation: presentationSchema.optional(),
649
661
  behavior: behaviorSchema.optional(),
650
662
  theme: themeFieldSchema.default("auto").describe("Theme preference (`auto` follows OS) or a tokens override object (`accent`, `radius`, `fontFamily`)."),
@@ -656,9 +668,10 @@ var widgetSettingsSchema = z15.object({
656
668
  footer: footerSchema.optional(),
657
669
  features: featureFlagsSchema.optional(),
658
670
  forms: formsSchema.optional(),
659
- modules: modulesSchema.optional()
671
+ modules: modulesSchema.optional(),
672
+ tracking: trackingSchema.optional()
660
673
  }).loose().describe(
661
- "Portal-configurable widget settings \u2014 thirteen sections, one per dashboard tab. The backend pushes this same shape on `/ai/agent/start-conversation` under `config`."
674
+ "Portal-configurable widget settings \u2014 fourteen sections, one per dashboard tab. The backend pushes this same shape on `/ai/agent/start-conversation` under `config`."
662
675
  ).meta({
663
676
  examples: [
664
677
  { presentation: { mode: "floating", position: "bottom-right" }, theme: "auto" },
@@ -676,10 +689,10 @@ var widgetSettingsSchema = z15.object({
676
689
  });
677
690
  var widgetConfigSchema = connectionConfigSchema.extend({
678
691
  ...widgetSettingsSchema.shape,
679
- site: z15.unknown().optional().describe(
692
+ site: z16.unknown().optional().describe(
680
693
  'Site config \u2014 applies in `mode: "page"`. Comes from the start-conversation response, not user-edited.'
681
694
  ),
682
- blocks: z15.unknown().optional().describe('Blocks (nav + link cards) \u2014 applies in `mode: "page"`. Comes from the start-conversation response.')
695
+ blocks: z16.unknown().optional().describe('Blocks (nav + link cards) \u2014 applies in `mode: "page"`. Comes from the start-conversation response.')
683
696
  }).describe(
684
697
  "Full client widget config \u2014 connection (where + auth) + widget settings (look + behaviour) + page-mode extras. This is what the runtime parses on `mount()` / `init()`. Mode-specific constraints (e.g. `position` only meaningful in `floating`) are NOT enforced here \u2014 the runtime silently ignores irrelevant fields rather than rejecting them so the same object can flow across mode changes."
685
698
  ).meta({
@@ -702,49 +715,49 @@ var widgetSettingsPartialSchema = widgetSettingsSchema.partial();
702
715
  var connectionConfigPartialSchema = connectionConfigSchema.partial();
703
716
 
704
717
  // src/schema/deployment.ts
705
- import { z as z16 } from "zod";
718
+ import { z as z17 } from "zod";
706
719
  var serverConfigSchema = widgetSettingsSchema.partial();
707
- var siteConfigSchema = z16.object({
708
- title: z16.string().min(1).max(120).optional().describe("Brand / site name. Used as the logo's alt-text fallback."),
720
+ var siteConfigSchema = z17.object({
721
+ title: z17.string().min(1).max(120).optional().describe("Brand / site name. Used as the logo's alt-text fallback."),
709
722
  logo: assetSchema.optional().describe("Brand logo shown at the top of the page-mode sidebar."),
710
723
  logoDark: assetSchema.optional().describe(
711
724
  "Optional dark-theme logo variant. Falls back to `logo` when the active theme is light or `logoDark` is unset."
712
725
  )
713
726
  }).loose();
714
- var blocksConfigSchema = z16.object({
715
- navigation: z16.array(linkSchema).max(100).optional().describe("Sidebar navigation links (vertical list, primary nav)."),
716
- linkCards: z16.array(linkSchema).max(100).optional().describe("Sidebar link cards (richer entries with optional `description`).")
727
+ var blocksConfigSchema = z17.object({
728
+ navigation: z17.array(linkSchema).max(100).optional().describe("Sidebar navigation links (vertical list, primary nav)."),
729
+ linkCards: z17.array(linkSchema).max(100).optional().describe("Sidebar link cards (richer entries with optional `description`).")
717
730
  }).loose();
718
- var handshakeWelcomeMessageSchema = z16.object({
719
- id: z16.string(),
720
- role: z16.enum(["assistant", "system"]),
721
- text: z16.string()
731
+ var handshakeWelcomeMessageSchema = z17.object({
732
+ id: z17.string(),
733
+ role: z17.enum(["assistant", "system"]),
734
+ text: z17.string()
722
735
  }).loose();
723
- var handshakeWelcomeSuggestionSchema = z16.object({
724
- id: z16.string(),
725
- label: z16.string(),
726
- text: z16.string().optional()
736
+ var handshakeWelcomeSuggestionSchema = z17.object({
737
+ id: z17.string(),
738
+ label: z17.string(),
739
+ text: z17.string().optional()
727
740
  }).loose();
728
- var rebindReasonSchema = z16.enum(["conflict", "expired", "invalid"]);
729
- var startConversationResponseSchema = z16.object({
730
- deployment: z16.object({
731
- id: z16.string(),
732
- name: z16.string(),
741
+ var rebindReasonSchema = z17.enum(["conflict", "expired", "invalid"]);
742
+ var startConversationResponseSchema = z17.object({
743
+ deployment: z17.object({
744
+ id: z17.string(),
745
+ name: z17.string(),
733
746
  // Page URL identifier — present on every deployment; unique per host.
734
747
  // Used to mount page deployments via `?slug=…`.
735
- slug: z16.string().optional(),
736
- publicKey: z16.string().optional()
748
+ slug: z17.string().optional(),
749
+ publicKey: z17.string().optional()
737
750
  // Deliberately no `type` / `channel` here. Deployment-level
738
751
  // taxonomy is a backend categorization concern — the widget's
739
752
  // rendering choice flows from `widget.presentation.mode`, not
740
753
  // the deployment record's category. `.loose()` lets any such
741
754
  // backend field pass through without typing.
742
755
  }).loose(),
743
- agent: z16.object({
744
- id: z16.string(),
745
- name: z16.string(),
746
- title: z16.string().optional(),
747
- status: z16.enum(["online", "away", "offline"]).optional()
756
+ agent: z17.object({
757
+ id: z17.string(),
758
+ name: z17.string(),
759
+ title: z17.string().optional(),
760
+ status: z17.enum(["online", "away", "offline"]).optional()
748
761
  }).loose(),
749
762
  /**
750
763
  * Deployment-wide widget configuration the dashboard admin saved
@@ -754,26 +767,26 @@ var startConversationResponseSchema = z16.object({
754
767
  config: serverConfigSchema.optional(),
755
768
  site: siteConfigSchema.optional(),
756
769
  blocks: blocksConfigSchema.optional(),
757
- welcome: z16.object({
758
- messages: z16.array(handshakeWelcomeMessageSchema).optional(),
759
- suggestions: z16.array(handshakeWelcomeSuggestionSchema).optional()
770
+ welcome: z17.object({
771
+ messages: z17.array(handshakeWelcomeMessageSchema).optional(),
772
+ suggestions: z17.array(handshakeWelcomeSuggestionSchema).optional()
760
773
  }).loose().optional(),
761
- visitorId: z16.string(),
762
- conversationId: z16.string(),
763
- canContinue: z16.boolean(),
764
- messages: z16.array(z16.unknown()),
774
+ visitorId: z17.string(),
775
+ conversationId: z17.string(),
776
+ canContinue: z17.boolean(),
777
+ messages: z17.array(z17.unknown()),
765
778
  /**
766
779
  * Form submissions recorded for this conversation — echoed like
767
780
  * `messages` so the widget reconstructs the collapsed "form submitted"
768
781
  * timeline markers on resume. `createdAt` is ISO-8601 (a serialized
769
782
  * Mongo ISODate — same format as message `createdAt`).
770
783
  */
771
- formSubmissions: z16.array(
772
- z16.object({
773
- formId: z16.string(),
774
- trigger: z16.string(),
775
- skipped: z16.boolean().optional(),
776
- createdAt: z16.iso.datetime().optional()
784
+ formSubmissions: z17.array(
785
+ z17.object({
786
+ formId: z17.string(),
787
+ trigger: z17.string(),
788
+ skipped: z17.boolean().optional(),
789
+ createdAt: z17.iso.datetime().optional()
777
790
  }).loose()
778
791
  ).optional(),
779
792
  /**
@@ -782,11 +795,11 @@ var startConversationResponseSchema = z16.object({
782
795
  * what THIS visitor toggled inside the widget, not the
783
796
  * deployment's admin-set defaults.
784
797
  */
785
- userPrefs: z16.record(z16.string(), z16.unknown()).optional(),
798
+ userPrefs: z17.record(z17.string(), z17.unknown()).optional(),
786
799
  // Present only when the server rotated the request `visitorId` /
787
800
  // `conversationId`. Purely advisory — client must adopt the response ids
788
801
  // verbatim regardless of whether this block is present.
789
- rebind: z16.object({
802
+ rebind: z17.object({
790
803
  visitorId: rebindReasonSchema.optional(),
791
804
  conversationId: rebindReasonSchema.optional()
792
805
  }).loose().optional()
@@ -796,7 +809,7 @@ var startConversationResponseSchema = z16.object({
796
809
  import "zod";
797
810
 
798
811
  // src/schema/json-schema.ts
799
- import { z as z18 } from "zod";
812
+ import { z as z19 } from "zod";
800
813
 
801
814
  // src/configurator/field-help.tsx
802
815
  import { createPortal } from "preact/compat";