@magicx-eng/ai-autocomplete-vanilla 0.34.0 → 0.36.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
@@ -59,7 +59,7 @@ const ac = new AIAutocomplete(document.getElementById("root"), {
59
59
  onSubmit: (result) => {
60
60
  console.log(result.query); // "Create a email"
61
61
  console.log(result.raw_query); // "Create a {{TASK_1}}"
62
- console.log(result.completed_params); // [{ placeholder: "{{TASK_1}}", type: "task", ... }]
62
+ console.log(result.completed_params); // [{ placeholder: "{{TASK_1}}", parameter: "task", ... }]
63
63
  },
64
64
  });
65
65
  ```
@@ -202,7 +202,10 @@ Each server item becomes a `Product` with `id` (the item's stable id), `title`,
202
202
  currency is yours to add), `vendor`, `imageUrl`, and a `url`: the item's own
203
203
  `item_url` when the uploaded catalog named one (absolute or root-relative;
204
204
  anything else is ignored), else a **relative** `/products/{handle}` — the right
205
- link for a Shopify widget running on the storefront itself. An item with
205
+ link for a Shopify widget running on the storefront itself — opened on the
206
+ variant the query chose (`?variant=…`, e.g. the blue one for "blue shoes") when
207
+ there is one, whose price and image the card then shows. `available` is carried
208
+ over when the server reports it. An item with
206
209
  neither gets no `url`: its card is still activatable and still emits
207
210
  `onProductSelect`, it just has nothing for cmd-click to open. `productFromMatchedItem` / `productsFromCustomFields` are
208
211
  exported for a hand-rolled strip that wants the same mapping.
@@ -229,6 +232,17 @@ empty or whitespace-only title shows `?`. The fallback works in both row and
229
232
  list layouts. Initial tiles are decorative (`aria-hidden="true"`); the card's
230
233
  visible title supplies its text.
231
234
 
235
+ **Sold out.** A product with `available: false` shows a "Sold out" badge over
236
+ the top-left of its image (in the list layout, a smaller banner across the
237
+ bottom of the thumbnail) and its image is desaturated; the card stays
238
+ selectable and keeps its link. Absent or `true` shows no
239
+ badge, so leave `available` out when you don't know. The badge is part of the
240
+ card's text, so screen readers announce it. Theme it with
241
+ `--aia-product-badge-bg`, `--aia-product-badge-color`,
242
+ `--aia-product-badge-font-size` and `--aia-product-badge-inset`, and the list
243
+ banner with `--aia-product-badge-list-bg`, `--aia-product-badge-list-color` and
244
+ `--aia-product-badge-list-font-size`.
245
+
232
246
  Set the option at construction or change it through `update()`. Both
233
247
  rendered tiers (`"full"` and `"dropdown"`) apply it to the visible cards:
234
248
 
@@ -269,7 +283,7 @@ ac.subscribe((state) => {
269
283
  if (!report) return; // no catalog was read for this response
270
284
  count.textContent = `${report.items.total} results`;
271
285
  if (report.dropped_filters.length > 0) {
272
- // e.g. { param: "Color", value: "Chartreuse", op: "eq" } — the shopper asked
286
+ // e.g. { parameter: "Color", value: "Chartreuse", op: "eq" } — the shopper asked
273
287
  // for a colour no item carries, so the results ignore it. Say so.
274
288
  note.textContent = `No match for ${report.dropped_filters.map((f) => f.value).join(", ")}`;
275
289
  }
@@ -277,7 +291,7 @@ ac.subscribe((state) => {
277
291
  ```
278
292
 
279
293
  - `applied_filters` / `dropped_filters` — the constraints the server read out
280
- of the query as `{ param, value, op }` (`op` is one of `eq`, `ne`, `lt`,
294
+ of the query as `{ parameter, value, op }` (`op` is one of `eq`, `ne`, `lt`,
281
295
  `lte`, `gt`, `gte`), split into the ones the catalog answered and the ones it
282
296
  could not (a parameter it does not have, a bound that is not a number, a
283
297
  value no item carries). The items answer the applied set, so the dropped
@@ -340,7 +354,7 @@ new AIAutocomplete(container, {
340
354
  });
341
355
  ```
342
356
 
343
- `Product` is exactly six fields; only `id` and `title` are required:
357
+ `Product` is exactly seven fields; only `id` and `title` are required:
344
358
 
345
359
  ```ts
346
360
  type Product = {
@@ -350,6 +364,7 @@ type Product = {
350
364
  imageUrl?: string | null; // null uses the configured productImageFallback
351
365
  price?: string; // pre-formatted by you
352
366
  vendor?: string;
367
+ available?: boolean; // false shows a "Sold out" badge
353
368
  };
354
369
  ```
355
370
 
@@ -736,9 +751,9 @@ The structured query as the SDK currently understands it. The same object is pas
736
751
  | `query` | `string` | Plain text as the user sees it, trimmed. |
737
752
  | `raw_query` | `string` | `query` with each completed param replaced by its placeholder token (e.g. `"Create a {{TASK_1}}"`). |
738
753
  | `completed_params` | `CompletedParam[]` | Filled parameter values in query order, followed by any the user skipped (see below). |
739
- | `identified_params` | `IdentifiedParam[]` | Parameters the server recognised in the user's own words, as `{ type, value }` — e.g. `{ type: "due_date", value: "Friday" }` when the user typed "by Friday" instead of picking a date. They are not tokenized in `raw_query`, and they are tentative: each response replaces the set, and an entry drops out as soon as its text is edited away. |
754
+ | `identified_params` | `IdentifiedParam[]` | Parameters the server recognised in the user's own words, as `{ parameter, text }` — e.g. `{ parameter: "due_date", text: "Friday" }` when the user typed "by Friday" instead of picking a date. They are not tokenized in `raw_query`, and they are tentative: each response replaces the set, and an entry drops out as soon as its text is edited away. |
740
755
  | `is_ready` | `boolean` | Whether the server considers the query complete enough to act on. |
741
- | `custom_fields?` | `CustomFieldsReport` | What catalog grounding did for the latest applied response, when it read a catalog at all — see [Product strip](#product-strip). `applied_filters` and `dropped_filters` list the query's constraints as `{ param, value, op }`; `items.total` is how many items the applied ones left standing and `items.matched` the ones the strip renders. Absent (no key) when the response carried no report. |
756
+ | `custom_fields?` | `CustomFieldsReport` | What catalog grounding did for the latest applied response, when it read a catalog at all — see [Product strip](#product-strip). `applied_filters` and `dropped_filters` list the query's constraints as `{ parameter, value, op }`; `items.total` is how many items the applied ones left standing and `items.matched` the ones the strip renders. Absent (no key) when the response carried no report. |
742
757
 
743
758
  #### Reading the query as it's built
744
759
 
@@ -772,12 +787,12 @@ What "every successful round-trip" means in practice:
772
787
  Pressing <kbd>→</kbd> at the end of the input dismisses the active pill. The dismissal is reported to the server — and included in `completed_params` here — as an entry with no placeholder and the sentinel text `"skipped"`:
773
788
 
774
789
  ```ts
775
- { placeholder: "", type: "goal", text: "skipped", kind: null }
790
+ { placeholder: "", parameter: "goal", text: "skipped", kind: null }
776
791
  ```
777
792
 
778
- Skipped entries are appended after the filled params (they have no position in the query) and are deduped by type. A skip is dropped if a param of the same type ends up filled anyway. Skipping the last available pill triggers an immediate request so the server can suggest something else; earlier skips ride along on the next request. `reset()` clears them.
793
+ Skipped entries are appended after the filled params (they have no position in the query) and are deduped by parameter. A skip is dropped if a param of the same parameter ends up filled anyway. Skipping the last available pill triggers an immediate request so the server can suggest something else; earlier skips ride along on the next request. `reset()` clears them.
779
794
 
780
- > **Reading `state.skippedParams` directly:** the array is append-only until `reset()`. The "drop a skip whose type got filled" rule is applied when the payload is built, not by pruning the array — so if the user skips `goal` and later fills one, the raw array still holds the `goal` entry. That's deliberate: the filter self-heals if they then delete that param's text, where pruning would discard the signal for good. Apply the same rule yourself with the exported `withSkippedParams(completedParams, skippedParams)`.
795
+ > **Reading `state.skippedParams` directly:** the array is append-only until `reset()`. The "drop a skip whose parameter got filled" rule is applied when the payload is built, not by pruning the array — so if the user skips `goal` and later fills one, the raw array still holds the `goal` entry. That's deliberate: the filter self-heals if they then delete that param's text, where pruning would discard the signal for good. Apply the same rule yourself with the exported `withSkippedParams(completedParams, skippedParams)`.
781
796
 
782
797
  ### Event Subscription
783
798
 
@@ -992,7 +1007,7 @@ Submits from Enter and from the built-in submit button are recorded for you. If
992
1007
 
993
1008
  ## Option Overrides
994
1009
 
995
- 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:
1010
+ Supply the options for a parameter yourself instead of taking the server's. Each entry is keyed by the suggestion `parameter` and is a function of the phrase the user has typed for that parameter:
996
1011
 
997
1012
  ```ts
998
1013
  new AIAutocomplete(el, {
@@ -1013,11 +1028,11 @@ new AIAutocomplete(el, {
1013
1028
  });
1014
1029
  ```
1015
1030
 
1016
- **When it's called.** Once the moment the parameter becomes active — a response suggests it, a skip or a selection moves it to the front, or the user taps a completed value of that type to change it — with whatever they have already typed for it (usually `""`, the request for the default list). Then again on the SDK's typing debounce with each new phrase, so you can run a search or page through a larger list. If a phrase is already covered by what you last returned, return that list again. The third argument is the `Suggestion` being answered, for the rare override that serves more than one type.
1031
+ **When it's called.** Once the moment the parameter becomes active — a response suggests it, a skip or a selection moves it to the front, or the user taps a completed value of that parameter to change it — with whatever they have already typed for it (usually `""`, the request for the default list). Then again on the SDK's typing debounce with each new phrase, so you can run a search or page through a larger list. If a phrase is already covered by what you last returned, return that list again. The third argument is the `Suggestion` being answered, for the rare override that serves more than one parameter.
1017
1032
 
1018
1033
  **What's shown.** Your answer, as-is: it is not filtered again by the phrase it was produced for, so a fuzzy or synonym match survives. Between two calls the previous answer is filtered locally by what the user types, so the list reacts to every keystroke. Typing the full text of an option in the answer completes the parameter, exactly as it does for a server option.
1019
1034
 
1020
- **The server's role.** The server's own options for an overridden type are never shown. While an override owns the active parameter the server is not asked for suggestions; it is asked again when the parameter is answered or skipped. Return an empty list for a typed phrase and the SDK falls back to the server for that phrase — the typed text goes out the way it does for a parameter with no matching options — and won't ask you the same phrase twice. An empty list for `""` leaves the parameter on screen with no options.
1035
+ **The server's role.** The server's own options for an overridden parameter are never shown. While an override owns the active parameter the server is not asked for suggestions; it is asked again when the parameter is answered or skipped. Return an empty list for a typed phrase and the SDK falls back to the server for that phrase — the typed text goes out the way it does for a parameter with no matching options — and won't ask you the same phrase twice. An empty list for `""` leaves the parameter on screen with no options.
1021
1036
 
1022
1037
  **Cancellation and errors.** Honour `signal`: it is aborted when a newer phrase supersedes the call, when the parameter stops being active, and on `destroy()`. A throw or a rejection is logged once per instance and treated as an empty answer, never as a fetch error.
1023
1038
 
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  type TaskKind = "automation" | "email" | "insight";
2
2
  interface CompletedParam {
3
3
  placeholder: string;
4
- type: string;
4
+ parameter: string;
5
5
  text?: string;
6
6
  kind: TaskKind | null;
7
7
  }
@@ -49,15 +49,34 @@ interface SuggestionOption {
49
49
  is_tappable: boolean;
50
50
  kind: TaskKind | null;
51
51
  metadata?: Record<string, unknown>;
52
+ /**
53
+ * The parameter a tap on this option answers. The server names it on every
54
+ * option; options the SDK builds itself (a calendar's dates) carry their
55
+ * suggestion's.
56
+ */
57
+ parameter?: string;
58
+ }
59
+ /**
60
+ * The value type of a suggestion's parameter — which picker it needs. Present
61
+ * only for a date or date-range parameter.
62
+ */
63
+ interface SuggestionType {
64
+ kind: "string" | "numeric" | "date" | "date_range" | "boolean";
65
+ /** How a date is written, e.g. "DD/MM/YYYY". */
66
+ date_format?: string;
67
+ /** What joins the two dates of a range, e.g. " to ". */
68
+ separator?: string;
69
+ unit?: string;
52
70
  }
53
71
  interface Suggestion {
54
- type: string;
72
+ parameter: string;
55
73
  text: string;
56
74
  required: boolean;
57
75
  options?: SuggestionOption[];
76
+ type?: SuggestionType;
58
77
  }
59
78
  interface InputItem {
60
- type: string;
79
+ parameter: string;
61
80
  text: string;
62
81
  state: "completed" | "in_progress";
63
82
  /** Absent or "selected" = echo of client params; "identified" = LLM-inferred. */
@@ -65,15 +84,15 @@ interface InputItem {
65
84
  }
66
85
  /** Wire shape for an LLM-identified param echoed back to the server. */
67
86
  interface IdentifiedParam {
68
- type: string;
69
- value: string;
87
+ parameter: string;
88
+ text: string;
70
89
  }
71
90
  /**
72
91
  * Wire shape for a recently-suggested hint entry: a suggestion that was on
73
92
  * screen when the user started typing the current unresolved trailing text.
74
93
  */
75
94
  interface RecentlySuggested {
76
- type: string;
95
+ parameter: string;
77
96
  text: string;
78
97
  }
79
98
  interface AutocompleteRequest {
@@ -92,6 +111,8 @@ interface AutocompleteRequest {
92
111
  client_version: string;
93
112
  session_id: string;
94
113
  source?: "full-sdk" | "headless-sdk";
114
+ /** The wire format this SDK speaks ({@link SCHEMA_VERSION}). */
115
+ schema_version: string;
95
116
  };
96
117
  }
97
118
  interface AutocompleteResponse {
@@ -111,6 +132,8 @@ interface AutocompleteResponse {
111
132
  request_at: string;
112
133
  /** The server's funnel-telemetry switch. Absent means off: send no funnel events. */
113
134
  funnel_telemetry?: boolean;
135
+ /** The request's `schema_version`, echoed back. */
136
+ schema_version?: string;
114
137
  };
115
138
  }
116
139
  /** Comparison an {@link ExpressedFilter} applies to its value. */
@@ -120,7 +143,7 @@ type FilterOp = "eq" | "ne" | "lt" | "lte" | "gt" | "gte";
120
143
  * how the two compare ("price", "100", "lt").
121
144
  */
122
145
  interface ExpressedFilter {
123
- param: string;
146
+ parameter: string;
124
147
  value: string;
125
148
  op: FilterOp;
126
149
  }
@@ -154,6 +177,18 @@ interface MatchedItem {
154
177
  * item carries `handle` instead. When both are present the strip links here.
155
178
  */
156
179
  item_url?: string;
180
+ /**
181
+ * The variant a filter in the query chose for this item ("blue", "size 10"),
182
+ * as the platform's numeric variant id. When set, `price` and `image_url`
183
+ * are that variant's, and the strip links to `/products/{handle}?variant=…`
184
+ * so the shopper lands on it.
185
+ */
186
+ variant_id?: string;
187
+ /**
188
+ * Whether the item can be bought: `false` is sold out. Absent when the
189
+ * catalog doesn't say, which is not the same as sold out.
190
+ */
191
+ available?: boolean;
157
192
  }
158
193
  /** The items the applied filters left standing. */
159
194
  interface MatchedItems {
@@ -201,8 +236,13 @@ interface CompletedParamState extends CompletedParam {
201
236
  text: string;
202
237
  /** The originating option's `value` (see {@link SuggestionOption.value}), carried over so `toWireParam` can send it instead of the shortened `text`. */
203
238
  value?: string;
204
- /** Source suggestion's `type` — used by re-edit mode to render the dropdown pill. */
205
- suggestionType: string;
239
+ /** Source suggestion's `parameter` — used by re-edit mode to render the dropdown pill. */
240
+ suggestionParameter: string;
241
+ /**
242
+ * Source suggestion's `type` (its value type), carried so re-edit opens the
243
+ * same picker the first pick did — see {@link Suggestion.type}.
244
+ */
245
+ suggestionValueType?: SuggestionType;
206
246
  /** Source suggestion's `text` — used by re-edit mode to render the dropdown pill. */
207
247
  suggestionPlaceholder: string;
208
248
  /** Cached options from the suggestion that produced this param — re-edit shows these. */
@@ -241,8 +281,8 @@ interface CompletedParamState extends CompletedParam {
241
281
  */
242
282
  interface SkippedParamState {
243
283
  id: string;
244
- /** The skipped suggestion's `type` (e.g. "goal"). */
245
- type: string;
284
+ /** The skipped suggestion's `parameter` (e.g. "goal"). */
285
+ parameter: string;
246
286
  /** The suggestion's display text at skip time. Introspection only — never sent. */
247
287
  suggestionPlaceholder: string;
248
288
  }
@@ -253,7 +293,7 @@ interface SkippedParamState {
253
293
  */
254
294
  interface IdentifiedParamState {
255
295
  id: string;
256
- type: string;
296
+ parameter: string;
257
297
  text: string;
258
298
  }
259
299
  type Segment = {
@@ -352,6 +392,12 @@ interface Product {
352
392
  /** Pre-formatted by the integration, which is the side that knows the currency. */
353
393
  price?: string;
354
394
  vendor?: string;
395
+ /**
396
+ * `false` marks the card sold out: a "Sold out" badge over the image, and
397
+ * the image desaturated. The card stays selectable. Absent or `true` shows no
398
+ * badge — leave it out when availability is unknown.
399
+ */
400
+ available?: boolean;
355
401
  }
356
402
  /**
357
403
  * How the product strip lays its cards out. `"row"` is the horizontally
@@ -562,12 +608,15 @@ declare function isCalendarFormat(format: FormatType): boolean;
562
608
  * them. A parameter called `travel_date` whose options are all spans is a span
563
609
  * parameter, whatever its name says.
564
610
  *
565
- * Accepts anything with a `type`, not a `Suggestion`, so re-edit can ask the
566
- * same question about a completed param via its `suggestionType`.
611
+ * Accepts anything with a `parameter`, not a `Suggestion`, so re-edit can ask
612
+ * the same question about a completed param via its `suggestionParameter`.
613
+ * A suggestion whose `type` names a date or date-range parameter is that,
614
+ * whatever its options and name say.
567
615
  */
568
616
  declare function resolveFormatType(source: {
569
- type: string;
617
+ parameter: string;
570
618
  options?: SuggestionOption[];
619
+ type?: SuggestionType;
571
620
  } | undefined | null): FormatType;
572
621
 
573
622
  /**
@@ -636,7 +685,7 @@ interface CoreInputState {
636
685
  * owns the pill on screen. Owned by `OptionSourceController`.
637
686
  */
638
687
  optionSearch: {
639
- type: string;
688
+ parameter: string;
640
689
  query: string;
641
690
  status: "loading" | "done";
642
691
  } | null;
@@ -739,7 +788,7 @@ interface CoreInputState {
739
788
  editingIdentified: {
740
789
  id: string;
741
790
  /** The identified param's type, which the committed param inherits. */
742
- type: string;
791
+ parameter: string;
743
792
  /** Plain-text offsets bounding the span being replaced. */
744
793
  anchor: number;
745
794
  tail: number;
@@ -1251,7 +1300,7 @@ declare class AIAutocomplete {
1251
1300
  * The skipped suggestion is recorded in `skippedParams` so every subsequent
1252
1301
  * request (and the submit result) carries it as a `completed_params` entry
1253
1302
  * with `text: "skipped"` — otherwise the server has no way to know the user
1254
- * declined it and keeps suggesting the same parameter. Deduped by type: the
1303
+ * declined it and keeps suggesting the same parameter. Deduped by parameter: the
1255
1304
  * same type skipped twice is one entry.
1256
1305
  *
1257
1306
  * When the last pill is removed there are no options left to show, so the
@@ -2109,6 +2158,12 @@ interface Store<S> {
2109
2158
  }
2110
2159
  declare function createStore<S>(initial: S): Store<S>;
2111
2160
 
2161
+ /**
2162
+ * The /suggest wire format this SDK speaks, sent as `meta.schema_version` on
2163
+ * every request. The server answers in the same format.
2164
+ */
2165
+ declare const SCHEMA_VERSION = "1.0";
2166
+
2112
2167
  /** Base URL for the "AI Autocomplete" branding/attribution link in the dropdown footer. */
2113
2168
  declare const ATTRIBUTION_URL = "https://ai-autocomplete.com";
2114
2169
  /**
@@ -2160,7 +2215,7 @@ declare function getFooterHint(optionHighlighted: boolean, isInputEmpty: boolean
2160
2215
  /**
2161
2216
  * Projects client-side identified-param state onto its wire shape.
2162
2217
  *
2163
- * The one place the `{ type, value }` form is spelled out. Both the request
2218
+ * The one place the `{ parameter, text }` form is spelled out. Both the request
2164
2219
  * body (`api.ts`) and the `AutocompleteResult` handed to `onResult` /
2165
2220
  * `onSubmit` go through it, so the params the consumer receives are exactly
2166
2221
  * the ones the server was told about.
@@ -2181,9 +2236,10 @@ declare const PRODUCT_PATH_PREFIX = "/products/";
2181
2236
  * `customFields` gets the same cards the built-in one draws.
2182
2237
  *
2183
2238
  * The link is the item's own `item_url` when the catalog named one, else the
2184
- * `/products/{handle}` path a Shopify item implies. An item with neither
2185
- * yields a card without a `url`: still activatable, still emitting
2186
- * `onProductSelect`, just nothing for cmd-click to open.
2239
+ * `/products/{handle}` path a Shopify item implies, opened on the chosen
2240
+ * variant when there is one. An item with neither yields a card without a
2241
+ * `url`: still activatable, still emitting `onProductSelect`, just nothing for
2242
+ * cmd-click to open.
2187
2243
  */
2188
2244
  declare function productFromMatchedItem(item: MatchedItem): Product;
2189
2245
  /**
@@ -2299,4 +2355,4 @@ interface SubmitResultExtras {
2299
2355
  */
2300
2356
  declare function buildSubmitResult(text: string, completedParams: CompletedParamState[], skippedParams?: SkippedParamState[], extras?: SubmitResultExtras): AutocompleteResult;
2301
2357
 
2302
- export { AIAutocomplete, type APIConfig, type APIKeyConfig, ATTRIBUTION_URL, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteRequest, type AutocompleteResponse, type AutocompleteResult, type CompletedParam, type CompletedParamState, type CoreOptions, type CoreState, type CustomFieldsReport, DATE_RANGE_META_END, DATE_RANGE_META_START, DEFAULT_OPTION_COUNT_UNIT, type DateMonthView, type DateRange, type DateSelection, type ExpressedFilter, type FilterOp, type FormatType, type IdentifiedParam, type IdentifiedParamState, type InputItem, type LooseDateOptions, type MatchedItem, type MatchedItems, ModeController, OPTIONS_GRID_MOBILE_QUERY, OPTION_ENTER_DELAY_VAR, OPTION_ENTER_FADE_MS, OPTION_ENTER_RISE_MS, OPTION_ENTER_RISE_PX, OPTION_ENTER_STAGGER_MS, type OptionOverride, type OptionOverrides, type OptionsGridLayout, type OptionsGridPlan, PLACEHOLDER_FADE_OUT_MS, PLACEHOLDER_LEAVING_ATTR, PLACEHOLDER_SWAP_GAP_MS, PLACEHOLDER_TYPE_MS, PLACEHOLDER_WORD_PAUSE_MS, PRODUCT_PATH_PREFIX, PRODUCT_ROW_PX_PER_LINE, type Product, type ProductImageFallback, type ProductRowMetrics, type ProductRowWheel, type ProductsConfig, type ProductsLayout, RANGE_SEPARATOR, type RecentlySuggested, type RenderMode, SCROLL_ARROW_ATTR, SCROLL_ARROW_BOTTOM_VAR, SCROLL_ARROW_CLASS, SCROLL_ARROW_FADE_MS, SCROLL_ARROW_LABEL, SCROLL_ARROW_SCROLL_IDLE_MS, SCROLL_ARROW_VISIBLE_ATTR, SKIPPED_PARAM_TEXT, type ScrollArrowArgs, type ScrollArrowController, type Segment, type SkippedParamState, type Store, type SubmitResultExtras, type Suggestion, type SuggestionOption, type TaskKind, WEEKDAY_LABELS, addMonths, attachProductRowWheel, attachScrollArrow, buildAttributionUrl, buildDateOptions, buildQuery, buildSubmitResult, cellDay, cellIso, chipIdFromTap, computeOptionsGridLayout, containScroll, createStore, cursorIsAtEnd, dateCellMarks, dateSelectionFor, extractPlainText, formatAbsoluteDate, formatDate, formatDateRange, formatOptionCount, getCursorOffset, getFooterHint, identifiedParamLabel, isCalendarFormat, isOptionsGridMobileViewport, isoDate, keepCaretOnChip, measureOptionsGrid, monthLabel, needsOptionsGridMeasurement, optionCountLabel, optionEnterDelayMs, optionHasImage, optionImageSrc, optionLabel, optionsEntranceDurationMs, optionsGridTemplateColumns, parseDate, parseLooseDate, parseLooseDateRange, plainTextLength, planOptionsGrid, previousGraphemeBoundary, productFromMatchedItem, productInitial, productRowWheelTarget, productsFromCustomFields, renderEditableContent, resolveFormatType, resolveIdentifiedDate, sameOptionRows, sanitizeOptionIconSvg, scrollCaretIntoView, selectedIsoFromText, selectedRangeFor, setCursorOffset, toWireIdentifiedParams, visibleDateRange, withSkippedParams };
2358
+ export { AIAutocomplete, type APIConfig, type APIKeyConfig, ATTRIBUTION_URL, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteRequest, type AutocompleteResponse, type AutocompleteResult, type CompletedParam, type CompletedParamState, type CoreOptions, type CoreState, type CustomFieldsReport, DATE_RANGE_META_END, DATE_RANGE_META_START, DEFAULT_OPTION_COUNT_UNIT, type DateMonthView, type DateRange, type DateSelection, type ExpressedFilter, type FilterOp, type FormatType, type IdentifiedParam, type IdentifiedParamState, type InputItem, type LooseDateOptions, type MatchedItem, type MatchedItems, ModeController, OPTIONS_GRID_MOBILE_QUERY, OPTION_ENTER_DELAY_VAR, OPTION_ENTER_FADE_MS, OPTION_ENTER_RISE_MS, OPTION_ENTER_RISE_PX, OPTION_ENTER_STAGGER_MS, type OptionOverride, type OptionOverrides, type OptionsGridLayout, type OptionsGridPlan, PLACEHOLDER_FADE_OUT_MS, PLACEHOLDER_LEAVING_ATTR, PLACEHOLDER_SWAP_GAP_MS, PLACEHOLDER_TYPE_MS, PLACEHOLDER_WORD_PAUSE_MS, PRODUCT_PATH_PREFIX, PRODUCT_ROW_PX_PER_LINE, type Product, type ProductImageFallback, type ProductRowMetrics, type ProductRowWheel, type ProductsConfig, type ProductsLayout, RANGE_SEPARATOR, type RecentlySuggested, type RenderMode, SCHEMA_VERSION, SCROLL_ARROW_ATTR, SCROLL_ARROW_BOTTOM_VAR, SCROLL_ARROW_CLASS, SCROLL_ARROW_FADE_MS, SCROLL_ARROW_LABEL, SCROLL_ARROW_SCROLL_IDLE_MS, SCROLL_ARROW_VISIBLE_ATTR, SKIPPED_PARAM_TEXT, type ScrollArrowArgs, type ScrollArrowController, type Segment, type SkippedParamState, type Store, type SubmitResultExtras, type Suggestion, type SuggestionOption, type SuggestionType, type TaskKind, WEEKDAY_LABELS, addMonths, attachProductRowWheel, attachScrollArrow, buildAttributionUrl, buildDateOptions, buildQuery, buildSubmitResult, cellDay, cellIso, chipIdFromTap, computeOptionsGridLayout, containScroll, createStore, cursorIsAtEnd, dateCellMarks, dateSelectionFor, extractPlainText, formatAbsoluteDate, formatDate, formatDateRange, formatOptionCount, getCursorOffset, getFooterHint, identifiedParamLabel, isCalendarFormat, isOptionsGridMobileViewport, isoDate, keepCaretOnChip, measureOptionsGrid, monthLabel, needsOptionsGridMeasurement, optionCountLabel, optionEnterDelayMs, optionHasImage, optionImageSrc, optionLabel, optionsEntranceDurationMs, optionsGridTemplateColumns, parseDate, parseLooseDate, parseLooseDateRange, plainTextLength, planOptionsGrid, previousGraphemeBoundary, productFromMatchedItem, productInitial, productRowWheelTarget, productsFromCustomFields, renderEditableContent, resolveFormatType, resolveIdentifiedDate, sameOptionRows, sanitizeOptionIconSvg, scrollCaretIntoView, selectedIsoFromText, selectedRangeFor, setCursorOffset, toWireIdentifiedParams, visibleDateRange, withSkippedParams };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  type TaskKind = "automation" | "email" | "insight";
2
2
  interface CompletedParam {
3
3
  placeholder: string;
4
- type: string;
4
+ parameter: string;
5
5
  text?: string;
6
6
  kind: TaskKind | null;
7
7
  }
@@ -49,15 +49,34 @@ interface SuggestionOption {
49
49
  is_tappable: boolean;
50
50
  kind: TaskKind | null;
51
51
  metadata?: Record<string, unknown>;
52
+ /**
53
+ * The parameter a tap on this option answers. The server names it on every
54
+ * option; options the SDK builds itself (a calendar's dates) carry their
55
+ * suggestion's.
56
+ */
57
+ parameter?: string;
58
+ }
59
+ /**
60
+ * The value type of a suggestion's parameter — which picker it needs. Present
61
+ * only for a date or date-range parameter.
62
+ */
63
+ interface SuggestionType {
64
+ kind: "string" | "numeric" | "date" | "date_range" | "boolean";
65
+ /** How a date is written, e.g. "DD/MM/YYYY". */
66
+ date_format?: string;
67
+ /** What joins the two dates of a range, e.g. " to ". */
68
+ separator?: string;
69
+ unit?: string;
52
70
  }
53
71
  interface Suggestion {
54
- type: string;
72
+ parameter: string;
55
73
  text: string;
56
74
  required: boolean;
57
75
  options?: SuggestionOption[];
76
+ type?: SuggestionType;
58
77
  }
59
78
  interface InputItem {
60
- type: string;
79
+ parameter: string;
61
80
  text: string;
62
81
  state: "completed" | "in_progress";
63
82
  /** Absent or "selected" = echo of client params; "identified" = LLM-inferred. */
@@ -65,15 +84,15 @@ interface InputItem {
65
84
  }
66
85
  /** Wire shape for an LLM-identified param echoed back to the server. */
67
86
  interface IdentifiedParam {
68
- type: string;
69
- value: string;
87
+ parameter: string;
88
+ text: string;
70
89
  }
71
90
  /**
72
91
  * Wire shape for a recently-suggested hint entry: a suggestion that was on
73
92
  * screen when the user started typing the current unresolved trailing text.
74
93
  */
75
94
  interface RecentlySuggested {
76
- type: string;
95
+ parameter: string;
77
96
  text: string;
78
97
  }
79
98
  interface AutocompleteRequest {
@@ -92,6 +111,8 @@ interface AutocompleteRequest {
92
111
  client_version: string;
93
112
  session_id: string;
94
113
  source?: "full-sdk" | "headless-sdk";
114
+ /** The wire format this SDK speaks ({@link SCHEMA_VERSION}). */
115
+ schema_version: string;
95
116
  };
96
117
  }
97
118
  interface AutocompleteResponse {
@@ -111,6 +132,8 @@ interface AutocompleteResponse {
111
132
  request_at: string;
112
133
  /** The server's funnel-telemetry switch. Absent means off: send no funnel events. */
113
134
  funnel_telemetry?: boolean;
135
+ /** The request's `schema_version`, echoed back. */
136
+ schema_version?: string;
114
137
  };
115
138
  }
116
139
  /** Comparison an {@link ExpressedFilter} applies to its value. */
@@ -120,7 +143,7 @@ type FilterOp = "eq" | "ne" | "lt" | "lte" | "gt" | "gte";
120
143
  * how the two compare ("price", "100", "lt").
121
144
  */
122
145
  interface ExpressedFilter {
123
- param: string;
146
+ parameter: string;
124
147
  value: string;
125
148
  op: FilterOp;
126
149
  }
@@ -154,6 +177,18 @@ interface MatchedItem {
154
177
  * item carries `handle` instead. When both are present the strip links here.
155
178
  */
156
179
  item_url?: string;
180
+ /**
181
+ * The variant a filter in the query chose for this item ("blue", "size 10"),
182
+ * as the platform's numeric variant id. When set, `price` and `image_url`
183
+ * are that variant's, and the strip links to `/products/{handle}?variant=…`
184
+ * so the shopper lands on it.
185
+ */
186
+ variant_id?: string;
187
+ /**
188
+ * Whether the item can be bought: `false` is sold out. Absent when the
189
+ * catalog doesn't say, which is not the same as sold out.
190
+ */
191
+ available?: boolean;
157
192
  }
158
193
  /** The items the applied filters left standing. */
159
194
  interface MatchedItems {
@@ -201,8 +236,13 @@ interface CompletedParamState extends CompletedParam {
201
236
  text: string;
202
237
  /** The originating option's `value` (see {@link SuggestionOption.value}), carried over so `toWireParam` can send it instead of the shortened `text`. */
203
238
  value?: string;
204
- /** Source suggestion's `type` — used by re-edit mode to render the dropdown pill. */
205
- suggestionType: string;
239
+ /** Source suggestion's `parameter` — used by re-edit mode to render the dropdown pill. */
240
+ suggestionParameter: string;
241
+ /**
242
+ * Source suggestion's `type` (its value type), carried so re-edit opens the
243
+ * same picker the first pick did — see {@link Suggestion.type}.
244
+ */
245
+ suggestionValueType?: SuggestionType;
206
246
  /** Source suggestion's `text` — used by re-edit mode to render the dropdown pill. */
207
247
  suggestionPlaceholder: string;
208
248
  /** Cached options from the suggestion that produced this param — re-edit shows these. */
@@ -241,8 +281,8 @@ interface CompletedParamState extends CompletedParam {
241
281
  */
242
282
  interface SkippedParamState {
243
283
  id: string;
244
- /** The skipped suggestion's `type` (e.g. "goal"). */
245
- type: string;
284
+ /** The skipped suggestion's `parameter` (e.g. "goal"). */
285
+ parameter: string;
246
286
  /** The suggestion's display text at skip time. Introspection only — never sent. */
247
287
  suggestionPlaceholder: string;
248
288
  }
@@ -253,7 +293,7 @@ interface SkippedParamState {
253
293
  */
254
294
  interface IdentifiedParamState {
255
295
  id: string;
256
- type: string;
296
+ parameter: string;
257
297
  text: string;
258
298
  }
259
299
  type Segment = {
@@ -352,6 +392,12 @@ interface Product {
352
392
  /** Pre-formatted by the integration, which is the side that knows the currency. */
353
393
  price?: string;
354
394
  vendor?: string;
395
+ /**
396
+ * `false` marks the card sold out: a "Sold out" badge over the image, and
397
+ * the image desaturated. The card stays selectable. Absent or `true` shows no
398
+ * badge — leave it out when availability is unknown.
399
+ */
400
+ available?: boolean;
355
401
  }
356
402
  /**
357
403
  * How the product strip lays its cards out. `"row"` is the horizontally
@@ -562,12 +608,15 @@ declare function isCalendarFormat(format: FormatType): boolean;
562
608
  * them. A parameter called `travel_date` whose options are all spans is a span
563
609
  * parameter, whatever its name says.
564
610
  *
565
- * Accepts anything with a `type`, not a `Suggestion`, so re-edit can ask the
566
- * same question about a completed param via its `suggestionType`.
611
+ * Accepts anything with a `parameter`, not a `Suggestion`, so re-edit can ask
612
+ * the same question about a completed param via its `suggestionParameter`.
613
+ * A suggestion whose `type` names a date or date-range parameter is that,
614
+ * whatever its options and name say.
567
615
  */
568
616
  declare function resolveFormatType(source: {
569
- type: string;
617
+ parameter: string;
570
618
  options?: SuggestionOption[];
619
+ type?: SuggestionType;
571
620
  } | undefined | null): FormatType;
572
621
 
573
622
  /**
@@ -636,7 +685,7 @@ interface CoreInputState {
636
685
  * owns the pill on screen. Owned by `OptionSourceController`.
637
686
  */
638
687
  optionSearch: {
639
- type: string;
688
+ parameter: string;
640
689
  query: string;
641
690
  status: "loading" | "done";
642
691
  } | null;
@@ -739,7 +788,7 @@ interface CoreInputState {
739
788
  editingIdentified: {
740
789
  id: string;
741
790
  /** The identified param's type, which the committed param inherits. */
742
- type: string;
791
+ parameter: string;
743
792
  /** Plain-text offsets bounding the span being replaced. */
744
793
  anchor: number;
745
794
  tail: number;
@@ -1251,7 +1300,7 @@ declare class AIAutocomplete {
1251
1300
  * The skipped suggestion is recorded in `skippedParams` so every subsequent
1252
1301
  * request (and the submit result) carries it as a `completed_params` entry
1253
1302
  * with `text: "skipped"` — otherwise the server has no way to know the user
1254
- * declined it and keeps suggesting the same parameter. Deduped by type: the
1303
+ * declined it and keeps suggesting the same parameter. Deduped by parameter: the
1255
1304
  * same type skipped twice is one entry.
1256
1305
  *
1257
1306
  * When the last pill is removed there are no options left to show, so the
@@ -2109,6 +2158,12 @@ interface Store<S> {
2109
2158
  }
2110
2159
  declare function createStore<S>(initial: S): Store<S>;
2111
2160
 
2161
+ /**
2162
+ * The /suggest wire format this SDK speaks, sent as `meta.schema_version` on
2163
+ * every request. The server answers in the same format.
2164
+ */
2165
+ declare const SCHEMA_VERSION = "1.0";
2166
+
2112
2167
  /** Base URL for the "AI Autocomplete" branding/attribution link in the dropdown footer. */
2113
2168
  declare const ATTRIBUTION_URL = "https://ai-autocomplete.com";
2114
2169
  /**
@@ -2160,7 +2215,7 @@ declare function getFooterHint(optionHighlighted: boolean, isInputEmpty: boolean
2160
2215
  /**
2161
2216
  * Projects client-side identified-param state onto its wire shape.
2162
2217
  *
2163
- * The one place the `{ type, value }` form is spelled out. Both the request
2218
+ * The one place the `{ parameter, text }` form is spelled out. Both the request
2164
2219
  * body (`api.ts`) and the `AutocompleteResult` handed to `onResult` /
2165
2220
  * `onSubmit` go through it, so the params the consumer receives are exactly
2166
2221
  * the ones the server was told about.
@@ -2181,9 +2236,10 @@ declare const PRODUCT_PATH_PREFIX = "/products/";
2181
2236
  * `customFields` gets the same cards the built-in one draws.
2182
2237
  *
2183
2238
  * The link is the item's own `item_url` when the catalog named one, else the
2184
- * `/products/{handle}` path a Shopify item implies. An item with neither
2185
- * yields a card without a `url`: still activatable, still emitting
2186
- * `onProductSelect`, just nothing for cmd-click to open.
2239
+ * `/products/{handle}` path a Shopify item implies, opened on the chosen
2240
+ * variant when there is one. An item with neither yields a card without a
2241
+ * `url`: still activatable, still emitting `onProductSelect`, just nothing for
2242
+ * cmd-click to open.
2187
2243
  */
2188
2244
  declare function productFromMatchedItem(item: MatchedItem): Product;
2189
2245
  /**
@@ -2299,4 +2355,4 @@ interface SubmitResultExtras {
2299
2355
  */
2300
2356
  declare function buildSubmitResult(text: string, completedParams: CompletedParamState[], skippedParams?: SkippedParamState[], extras?: SubmitResultExtras): AutocompleteResult;
2301
2357
 
2302
- export { AIAutocomplete, type APIConfig, type APIKeyConfig, ATTRIBUTION_URL, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteRequest, type AutocompleteResponse, type AutocompleteResult, type CompletedParam, type CompletedParamState, type CoreOptions, type CoreState, type CustomFieldsReport, DATE_RANGE_META_END, DATE_RANGE_META_START, DEFAULT_OPTION_COUNT_UNIT, type DateMonthView, type DateRange, type DateSelection, type ExpressedFilter, type FilterOp, type FormatType, type IdentifiedParam, type IdentifiedParamState, type InputItem, type LooseDateOptions, type MatchedItem, type MatchedItems, ModeController, OPTIONS_GRID_MOBILE_QUERY, OPTION_ENTER_DELAY_VAR, OPTION_ENTER_FADE_MS, OPTION_ENTER_RISE_MS, OPTION_ENTER_RISE_PX, OPTION_ENTER_STAGGER_MS, type OptionOverride, type OptionOverrides, type OptionsGridLayout, type OptionsGridPlan, PLACEHOLDER_FADE_OUT_MS, PLACEHOLDER_LEAVING_ATTR, PLACEHOLDER_SWAP_GAP_MS, PLACEHOLDER_TYPE_MS, PLACEHOLDER_WORD_PAUSE_MS, PRODUCT_PATH_PREFIX, PRODUCT_ROW_PX_PER_LINE, type Product, type ProductImageFallback, type ProductRowMetrics, type ProductRowWheel, type ProductsConfig, type ProductsLayout, RANGE_SEPARATOR, type RecentlySuggested, type RenderMode, SCROLL_ARROW_ATTR, SCROLL_ARROW_BOTTOM_VAR, SCROLL_ARROW_CLASS, SCROLL_ARROW_FADE_MS, SCROLL_ARROW_LABEL, SCROLL_ARROW_SCROLL_IDLE_MS, SCROLL_ARROW_VISIBLE_ATTR, SKIPPED_PARAM_TEXT, type ScrollArrowArgs, type ScrollArrowController, type Segment, type SkippedParamState, type Store, type SubmitResultExtras, type Suggestion, type SuggestionOption, type TaskKind, WEEKDAY_LABELS, addMonths, attachProductRowWheel, attachScrollArrow, buildAttributionUrl, buildDateOptions, buildQuery, buildSubmitResult, cellDay, cellIso, chipIdFromTap, computeOptionsGridLayout, containScroll, createStore, cursorIsAtEnd, dateCellMarks, dateSelectionFor, extractPlainText, formatAbsoluteDate, formatDate, formatDateRange, formatOptionCount, getCursorOffset, getFooterHint, identifiedParamLabel, isCalendarFormat, isOptionsGridMobileViewport, isoDate, keepCaretOnChip, measureOptionsGrid, monthLabel, needsOptionsGridMeasurement, optionCountLabel, optionEnterDelayMs, optionHasImage, optionImageSrc, optionLabel, optionsEntranceDurationMs, optionsGridTemplateColumns, parseDate, parseLooseDate, parseLooseDateRange, plainTextLength, planOptionsGrid, previousGraphemeBoundary, productFromMatchedItem, productInitial, productRowWheelTarget, productsFromCustomFields, renderEditableContent, resolveFormatType, resolveIdentifiedDate, sameOptionRows, sanitizeOptionIconSvg, scrollCaretIntoView, selectedIsoFromText, selectedRangeFor, setCursorOffset, toWireIdentifiedParams, visibleDateRange, withSkippedParams };
2358
+ export { AIAutocomplete, type APIConfig, type APIKeyConfig, ATTRIBUTION_URL, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteRequest, type AutocompleteResponse, type AutocompleteResult, type CompletedParam, type CompletedParamState, type CoreOptions, type CoreState, type CustomFieldsReport, DATE_RANGE_META_END, DATE_RANGE_META_START, DEFAULT_OPTION_COUNT_UNIT, type DateMonthView, type DateRange, type DateSelection, type ExpressedFilter, type FilterOp, type FormatType, type IdentifiedParam, type IdentifiedParamState, type InputItem, type LooseDateOptions, type MatchedItem, type MatchedItems, ModeController, OPTIONS_GRID_MOBILE_QUERY, OPTION_ENTER_DELAY_VAR, OPTION_ENTER_FADE_MS, OPTION_ENTER_RISE_MS, OPTION_ENTER_RISE_PX, OPTION_ENTER_STAGGER_MS, type OptionOverride, type OptionOverrides, type OptionsGridLayout, type OptionsGridPlan, PLACEHOLDER_FADE_OUT_MS, PLACEHOLDER_LEAVING_ATTR, PLACEHOLDER_SWAP_GAP_MS, PLACEHOLDER_TYPE_MS, PLACEHOLDER_WORD_PAUSE_MS, PRODUCT_PATH_PREFIX, PRODUCT_ROW_PX_PER_LINE, type Product, type ProductImageFallback, type ProductRowMetrics, type ProductRowWheel, type ProductsConfig, type ProductsLayout, RANGE_SEPARATOR, type RecentlySuggested, type RenderMode, SCHEMA_VERSION, SCROLL_ARROW_ATTR, SCROLL_ARROW_BOTTOM_VAR, SCROLL_ARROW_CLASS, SCROLL_ARROW_FADE_MS, SCROLL_ARROW_LABEL, SCROLL_ARROW_SCROLL_IDLE_MS, SCROLL_ARROW_VISIBLE_ATTR, SKIPPED_PARAM_TEXT, type ScrollArrowArgs, type ScrollArrowController, type Segment, type SkippedParamState, type Store, type SubmitResultExtras, type Suggestion, type SuggestionOption, type SuggestionType, type TaskKind, WEEKDAY_LABELS, addMonths, attachProductRowWheel, attachScrollArrow, buildAttributionUrl, buildDateOptions, buildQuery, buildSubmitResult, cellDay, cellIso, chipIdFromTap, computeOptionsGridLayout, containScroll, createStore, cursorIsAtEnd, dateCellMarks, dateSelectionFor, extractPlainText, formatAbsoluteDate, formatDate, formatDateRange, formatOptionCount, getCursorOffset, getFooterHint, identifiedParamLabel, isCalendarFormat, isOptionsGridMobileViewport, isoDate, keepCaretOnChip, measureOptionsGrid, monthLabel, needsOptionsGridMeasurement, optionCountLabel, optionEnterDelayMs, optionHasImage, optionImageSrc, optionLabel, optionsEntranceDurationMs, optionsGridTemplateColumns, parseDate, parseLooseDate, parseLooseDateRange, plainTextLength, planOptionsGrid, previousGraphemeBoundary, productFromMatchedItem, productInitial, productRowWheelTarget, productsFromCustomFields, renderEditableContent, resolveFormatType, resolveIdentifiedDate, sameOptionRows, sanitizeOptionIconSvg, scrollCaretIntoView, selectedIsoFromText, selectedRangeFor, setCursorOffset, toWireIdentifiedParams, visibleDateRange, withSkippedParams };