@findlane/server 0.15.0 → 0.16.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
@@ -48,6 +48,7 @@ const results = await products.search({ q }, { visitor: { ip: req.ip, userAgent:
48
48
  | Method | What it does |
49
49
  | --- | --- |
50
50
  | `search(request, options?)` | Search with a query, filters, facets, a sort, paging, and highlighting. `explain: true` says why each hit matched and what ordered it, and `appliedRules` lists the index's query rules the query fired. `options` takes `signal` and `visitor` (below). |
51
+ | `querySuggestions({ q, limit? })`, `popularSearches({ limit? })` | Whole searches to offer as a visitor types, `[{ q, typed }]`, and the index's popular searches for an empty box. Not counted as searches. |
51
52
  | `upsert(records)` | Add or update up to 1,000 records by `objectID`. |
52
53
  | `replaceAll(records)` | Replace the whole catalog in one request (up to 100,000 records). |
53
54
  | `replaceAllStaged(records, options)` | Replace a larger catalog in batches under one stage ID, switched in one commit. Retrying with the same `stageId` resumes. `abortReplacement(stageId)` drops a stage. |
package/dist/index.cjs CHANGED
@@ -253,6 +253,14 @@ class SearchServerClient {
253
253
  const { signal, visitor } = requestOptions(options);
254
254
  return (await request("/suggest", "POST", query, signal, visitorHeaders(visitor))).didYouMean;
255
255
  },
256
+ querySuggestions: async (query, options) => {
257
+ const { signal } = requestOptions(options);
258
+ return (await request("/query-suggestions", "POST", query, signal)).suggestions;
259
+ },
260
+ popularSearches: async (options = {}, requestOptionsOrSignal) => {
261
+ const { signal } = requestOptions(requestOptionsOrSignal);
262
+ return (await request("/query-suggestions", "POST", { q: "", limit: options.limit ?? 6 }, signal)).suggestions;
263
+ },
256
264
  recommendations: (objectID, options = {}, requestOptionsOrSignal) => {
257
265
  const { signal, visitor } = requestOptions(requestOptionsOrSignal);
258
266
  return request("/recommendations", "POST", { objectID, ...options }, signal, visitorHeaders(visitor));
package/dist/index.d.cts CHANGED
@@ -63,6 +63,9 @@ export type IndexSettings = {
63
63
  * Exact matches rank first. Searches use it once the index's word list is built, a minute or so after it's
64
64
  * turned on. Off by default. */
65
65
  compoundWords?: boolean;
66
+ /** Query suggestions: whole searches offered as shoppers type, and popular searches for an empty box,
67
+ * from what shoppers search and the catalog. On by default. Changes apply within a few minutes. */
68
+ querySuggestions?: QuerySuggestionSettings;
66
69
  normalizationProfile?: "default-v2" | "default-v1" | "icelandic-ascii-v1";
67
70
  /** An object field of lat and lng numbers, such as `_geoloc`, that `near` and `within` search; null for none. */
68
71
  locationField?: string | null;
@@ -71,6 +74,33 @@ export type IndexSettings = {
71
74
  fieldTypes?: Record<string, "text" | "number" | "boolean" | "text[]" | "number[]" | "boolean[]" | "location">;
72
75
  [key: string]: unknown;
73
76
  };
77
+ /** An index's query suggestion settings. When saving, give only those to change. */
78
+ export type QuerySuggestionSettings = {
79
+ /** false: no suggestions. */
80
+ enabled?: boolean;
81
+ /** false: no popular searches for an empty box; typed suggestions still use them. */
82
+ popularSearches?: boolean;
83
+ /** Popular searches an empty box shows, 1 to 10; 6 by default. */
84
+ popularCount?: number;
85
+ /** A shoppers' search becomes a suggestion once searched this many times (3 by default), on this many
86
+ * different days (2 by default). */
87
+ minSearches?: number;
88
+ minDays?: number;
89
+ /** The facet and searchable fields whose values are suggested, up to 20; null (the default) chooses
90
+ * readable ones from the records, leaving out slugs, sizes and long text. */
91
+ fields?: string[] | null;
92
+ /** Searches to suggest, up to 1,000; to show first, in the empty box too, up to 20; and never to show,
93
+ * nor anything with their words in a row, up to 1,000. One to six words each. */
94
+ added?: string[];
95
+ pinned?: string[];
96
+ hidden?: string[];
97
+ };
98
+ /** A whole search to offer as a shopper types, or in an empty box. `typed`: where what was typed is in
99
+ * `q`, as UTF-16 offsets (end exclusive); popular searches have none. */
100
+ export type QuerySuggestion = {
101
+ q: string;
102
+ typed?: [number, number];
103
+ };
74
104
  /** When a query is, starts with, or contains one of a rule's phrases, the rule's `then` applies to that
75
105
  * search. Phrases are compared as synonyms are: without case, accents, or the index languages' stop words,
76
106
  * and with their plurals and other spellings, so a rule for "balloon" also fires for "balloons". */
@@ -758,6 +788,18 @@ export declare class SearchServerClient {
758
788
  * same request (its q, filters, and fields matter). Needs the `didYouMean` setting; not counted as
759
789
  * a search. */
760
790
  suggest: (query: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<DidYouMean | null>;
791
+ /** Query suggestions: whole searches to offer as a shopper types `q`, the best first; with `q` empty, the
792
+ * index's popular searches. The API key needs the `search` scope; not counted as searches. `limit`: 1 to
793
+ * 10, 5 by default. */
794
+ querySuggestions: (query: {
795
+ q: string;
796
+ limit?: number;
797
+ }, options?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
798
+ /** The index's popular searches, for an empty search box, with the owner's pinned searches first;
799
+ * empty until the index has enough searches. The list changes daily. */
800
+ popularSearches: (options?: {
801
+ limit?: number;
802
+ }, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
761
803
  /** A product's recommendations (the recommendations add-on): products that go with it, and similar products.
762
804
  * The API key needs the `search` scope; not counted as a search. */
763
805
  recommendations: <R = T>(objectID: string, options?: RecommendationsRequest, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<RecommendationsResponse<R>>;
package/dist/index.d.ts CHANGED
@@ -63,6 +63,9 @@ export type IndexSettings = {
63
63
  * Exact matches rank first. Searches use it once the index's word list is built, a minute or so after it's
64
64
  * turned on. Off by default. */
65
65
  compoundWords?: boolean;
66
+ /** Query suggestions: whole searches offered as shoppers type, and popular searches for an empty box,
67
+ * from what shoppers search and the catalog. On by default. Changes apply within a few minutes. */
68
+ querySuggestions?: QuerySuggestionSettings;
66
69
  normalizationProfile?: "default-v2" | "default-v1" | "icelandic-ascii-v1";
67
70
  /** An object field of lat and lng numbers, such as `_geoloc`, that `near` and `within` search; null for none. */
68
71
  locationField?: string | null;
@@ -71,6 +74,33 @@ export type IndexSettings = {
71
74
  fieldTypes?: Record<string, "text" | "number" | "boolean" | "text[]" | "number[]" | "boolean[]" | "location">;
72
75
  [key: string]: unknown;
73
76
  };
77
+ /** An index's query suggestion settings. When saving, give only those to change. */
78
+ export type QuerySuggestionSettings = {
79
+ /** false: no suggestions. */
80
+ enabled?: boolean;
81
+ /** false: no popular searches for an empty box; typed suggestions still use them. */
82
+ popularSearches?: boolean;
83
+ /** Popular searches an empty box shows, 1 to 10; 6 by default. */
84
+ popularCount?: number;
85
+ /** A shoppers' search becomes a suggestion once searched this many times (3 by default), on this many
86
+ * different days (2 by default). */
87
+ minSearches?: number;
88
+ minDays?: number;
89
+ /** The facet and searchable fields whose values are suggested, up to 20; null (the default) chooses
90
+ * readable ones from the records, leaving out slugs, sizes and long text. */
91
+ fields?: string[] | null;
92
+ /** Searches to suggest, up to 1,000; to show first, in the empty box too, up to 20; and never to show,
93
+ * nor anything with their words in a row, up to 1,000. One to six words each. */
94
+ added?: string[];
95
+ pinned?: string[];
96
+ hidden?: string[];
97
+ };
98
+ /** A whole search to offer as a shopper types, or in an empty box. `typed`: where what was typed is in
99
+ * `q`, as UTF-16 offsets (end exclusive); popular searches have none. */
100
+ export type QuerySuggestion = {
101
+ q: string;
102
+ typed?: [number, number];
103
+ };
74
104
  /** When a query is, starts with, or contains one of a rule's phrases, the rule's `then` applies to that
75
105
  * search. Phrases are compared as synonyms are: without case, accents, or the index languages' stop words,
76
106
  * and with their plurals and other spellings, so a rule for "balloon" also fires for "balloons". */
@@ -758,6 +788,18 @@ export declare class SearchServerClient {
758
788
  * same request (its q, filters, and fields matter). Needs the `didYouMean` setting; not counted as
759
789
  * a search. */
760
790
  suggest: (query: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<DidYouMean | null>;
791
+ /** Query suggestions: whole searches to offer as a shopper types `q`, the best first; with `q` empty, the
792
+ * index's popular searches. The API key needs the `search` scope; not counted as searches. `limit`: 1 to
793
+ * 10, 5 by default. */
794
+ querySuggestions: (query: {
795
+ q: string;
796
+ limit?: number;
797
+ }, options?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
798
+ /** The index's popular searches, for an empty search box, with the owner's pinned searches first;
799
+ * empty until the index has enough searches. The list changes daily. */
800
+ popularSearches: (options?: {
801
+ limit?: number;
802
+ }, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
761
803
  /** A product's recommendations (the recommendations add-on): products that go with it, and similar products.
762
804
  * The API key needs the `search` scope; not counted as a search. */
763
805
  recommendations: <R = T>(objectID: string, options?: RecommendationsRequest, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<RecommendationsResponse<R>>;
package/dist/index.js CHANGED
@@ -207,6 +207,14 @@ class SearchServerClient {
207
207
  const { signal, visitor } = requestOptions(options);
208
208
  return (await request("/suggest", "POST", query, signal, visitorHeaders(visitor))).didYouMean;
209
209
  },
210
+ querySuggestions: async (query, options) => {
211
+ const { signal } = requestOptions(options);
212
+ return (await request("/query-suggestions", "POST", query, signal)).suggestions;
213
+ },
214
+ popularSearches: async (options = {}, requestOptionsOrSignal) => {
215
+ const { signal } = requestOptions(requestOptionsOrSignal);
216
+ return (await request("/query-suggestions", "POST", { q: "", limit: options.limit ?? 6 }, signal)).suggestions;
217
+ },
210
218
  recommendations: (objectID, options = {}, requestOptionsOrSignal) => {
211
219
  const { signal, visitor } = requestOptions(requestOptionsOrSignal);
212
220
  return request("/recommendations", "POST", { objectID, ...options }, signal, visitorHeaders(visitor));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@findlane/server",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Findlane server SDK: upload catalogs, manage index settings, and search with a secret workspace API key.",
5
5
  "keywords": ["findlane", "search", "full-text search", "typo tolerance", "ecommerce search", "search api", "sdk"],
6
6
  "license": "MIT",