@magicx-eng/ai-autocomplete-vanilla 0.32.2 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -647,6 +647,7 @@ unsub();
647
647
  | `removeLastParam()` | Remove the last completed param from state. The text stays in the input as plain text. |
648
648
  | `clearNewParamId()` | Clear shimmer animation state. |
649
649
  | `reset()` | Clear all state, re-fetch initial suggestions, and start a new session (rotates `session_id`). Call this after handling submit. |
650
+ | `recordSubmit(result)` | Record a submit from a button you render. Enter and the built-in button are recorded for you; call this once per submit from your own button. |
650
651
  | `setValue(text)` | Set text (controlled mode). |
651
652
  | `setCompletedParams(params)` | Set completed params (controlled mode). |
652
653
  | `setMode(mode)` | Switch color mode at runtime. |
@@ -982,6 +983,12 @@ const ac = new AIAutocomplete(container, {
982
983
  });
983
984
  ```
984
985
 
986
+ ### Visitor id and submits
987
+
988
+ Pass `visitorId` to tie searches to what the same visitor does later: a UUID v4 you keep across page loads (for example a first-party cookie), or a function that returns one. A function is called only when the id is needed, so it is safe to create the id lazily inside it.
989
+
990
+ Submits from Enter and from the built-in submit button are recorded for you. If you render your own submit button (Tier 2 or 3), call `recordSubmit(result)` from it, once per submit, with the result you pass to your own submit handler.
991
+
985
992
  ## Option Overrides
986
993
 
987
994
  Supply the options for a parameter yourself instead of taking the server's. Each entry is keyed by the suggestion `type` and is a function of the phrase the user has typed for that parameter:
package/dist/index.d.mts CHANGED
@@ -109,6 +109,8 @@ interface AutocompleteResponse {
109
109
  meta: {
110
110
  request_id: string;
111
111
  request_at: string;
112
+ /** The server's funnel-telemetry switch. Absent means off: send no funnel events. */
113
+ funnel_telemetry?: boolean;
112
114
  };
113
115
  }
114
116
  /** Comparison an {@link ExpressedFilter} applies to its value. */
@@ -880,6 +882,16 @@ interface CoreOptions {
880
882
  * parameters and options to them.
881
883
  */
882
884
  additionalContext?: Record<string, unknown>;
885
+ /**
886
+ * Stable id for this visitor, kept by the host across page loads (e.g. a
887
+ * first-party cookie). Rides on funnel telemetry so searches can be joined
888
+ * to what the visitor does afterwards. Must be a UUID v4; omit to send none.
889
+ *
890
+ * A function is called only once the server has switched funnel telemetry
891
+ * on, so a host that creates the id lazily (sets a cookie) creates nothing
892
+ * while it is off.
893
+ */
894
+ visitorId?: string | (() => string | undefined);
883
895
  columns?: number;
884
896
  /** Where pills render in "full" mode. Default: "dropdown". Ignored in "dropdown" mode (always in dropdown). */
885
897
  pillPlacement?: "inline" | "dropdown" | "hidden";
@@ -1064,6 +1076,19 @@ declare class AIAutocomplete {
1064
1076
  private subscriberCount;
1065
1077
  private emitter;
1066
1078
  private sessionId;
1079
+ /** The /suggest request whose response is on screen; telemetry echoes it. */
1080
+ private lastRequestId;
1081
+ /** Session that already sent `search_started`, so it fires once per session. */
1082
+ private searchStartedSessionId;
1083
+ /**
1084
+ * The server's funnel-telemetry switch, from the latest response's meta.
1085
+ * `null` until a response says; no funnel event goes out before that.
1086
+ */
1087
+ private funnelTelemetry;
1088
+ /** A `search_started` that happened before any response said whether to send it. */
1089
+ private pendingSearchStarted;
1090
+ /** What the last `impression` showed, so an identical response doesn't resend it. */
1091
+ private lastImpressionKey;
1067
1092
  private readonly emitSubmit;
1068
1093
  private readonly emitError;
1069
1094
  constructor(container: HTMLElement, opts?: CoreOptions);
@@ -1174,6 +1199,12 @@ declare class AIAutocomplete {
1174
1199
  * highlight the keyboard has since moved elsewhere is left alone.
1175
1200
  */
1176
1201
  clearHighlight(index: number): void;
1202
+ /**
1203
+ * Records a submit in telemetry. The SDK does this itself when it runs the
1204
+ * submit (Enter, or Tier 1's button); call it only from a submit path you
1205
+ * own — a button you render — so each submit is counted once.
1206
+ */
1207
+ recordSubmit(result: AutocompleteResult): void;
1177
1208
  /**
1178
1209
  * Announce a product selection. The rendered cards call this on activation;
1179
1210
  * headless consumers rendering their own strip call it themselves.
@@ -1252,7 +1283,13 @@ declare class AIAutocomplete {
1252
1283
  update(opts: CoreUpdateOptions): void;
1253
1284
  selectOption(option: SuggestionOption): void;
1254
1285
  private startSelectionAnimationTimer;
1286
+ private resolveVisitorId;
1255
1287
  private resolveSource;
1288
+ /**
1289
+ * Records what a response put on screen: pills and their options in display
1290
+ * order, and the product cards. Positions are 1-based array order.
1291
+ */
1292
+ private fireImpression;
1256
1293
  private fireTelemetry;
1257
1294
  private setupContainer;
1258
1295
  private buildAndRenderFull;
package/dist/index.d.ts CHANGED
@@ -109,6 +109,8 @@ interface AutocompleteResponse {
109
109
  meta: {
110
110
  request_id: string;
111
111
  request_at: string;
112
+ /** The server's funnel-telemetry switch. Absent means off: send no funnel events. */
113
+ funnel_telemetry?: boolean;
112
114
  };
113
115
  }
114
116
  /** Comparison an {@link ExpressedFilter} applies to its value. */
@@ -880,6 +882,16 @@ interface CoreOptions {
880
882
  * parameters and options to them.
881
883
  */
882
884
  additionalContext?: Record<string, unknown>;
885
+ /**
886
+ * Stable id for this visitor, kept by the host across page loads (e.g. a
887
+ * first-party cookie). Rides on funnel telemetry so searches can be joined
888
+ * to what the visitor does afterwards. Must be a UUID v4; omit to send none.
889
+ *
890
+ * A function is called only once the server has switched funnel telemetry
891
+ * on, so a host that creates the id lazily (sets a cookie) creates nothing
892
+ * while it is off.
893
+ */
894
+ visitorId?: string | (() => string | undefined);
883
895
  columns?: number;
884
896
  /** Where pills render in "full" mode. Default: "dropdown". Ignored in "dropdown" mode (always in dropdown). */
885
897
  pillPlacement?: "inline" | "dropdown" | "hidden";
@@ -1064,6 +1076,19 @@ declare class AIAutocomplete {
1064
1076
  private subscriberCount;
1065
1077
  private emitter;
1066
1078
  private sessionId;
1079
+ /** The /suggest request whose response is on screen; telemetry echoes it. */
1080
+ private lastRequestId;
1081
+ /** Session that already sent `search_started`, so it fires once per session. */
1082
+ private searchStartedSessionId;
1083
+ /**
1084
+ * The server's funnel-telemetry switch, from the latest response's meta.
1085
+ * `null` until a response says; no funnel event goes out before that.
1086
+ */
1087
+ private funnelTelemetry;
1088
+ /** A `search_started` that happened before any response said whether to send it. */
1089
+ private pendingSearchStarted;
1090
+ /** What the last `impression` showed, so an identical response doesn't resend it. */
1091
+ private lastImpressionKey;
1067
1092
  private readonly emitSubmit;
1068
1093
  private readonly emitError;
1069
1094
  constructor(container: HTMLElement, opts?: CoreOptions);
@@ -1174,6 +1199,12 @@ declare class AIAutocomplete {
1174
1199
  * highlight the keyboard has since moved elsewhere is left alone.
1175
1200
  */
1176
1201
  clearHighlight(index: number): void;
1202
+ /**
1203
+ * Records a submit in telemetry. The SDK does this itself when it runs the
1204
+ * submit (Enter, or Tier 1's button); call it only from a submit path you
1205
+ * own — a button you render — so each submit is counted once.
1206
+ */
1207
+ recordSubmit(result: AutocompleteResult): void;
1177
1208
  /**
1178
1209
  * Announce a product selection. The rendered cards call this on activation;
1179
1210
  * headless consumers rendering their own strip call it themselves.
@@ -1252,7 +1283,13 @@ declare class AIAutocomplete {
1252
1283
  update(opts: CoreUpdateOptions): void;
1253
1284
  selectOption(option: SuggestionOption): void;
1254
1285
  private startSelectionAnimationTimer;
1286
+ private resolveVisitorId;
1255
1287
  private resolveSource;
1288
+ /**
1289
+ * Records what a response put on screen: pills and their options in display
1290
+ * order, and the product cards. Positions are 1-based array order.
1291
+ */
1292
+ private fireImpression;
1256
1293
  private fireTelemetry;
1257
1294
  private setupContainer;
1258
1295
  private buildAndRenderFull;