@findlane/server 0.24.0 → 0.26.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/dist/index.d.ts CHANGED
@@ -394,6 +394,25 @@ export type SearchRequest = {
394
394
  /** Checks rules as at this time, in milliseconds since 1970, such as a campaign's start, instead of now
395
395
  * (0.20.0). Browser search doesn't take it. */
396
396
  rulesAt?: number;
397
+ /** The index's subindexes to search too, such as a store's categories and pages beside its products, by
398
+ * name: each with its own search, which takes this one's `q` and `highlight` unless it says, and 5 results
399
+ * unless it says, or `true` for that. Up to 5. Their results come back in `subindexes`; the search and its
400
+ * subindexes count as one search (0.25.0). */
401
+ subindexes?: Record<string, Omit<SearchRequest, "subindexes"> | true>;
402
+ };
403
+ /** A subindex whose search failed, such as one the index doesn't have (404). */
404
+ export type SubindexError = {
405
+ error: string;
406
+ status: number;
407
+ };
408
+ /** One of an index's subindexes: its full name (products.categories), its own name, and its records. */
409
+ export type Subindex = {
410
+ id: string;
411
+ name: string;
412
+ subindex: string;
413
+ kind: string | null;
414
+ status: string;
415
+ records: number;
397
416
  };
398
417
  /** A point in degrees: lat from -90 to 90, lng from -180 to 180. */
399
418
  export type GeoPoint = {
@@ -541,6 +560,8 @@ export type SearchResponse<T> = {
541
560
  }>;
542
561
  total: number;
543
562
  };
563
+ /** With `subindexes`: each subindex's results by name, or its error (0.25.0). */
564
+ subindexes?: Record<string, SearchResponse<JsonRecord> | SubindexError>;
544
565
  };
545
566
  /** How a product's recommendations are served (the recommendations add-on). */
546
567
  /** One of an index's lists (docs: Lists): a row of products, such as Popular or New arrivals, from a filter and
@@ -729,6 +750,13 @@ export type ServerEvent = {
729
750
  list?: "goesWith" | "similar" | "together" | "related";
730
751
  from?: string;
731
752
  timestamp?: number;
753
+ /** When the search wasn't made on the store but opened from outside it: an ad, an email, or another site's
754
+ * link. Revenue from search leaves these clicks out. */
755
+ landing?: "ad" | "email" | "link";
756
+ /** With `landing: "ad"`: the ad's network, from its click ID or tags. */
757
+ network?: "google" | "microsoft" | "meta" | "tiktok" | "x" | "linkedin" | "pinterest" | "snapchat";
758
+ /** The filters of the search the click came from, as the search took them, for sales by filter value. */
759
+ filters?: Record<string, unknown>;
732
760
  } | {
733
761
  type: "addToCart";
734
762
  items: EventItem[];
@@ -1094,6 +1122,8 @@ export type RevenueQuery = {
1094
1122
  carts: number;
1095
1123
  orders: number;
1096
1124
  revenue: number;
1125
+ /** Orders' value after this search when an ad, an email or another site opened it, not counted in `revenue`. */
1126
+ openedRevenue: number;
1097
1127
  typed: string[];
1098
1128
  };
1099
1129
  /** A product's orders and their value, beside those found through search, and the query it was found by most. */
@@ -1105,6 +1135,7 @@ export type RevenueProduct = {
1105
1135
  revenue: number;
1106
1136
  searchOrders: number;
1107
1137
  searchRevenue: number;
1138
+ openedRevenue: number;
1108
1139
  topQuery: string | null;
1109
1140
  };
1110
1141
  /** Revenue from search (0.20.0): purchases and add-to-carts of products the shopper clicked in search results in
@@ -1123,6 +1154,19 @@ export type RevenueReport = AnalyticsReport & {
1123
1154
  searchCarts: number;
1124
1155
  searchCartValue: number;
1125
1156
  searchClicks: number;
1157
+ /** Orders and add-to-carts after searches an ad, an email or another site's link opened (0.26.0): the shopper didn't
1158
+ * search, so they're left out of the search numbers. By kind, with the clicks on such searches. */
1159
+ opened: {
1160
+ orders: number;
1161
+ revenue: number;
1162
+ carts: number;
1163
+ cartValue: number;
1164
+ clicks: number;
1165
+ byKind: Record<"ad" | "email" | "link", {
1166
+ orders: number;
1167
+ revenue: number;
1168
+ }>;
1169
+ };
1126
1170
  otherCurrencies: {
1127
1171
  currency: string;
1128
1172
  orders: number;
@@ -1143,6 +1187,31 @@ export type RevenueReport = AnalyticsReport & {
1143
1187
  /** The products bought after a search, the most revenue from search first, up to 50. */
1144
1188
  products: RevenueProduct[];
1145
1189
  };
1190
+ /** A filter value's clicks on results while it was chosen, and the add-to-carts, orders and revenue of the products
1191
+ * clicked. */
1192
+ export type FilterValueSales = {
1193
+ value: string;
1194
+ clicks: number;
1195
+ carts: number;
1196
+ orders: number;
1197
+ revenue: number;
1198
+ };
1199
+ /** Sales by filter value (0.26.0): for each facet field, the values shoppers filtered on, on searches and on category
1200
+ * pages apart, attributed as revenue from search is. A click with several values counts for each. From when clicks
1201
+ * started carrying filters (`since`). */
1202
+ export type FilterSalesReport = AnalyticsReport & {
1203
+ computedAt: string;
1204
+ since: string;
1205
+ currency: string | null;
1206
+ fields: {
1207
+ field: string;
1208
+ search: FilterValueSales[];
1209
+ page: FilterValueSales[];
1210
+ }[];
1211
+ /** Searches without filters, to compare with. */
1212
+ unfiltered: Omit<FilterValueSales, "value">;
1213
+ visitorIds: boolean;
1214
+ };
1146
1215
  export declare class FindlaneError extends Error {
1147
1216
  status: number;
1148
1217
  constructor(status: number, message: string);
@@ -1330,6 +1399,8 @@ export declare class SearchServerClient {
1330
1399
  /** Revenue from search: orders and add-to-carts of products found through search, per query and per
1331
1400
  * product (0.20.0). */
1332
1401
  revenue: (options?: Omit<AnalyticsOptions, "source">) => Promise<RevenueReport>;
1402
+ /** Sales by filter value: each facet value's clicks, add-to-carts, orders and revenue (0.26.0). */
1403
+ filterSales: (options?: Omit<AnalyticsOptions, "source">) => Promise<FilterSalesReport>;
1333
1404
  /** Each banner's shown (shoppers' searches that showed it, cache answers included) and clicks, by its rule,
1334
1405
  * over the last 7, 30 (by default) or 90 days (0.23.0). */
1335
1406
  banners: (options?: {
@@ -1366,6 +1437,2193 @@ export declare class SearchServerClient {
1366
1437
  intervalMs?: number;
1367
1438
  signal?: AbortSignal;
1368
1439
  }) => Promise<CurrentSettings>;
1440
+ /** A subindex of this index (0.25.0), such as `index("products").subindex("categories")`: an index of its own,
1441
+ * named products.categories, searched with this one (`subindexes` in a search) and opened by its keys. */
1442
+ subindex: <S extends {
1443
+ objectID: string;
1444
+ } = JsonRecord>(subindex: string) => {
1445
+ /** Searches the index; the API key needs the `search` scope. Pass `{ visitor }` when searching for
1446
+ * someone, such as a shopper loading a server-rendered page (see Visitor). */
1447
+ search: <R = S>(query?: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<SearchResponse<R>>;
1448
+ /** Did you mean: for a search that found nothing, a query that finds something, or null. Takes the
1449
+ * same request (its q, filters, and fields matter). Needs the `didYouMean` setting; not counted as
1450
+ * a search. */
1451
+ suggest: (query: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<DidYouMean | null>;
1452
+ /** Query suggestions: whole searches to offer as a shopper types `q`, the best first; with `q` empty, the
1453
+ * index's popular searches. The API key needs the `search` scope; not counted as searches. `limit`: 1 to
1454
+ * 10, 5 by default. */
1455
+ querySuggestions: (query: {
1456
+ q: string;
1457
+ limit?: number;
1458
+ }, options?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
1459
+ /** The index's popular searches, for an empty search box, with the owner's pinned searches first;
1460
+ * empty until the index has enough searches. The list changes daily. */
1461
+ popularSearches: (options?: {
1462
+ limit?: number;
1463
+ }, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
1464
+ /** A product's recommendations (the recommendations add-on): products that go with it, and similar products.
1465
+ * The API key needs the `search` scope; not counted as a search. */
1466
+ recommendations: <R = S>(objectID: string, options?: RecommendationsRequest, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<RecommendationsResponse<R>>;
1467
+ /** The index's lists: rows of products, such as Popular, and facet fields' values for menus, built ahead
1468
+ * and served from a cache, so reading them isn't counted as searches. Reading needs the `search` scope;
1469
+ * setting them up needs `write`. */
1470
+ /** Merchandising (0.23.0): category pages and searches arranged as the dashboard's Merchandising page does:
1471
+ * the products placed first, hidden products, a banner, and when. Saved as the page's rule within seconds,
1472
+ * keeping anything else the rule does. Reading needs the `search` or `write` scope; changing, `write`. */
1473
+ merchandising: {
1474
+ /** Every arranged category page and search. */
1475
+ list: (signal?: AbortSignal) => Promise<Arrangement[]>;
1476
+ /** One page's or search's arrangement; status "none" when nothing is arranged. */
1477
+ get: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
1478
+ /** Changes one: `order` up to 20 objectIDs placed first, `hidden` up to 100, `banner` ({ image, link?, title?,
1479
+ * position? } or null), `active` ({ from?, until? } or null), `enabled`. Fields left out stay as they are. */
1480
+ set: (target: MerchandisingTarget, change: ArrangementChange, signal?: AbortSignal) => Promise<Arrangement>;
1481
+ /** Stops arranging one: its order, hidden products and banner go; the rule's other actions stay. */
1482
+ remove: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
1483
+ };
1484
+ /** Images for the index's banners, hosted by Findlane at https://images.findlane.dev (0.23.0): JPEG, PNG,
1485
+ * WebP or AVIF, up to 2 MB each, 50 images and 100 MB an index. An image no rule shows is deleted a week
1486
+ * later. Uploading and deleting need the `write` scope. */
1487
+ images: {
1488
+ list: (signal?: AbortSignal) => Promise<ImageLibrary>;
1489
+ /** Uploads an image's bytes; the same image again gives the same URL. */
1490
+ upload: (image: Blob | ArrayBuffer | Uint8Array, options?: {
1491
+ contentType?: string;
1492
+ signal?: AbortSignal;
1493
+ }) => Promise<UploadedImage & {
1494
+ error?: string;
1495
+ }>;
1496
+ /** Uploads the image at an https address, which Findlane fetches. */
1497
+ uploadFromUrl: (url: string, signal?: AbortSignal) => Promise<UploadedImage>;
1498
+ /** Deletes an image by its key; refused (409) while a rule's banner shows it. */
1499
+ delete: (key: string, signal?: AbortSignal) => Promise<{
1500
+ deleted: true;
1501
+ }>;
1502
+ };
1503
+ /** The index's product feed (0.24.0): a store's Google or Meta product feed, or a JSON file of records, read on
1504
+ * a schedule (hourly, every 6 hours, or daily), replacing the index's records with only what changed. Reading
1505
+ * needs the `search` or `write` scope; the rest, `write`. */
1506
+ feed: {
1507
+ /** The feed and its last run, or null. */
1508
+ get: (signal?: AbortSignal) => Promise<ProductFeed | null>;
1509
+ /** Connects a feed or changes its setup; a new address, sign-in or variants setting reads it now. */
1510
+ set: (setup: FeedSetup, signal?: AbortSignal) => Promise<ProductFeed>;
1511
+ /** Disconnects it; the index keeps its records. */
1512
+ remove: (signal?: AbortSignal) => Promise<void>;
1513
+ /** Reads a feed's first 2,000 items without saving anything; without a url, the connected feed's. */
1514
+ check: (setup?: Pick<FeedSetup, "url" | "username" | "password" | "variants">, signal?: AbortSignal) => Promise<FeedCheck>;
1515
+ /** Reads it now, in full, in the background; `runs` shows how it went. */
1516
+ run: (signal?: AbortSignal) => Promise<FeedRun>;
1517
+ /** The last 20 runs, newest first. */
1518
+ runs: (signal?: AbortSignal) => Promise<FeedRun[]>;
1519
+ /** Imports a held run's copy of the feed as it is, without the checks that held it. */
1520
+ importHeld: (runId: string, signal?: AbortSignal) => Promise<FeedRun>;
1521
+ };
1522
+ lists: {
1523
+ /** One list by its ID; throws a FindlaneError with status 404 when there's none. `limit` shows fewer. */
1524
+ get: <R = S>(id: string, options?: {
1525
+ limit?: number;
1526
+ signal?: AbortSignal;
1527
+ }) => Promise<List<R>>;
1528
+ /** Several lists (up to 10) in the order asked, leaving out IDs without a list; without IDs, all of them. */
1529
+ getMany: <R = S>(ids?: string[], options?: {
1530
+ limit?: number;
1531
+ signal?: AbortSignal;
1532
+ }) => Promise<List<R>[]>;
1533
+ /** How the index's lists are set up, and their last build. */
1534
+ settings: (signal?: AbortSignal) => Promise<ListSettings>;
1535
+ /** Creates or changes a list and builds it; one whose filters, sort or field don't work on the index is
1536
+ * refused with why (400), and a new list past the plan's lists per index too (402). */
1537
+ save: (id: string, list: ListDefinition, signal?: AbortSignal) => Promise<ListSettings>;
1538
+ delete: (id: string, signal?: AbortSignal) => Promise<ListSettings>;
1539
+ /** Puts the lists in this order: every list's ID once. */
1540
+ order: (ids: string[], signal?: AbortSignal) => Promise<ListSettings>;
1541
+ /** Builds the lists again now, rather than within the minute they take to follow the index; once a minute. */
1542
+ refresh: (signal?: AbortSignal) => Promise<ListSettings>;
1543
+ /** What a list would hold, built without saving it. */
1544
+ preview: <R = S>(list: ListDefinition, signal?: AbortSignal) => Promise<{
1545
+ list: List<R>;
1546
+ tookMs: number;
1547
+ }>;
1548
+ };
1549
+ /** Events for the index's Events page and Bought together; the API key needs the `events` or `write`
1550
+ * scope. Orders count once each, however often they're sent. */
1551
+ events: {
1552
+ /** Sends events, 200 a request. One bad event doesn't refuse the rest: they're in `rejected`. Pass
1553
+ * `{ visitorId, visitId }` to link a shopper's events (see EventOptions). */
1554
+ send: (events: ServerEvent[], options?: AbortSignal | EventOptions) => Promise<EventsResult>;
1555
+ /** Sends past orders, up to 400 days old, from a list or an async iterable (such as a database
1556
+ * cursor), 200 a request. */
1557
+ importOrders: (orders: Iterable<Order> | AsyncIterable<Order>, signal?: AbortSignal) => Promise<EventsResult>;
1558
+ /** Takes a cancelled or refunded order out of Bought together. */
1559
+ cancelOrder: (orderID: string, signal?: AbortSignal) => Promise<EventsResult>;
1560
+ /** Deletes the events sent with these visitor or visit IDs, for shoppers who asked: Findlane does it
1561
+ * within a week. 1,000 IDs a request. */
1562
+ forget: (ids: string[], signal?: AbortSignal) => Promise<{
1563
+ forgotten: number;
1564
+ }>;
1565
+ /** A route on your own domain for the browser SDK's events (its `eventsUrl` option): ad blockers
1566
+ * block beacons to other sites, not to the page's own. Give it the browser's POST request (Next.js
1567
+ * route handlers, Workers, Hono, Bun, Deno); it finds the visitor's address in the headers
1568
+ * Cloudflare, Vercel and most proxies set. Where a visitor reaches your server directly, they can
1569
+ * set those too, so pass `{ ip }`. The API key needs the `events` or `write` scope. */
1570
+ proxy: (request: Request, visitor?: Partial<RelayedVisitor>) => Promise<Response>;
1571
+ /** `proxy` for servers without Fetch API requests, such as Express: the request's body as text,
1572
+ * and its visitor. Answers with the API's response. */
1573
+ relay: (body: string, visitor: RelayedVisitor, signal?: AbortSignal) => Promise<Response>;
1574
+ };
1575
+ /** The index's search analytics. The API key needs the `analytics` scope, and works only from a server:
1576
+ * requests from web pages are refused. */
1577
+ analytics: {
1578
+ /** Searches, searches without results and response times, beside the same span before, and a series per
1579
+ * hour (up to 7 days, by default) or day. */
1580
+ searches: (options?: AnalyticsOptions & {
1581
+ interval?: "hour" | "day";
1582
+ }) => Promise<SearchesReport>;
1583
+ /** Queries, the most searched first: `top` (by default) with their clicks, `noResults`, or `noClicks`, which
1584
+ * found something nobody clicked. `limit` is 1 to 1,000, 100 by default. */
1585
+ queries: <L extends keyof QueryLists = "top">(options?: AnalyticsOptions & {
1586
+ list?: L | undefined;
1587
+ limit?: number;
1588
+ }) => Promise<QueriesReport<L>>;
1589
+ /** The filter fields and sorts searches used. */
1590
+ filters: (options?: AnalyticsOptions) => Promise<FiltersReport>;
1591
+ /** Events of each type over time and by source, orders stored, and refused and bot events. */
1592
+ events: (options?: AnalyticsOptions & {
1593
+ interval?: "hour" | "day";
1594
+ }) => Promise<EventsReport>;
1595
+ /** The most viewed, most added to carts and most ordered products, with titles and images, and those
1596
+ * viewed but rarely bought. Exact, from every event kept (13 months, from 9 October 2026). */
1597
+ products: (options?: AnalyticsOptions) => Promise<ProductListsReport>;
1598
+ /** Every product with events or orders in the window, the most viewed first, up to 50,000: views,
1599
+ * viewers, clicks, add-to-carts and orders. Exact, like `products`. */
1600
+ productCounts: (options?: AnalyticsOptions) => Promise<ProductCountsReport>;
1601
+ /** One product's views, viewers, clicks, add-to-carts and orders per hour or day, the queries it was
1602
+ * clicked from, and its clicks in recommendations. Fast, for a product page in an admin: views and
1603
+ * clicks are estimates when `sampled`, and an add-to-cart of several products counts toward the first. */
1604
+ product: (objectID: string, options?: AnalyticsOptions & {
1605
+ interval?: "hour" | "day";
1606
+ }) => Promise<ProductReport>;
1607
+ /** Revenue from search: orders and add-to-carts of products found through search, per query and per
1608
+ * product (0.20.0). */
1609
+ revenue: (options?: Omit<AnalyticsOptions, "source">) => Promise<RevenueReport>;
1610
+ /** Sales by filter value: each facet value's clicks, add-to-carts, orders and revenue (0.26.0). */
1611
+ filterSales: (options?: Omit<AnalyticsOptions, "source">) => Promise<FilterSalesReport>;
1612
+ /** Each banner's shown (shoppers' searches that showed it, cache answers included) and clicks, by its rule,
1613
+ * over the last 7, 30 (by default) or 90 days (0.23.0). */
1614
+ banners: (options?: {
1615
+ range?: "7d" | "30d" | "90d";
1616
+ signal?: AbortSignal;
1617
+ }) => Promise<BannerStatsReport>;
1618
+ };
1619
+ upsert: (records: S[], signal?: AbortSignal) => Promise<WriteReceipt>;
1620
+ getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S>>;
1621
+ upsertOne: (record: S, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
1622
+ deleteOne: (objectID: string, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
1623
+ replaceAll: (records: S[], signal?: AbortSignal) => Promise<WriteReceipt>;
1624
+ beginReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
1625
+ uploadReplacementBatch: (stageId: string, batchId: string, records: S[], signal?: AbortSignal) => Promise<ReplacementStage>;
1626
+ commitReplacement: (stageId: string, expectedBatches: number, expectedRecords: number, signal?: AbortSignal) => Promise<WriteReceipt>;
1627
+ abortReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
1628
+ replaceAllStaged: (records: Iterable<S> | AsyncIterable<S>, options?: StagedReplaceOptions) => Promise<WriteReceipt>;
1629
+ delete: (objectID: string, signal?: AbortSignal) => Promise<WriteReceipt>;
1630
+ getSettings: (signal?: AbortSignal) => Promise<CurrentSettings>;
1631
+ replaceSettings: (settings: IndexSettings, signal?: AbortSignal) => Promise<SavedSettings>;
1632
+ /** Compares settings with the index's own without saving them: its search tests, `queries`, and its 100
1633
+ * most searched queries of the last 30 days, each searched with both, for up to 20 seconds. Takes the
1634
+ * settings `replaceSettings` does, or only those that change; `{}` runs the tests with the current
1635
+ * settings. A change to what the index stores (new searchable, facet, filter, sort or location fields,
1636
+ * or normalization) throws a 409: save it first. Not counted as searches. */
1637
+ compareSettings: (settings: Partial<IndexSettings>, options?: CompareOptions) => Promise<SettingsComparison>;
1638
+ /** The index's search tests. */
1639
+ getSearchTests: (signal?: AbortSignal) => Promise<SearchTest[]>;
1640
+ /** Replaces the index's search tests, up to 200; `[]` deletes them. */
1641
+ setSearchTests: (tests: SearchTest[], signal?: AbortSignal) => Promise<SearchTest[]>;
1642
+ /** Waits until no settings rebuild is running; throws if it failed. */
1643
+ waitForSettings: (options?: {
1644
+ timeoutMs?: number;
1645
+ intervalMs?: number;
1646
+ signal?: AbortSignal;
1647
+ }) => Promise<CurrentSettings>;
1648
+ subindex: <S_1 extends {
1649
+ objectID: string;
1650
+ } = JsonRecord>(subindex: string) => {
1651
+ /** Searches the index; the API key needs the `search` scope. Pass `{ visitor }` when searching for
1652
+ * someone, such as a shopper loading a server-rendered page (see Visitor). */
1653
+ search: <R = S_1>(query?: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<SearchResponse<R>>;
1654
+ /** Did you mean: for a search that found nothing, a query that finds something, or null. Takes the
1655
+ * same request (its q, filters, and fields matter). Needs the `didYouMean` setting; not counted as
1656
+ * a search. */
1657
+ suggest: (query: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<DidYouMean | null>;
1658
+ /** Query suggestions: whole searches to offer as a shopper types `q`, the best first; with `q` empty, the
1659
+ * index's popular searches. The API key needs the `search` scope; not counted as searches. `limit`: 1 to
1660
+ * 10, 5 by default. */
1661
+ querySuggestions: (query: {
1662
+ q: string;
1663
+ limit?: number;
1664
+ }, options?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
1665
+ /** The index's popular searches, for an empty search box, with the owner's pinned searches first;
1666
+ * empty until the index has enough searches. The list changes daily. */
1667
+ popularSearches: (options?: {
1668
+ limit?: number;
1669
+ }, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
1670
+ /** A product's recommendations (the recommendations add-on): products that go with it, and similar products.
1671
+ * The API key needs the `search` scope; not counted as a search. */
1672
+ recommendations: <R = S_1>(objectID: string, options?: RecommendationsRequest, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<RecommendationsResponse<R>>;
1673
+ /** The index's lists: rows of products, such as Popular, and facet fields' values for menus, built ahead
1674
+ * and served from a cache, so reading them isn't counted as searches. Reading needs the `search` scope;
1675
+ * setting them up needs `write`. */
1676
+ /** Merchandising (0.23.0): category pages and searches arranged as the dashboard's Merchandising page does:
1677
+ * the products placed first, hidden products, a banner, and when. Saved as the page's rule within seconds,
1678
+ * keeping anything else the rule does. Reading needs the `search` or `write` scope; changing, `write`. */
1679
+ merchandising: {
1680
+ /** Every arranged category page and search. */
1681
+ list: (signal?: AbortSignal) => Promise<Arrangement[]>;
1682
+ /** One page's or search's arrangement; status "none" when nothing is arranged. */
1683
+ get: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
1684
+ /** Changes one: `order` up to 20 objectIDs placed first, `hidden` up to 100, `banner` ({ image, link?, title?,
1685
+ * position? } or null), `active` ({ from?, until? } or null), `enabled`. Fields left out stay as they are. */
1686
+ set: (target: MerchandisingTarget, change: ArrangementChange, signal?: AbortSignal) => Promise<Arrangement>;
1687
+ /** Stops arranging one: its order, hidden products and banner go; the rule's other actions stay. */
1688
+ remove: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
1689
+ };
1690
+ /** Images for the index's banners, hosted by Findlane at https://images.findlane.dev (0.23.0): JPEG, PNG,
1691
+ * WebP or AVIF, up to 2 MB each, 50 images and 100 MB an index. An image no rule shows is deleted a week
1692
+ * later. Uploading and deleting need the `write` scope. */
1693
+ images: {
1694
+ list: (signal?: AbortSignal) => Promise<ImageLibrary>;
1695
+ /** Uploads an image's bytes; the same image again gives the same URL. */
1696
+ upload: (image: Blob | ArrayBuffer | Uint8Array, options?: {
1697
+ contentType?: string;
1698
+ signal?: AbortSignal;
1699
+ }) => Promise<UploadedImage & {
1700
+ error?: string;
1701
+ }>;
1702
+ /** Uploads the image at an https address, which Findlane fetches. */
1703
+ uploadFromUrl: (url: string, signal?: AbortSignal) => Promise<UploadedImage>;
1704
+ /** Deletes an image by its key; refused (409) while a rule's banner shows it. */
1705
+ delete: (key: string, signal?: AbortSignal) => Promise<{
1706
+ deleted: true;
1707
+ }>;
1708
+ };
1709
+ /** The index's product feed (0.24.0): a store's Google or Meta product feed, or a JSON file of records, read on
1710
+ * a schedule (hourly, every 6 hours, or daily), replacing the index's records with only what changed. Reading
1711
+ * needs the `search` or `write` scope; the rest, `write`. */
1712
+ feed: {
1713
+ /** The feed and its last run, or null. */
1714
+ get: (signal?: AbortSignal) => Promise<ProductFeed | null>;
1715
+ /** Connects a feed or changes its setup; a new address, sign-in or variants setting reads it now. */
1716
+ set: (setup: FeedSetup, signal?: AbortSignal) => Promise<ProductFeed>;
1717
+ /** Disconnects it; the index keeps its records. */
1718
+ remove: (signal?: AbortSignal) => Promise<void>;
1719
+ /** Reads a feed's first 2,000 items without saving anything; without a url, the connected feed's. */
1720
+ check: (setup?: Pick<FeedSetup, "url" | "username" | "password" | "variants">, signal?: AbortSignal) => Promise<FeedCheck>;
1721
+ /** Reads it now, in full, in the background; `runs` shows how it went. */
1722
+ run: (signal?: AbortSignal) => Promise<FeedRun>;
1723
+ /** The last 20 runs, newest first. */
1724
+ runs: (signal?: AbortSignal) => Promise<FeedRun[]>;
1725
+ /** Imports a held run's copy of the feed as it is, without the checks that held it. */
1726
+ importHeld: (runId: string, signal?: AbortSignal) => Promise<FeedRun>;
1727
+ };
1728
+ lists: {
1729
+ /** One list by its ID; throws a FindlaneError with status 404 when there's none. `limit` shows fewer. */
1730
+ get: <R = S_1>(id: string, options?: {
1731
+ limit?: number;
1732
+ signal?: AbortSignal;
1733
+ }) => Promise<List<R>>;
1734
+ /** Several lists (up to 10) in the order asked, leaving out IDs without a list; without IDs, all of them. */
1735
+ getMany: <R = S_1>(ids?: string[], options?: {
1736
+ limit?: number;
1737
+ signal?: AbortSignal;
1738
+ }) => Promise<List<R>[]>;
1739
+ /** How the index's lists are set up, and their last build. */
1740
+ settings: (signal?: AbortSignal) => Promise<ListSettings>;
1741
+ /** Creates or changes a list and builds it; one whose filters, sort or field don't work on the index is
1742
+ * refused with why (400), and a new list past the plan's lists per index too (402). */
1743
+ save: (id: string, list: ListDefinition, signal?: AbortSignal) => Promise<ListSettings>;
1744
+ delete: (id: string, signal?: AbortSignal) => Promise<ListSettings>;
1745
+ /** Puts the lists in this order: every list's ID once. */
1746
+ order: (ids: string[], signal?: AbortSignal) => Promise<ListSettings>;
1747
+ /** Builds the lists again now, rather than within the minute they take to follow the index; once a minute. */
1748
+ refresh: (signal?: AbortSignal) => Promise<ListSettings>;
1749
+ /** What a list would hold, built without saving it. */
1750
+ preview: <R = S_1>(list: ListDefinition, signal?: AbortSignal) => Promise<{
1751
+ list: List<R>;
1752
+ tookMs: number;
1753
+ }>;
1754
+ };
1755
+ /** Events for the index's Events page and Bought together; the API key needs the `events` or `write`
1756
+ * scope. Orders count once each, however often they're sent. */
1757
+ events: {
1758
+ /** Sends events, 200 a request. One bad event doesn't refuse the rest: they're in `rejected`. Pass
1759
+ * `{ visitorId, visitId }` to link a shopper's events (see EventOptions). */
1760
+ send: (events: ServerEvent[], options?: AbortSignal | EventOptions) => Promise<EventsResult>;
1761
+ /** Sends past orders, up to 400 days old, from a list or an async iterable (such as a database
1762
+ * cursor), 200 a request. */
1763
+ importOrders: (orders: Iterable<Order> | AsyncIterable<Order>, signal?: AbortSignal) => Promise<EventsResult>;
1764
+ /** Takes a cancelled or refunded order out of Bought together. */
1765
+ cancelOrder: (orderID: string, signal?: AbortSignal) => Promise<EventsResult>;
1766
+ /** Deletes the events sent with these visitor or visit IDs, for shoppers who asked: Findlane does it
1767
+ * within a week. 1,000 IDs a request. */
1768
+ forget: (ids: string[], signal?: AbortSignal) => Promise<{
1769
+ forgotten: number;
1770
+ }>;
1771
+ /** A route on your own domain for the browser SDK's events (its `eventsUrl` option): ad blockers
1772
+ * block beacons to other sites, not to the page's own. Give it the browser's POST request (Next.js
1773
+ * route handlers, Workers, Hono, Bun, Deno); it finds the visitor's address in the headers
1774
+ * Cloudflare, Vercel and most proxies set. Where a visitor reaches your server directly, they can
1775
+ * set those too, so pass `{ ip }`. The API key needs the `events` or `write` scope. */
1776
+ proxy: (request: Request, visitor?: Partial<RelayedVisitor>) => Promise<Response>;
1777
+ /** `proxy` for servers without Fetch API requests, such as Express: the request's body as text,
1778
+ * and its visitor. Answers with the API's response. */
1779
+ relay: (body: string, visitor: RelayedVisitor, signal?: AbortSignal) => Promise<Response>;
1780
+ };
1781
+ /** The index's search analytics. The API key needs the `analytics` scope, and works only from a server:
1782
+ * requests from web pages are refused. */
1783
+ analytics: {
1784
+ /** Searches, searches without results and response times, beside the same span before, and a series per
1785
+ * hour (up to 7 days, by default) or day. */
1786
+ searches: (options?: AnalyticsOptions & {
1787
+ interval?: "hour" | "day";
1788
+ }) => Promise<SearchesReport>;
1789
+ /** Queries, the most searched first: `top` (by default) with their clicks, `noResults`, or `noClicks`, which
1790
+ * found something nobody clicked. `limit` is 1 to 1,000, 100 by default. */
1791
+ queries: <L extends keyof QueryLists = "top">(options?: AnalyticsOptions & {
1792
+ list?: L | undefined;
1793
+ limit?: number;
1794
+ }) => Promise<QueriesReport<L>>;
1795
+ /** The filter fields and sorts searches used. */
1796
+ filters: (options?: AnalyticsOptions) => Promise<FiltersReport>;
1797
+ /** Events of each type over time and by source, orders stored, and refused and bot events. */
1798
+ events: (options?: AnalyticsOptions & {
1799
+ interval?: "hour" | "day";
1800
+ }) => Promise<EventsReport>;
1801
+ /** The most viewed, most added to carts and most ordered products, with titles and images, and those
1802
+ * viewed but rarely bought. Exact, from every event kept (13 months, from 9 October 2026). */
1803
+ products: (options?: AnalyticsOptions) => Promise<ProductListsReport>;
1804
+ /** Every product with events or orders in the window, the most viewed first, up to 50,000: views,
1805
+ * viewers, clicks, add-to-carts and orders. Exact, like `products`. */
1806
+ productCounts: (options?: AnalyticsOptions) => Promise<ProductCountsReport>;
1807
+ /** One product's views, viewers, clicks, add-to-carts and orders per hour or day, the queries it was
1808
+ * clicked from, and its clicks in recommendations. Fast, for a product page in an admin: views and
1809
+ * clicks are estimates when `sampled`, and an add-to-cart of several products counts toward the first. */
1810
+ product: (objectID: string, options?: AnalyticsOptions & {
1811
+ interval?: "hour" | "day";
1812
+ }) => Promise<ProductReport>;
1813
+ /** Revenue from search: orders and add-to-carts of products found through search, per query and per
1814
+ * product (0.20.0). */
1815
+ revenue: (options?: Omit<AnalyticsOptions, "source">) => Promise<RevenueReport>;
1816
+ /** Sales by filter value: each facet value's clicks, add-to-carts, orders and revenue (0.26.0). */
1817
+ filterSales: (options?: Omit<AnalyticsOptions, "source">) => Promise<FilterSalesReport>;
1818
+ /** Each banner's shown (shoppers' searches that showed it, cache answers included) and clicks, by its rule,
1819
+ * over the last 7, 30 (by default) or 90 days (0.23.0). */
1820
+ banners: (options?: {
1821
+ range?: "7d" | "30d" | "90d";
1822
+ signal?: AbortSignal;
1823
+ }) => Promise<BannerStatsReport>;
1824
+ };
1825
+ upsert: (records: S_1[], signal?: AbortSignal) => Promise<WriteReceipt>;
1826
+ getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_1>>;
1827
+ upsertOne: (record: S_1, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
1828
+ deleteOne: (objectID: string, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
1829
+ replaceAll: (records: S_1[], signal?: AbortSignal) => Promise<WriteReceipt>;
1830
+ beginReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
1831
+ uploadReplacementBatch: (stageId: string, batchId: string, records: S_1[], signal?: AbortSignal) => Promise<ReplacementStage>;
1832
+ commitReplacement: (stageId: string, expectedBatches: number, expectedRecords: number, signal?: AbortSignal) => Promise<WriteReceipt>;
1833
+ abortReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
1834
+ replaceAllStaged: (records: Iterable<S_1> | AsyncIterable<S_1>, options?: StagedReplaceOptions) => Promise<WriteReceipt>;
1835
+ delete: (objectID: string, signal?: AbortSignal) => Promise<WriteReceipt>;
1836
+ getSettings: (signal?: AbortSignal) => Promise<CurrentSettings>;
1837
+ replaceSettings: (settings: IndexSettings, signal?: AbortSignal) => Promise<SavedSettings>;
1838
+ /** Compares settings with the index's own without saving them: its search tests, `queries`, and its 100
1839
+ * most searched queries of the last 30 days, each searched with both, for up to 20 seconds. Takes the
1840
+ * settings `replaceSettings` does, or only those that change; `{}` runs the tests with the current
1841
+ * settings. A change to what the index stores (new searchable, facet, filter, sort or location fields,
1842
+ * or normalization) throws a 409: save it first. Not counted as searches. */
1843
+ compareSettings: (settings: Partial<IndexSettings>, options?: CompareOptions) => Promise<SettingsComparison>;
1844
+ /** The index's search tests. */
1845
+ getSearchTests: (signal?: AbortSignal) => Promise<SearchTest[]>;
1846
+ /** Replaces the index's search tests, up to 200; `[]` deletes them. */
1847
+ setSearchTests: (tests: SearchTest[], signal?: AbortSignal) => Promise<SearchTest[]>;
1848
+ /** Waits until no settings rebuild is running; throws if it failed. */
1849
+ waitForSettings: (options?: {
1850
+ timeoutMs?: number;
1851
+ intervalMs?: number;
1852
+ signal?: AbortSignal;
1853
+ }) => Promise<CurrentSettings>;
1854
+ subindex: <S_2 extends {
1855
+ objectID: string;
1856
+ } = JsonRecord>(subindex: string) => {
1857
+ /** Searches the index; the API key needs the `search` scope. Pass `{ visitor }` when searching for
1858
+ * someone, such as a shopper loading a server-rendered page (see Visitor). */
1859
+ search: <R = S_2>(query?: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<SearchResponse<R>>;
1860
+ /** Did you mean: for a search that found nothing, a query that finds something, or null. Takes the
1861
+ * same request (its q, filters, and fields matter). Needs the `didYouMean` setting; not counted as
1862
+ * a search. */
1863
+ suggest: (query: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<DidYouMean | null>;
1864
+ /** Query suggestions: whole searches to offer as a shopper types `q`, the best first; with `q` empty, the
1865
+ * index's popular searches. The API key needs the `search` scope; not counted as searches. `limit`: 1 to
1866
+ * 10, 5 by default. */
1867
+ querySuggestions: (query: {
1868
+ q: string;
1869
+ limit?: number;
1870
+ }, options?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
1871
+ /** The index's popular searches, for an empty search box, with the owner's pinned searches first;
1872
+ * empty until the index has enough searches. The list changes daily. */
1873
+ popularSearches: (options?: {
1874
+ limit?: number;
1875
+ }, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
1876
+ /** A product's recommendations (the recommendations add-on): products that go with it, and similar products.
1877
+ * The API key needs the `search` scope; not counted as a search. */
1878
+ recommendations: <R = S_2>(objectID: string, options?: RecommendationsRequest, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<RecommendationsResponse<R>>;
1879
+ /** The index's lists: rows of products, such as Popular, and facet fields' values for menus, built ahead
1880
+ * and served from a cache, so reading them isn't counted as searches. Reading needs the `search` scope;
1881
+ * setting them up needs `write`. */
1882
+ /** Merchandising (0.23.0): category pages and searches arranged as the dashboard's Merchandising page does:
1883
+ * the products placed first, hidden products, a banner, and when. Saved as the page's rule within seconds,
1884
+ * keeping anything else the rule does. Reading needs the `search` or `write` scope; changing, `write`. */
1885
+ merchandising: {
1886
+ /** Every arranged category page and search. */
1887
+ list: (signal?: AbortSignal) => Promise<Arrangement[]>;
1888
+ /** One page's or search's arrangement; status "none" when nothing is arranged. */
1889
+ get: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
1890
+ /** Changes one: `order` up to 20 objectIDs placed first, `hidden` up to 100, `banner` ({ image, link?, title?,
1891
+ * position? } or null), `active` ({ from?, until? } or null), `enabled`. Fields left out stay as they are. */
1892
+ set: (target: MerchandisingTarget, change: ArrangementChange, signal?: AbortSignal) => Promise<Arrangement>;
1893
+ /** Stops arranging one: its order, hidden products and banner go; the rule's other actions stay. */
1894
+ remove: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
1895
+ };
1896
+ /** Images for the index's banners, hosted by Findlane at https://images.findlane.dev (0.23.0): JPEG, PNG,
1897
+ * WebP or AVIF, up to 2 MB each, 50 images and 100 MB an index. An image no rule shows is deleted a week
1898
+ * later. Uploading and deleting need the `write` scope. */
1899
+ images: {
1900
+ list: (signal?: AbortSignal) => Promise<ImageLibrary>;
1901
+ /** Uploads an image's bytes; the same image again gives the same URL. */
1902
+ upload: (image: Blob | ArrayBuffer | Uint8Array, options?: {
1903
+ contentType?: string;
1904
+ signal?: AbortSignal;
1905
+ }) => Promise<UploadedImage & {
1906
+ error?: string;
1907
+ }>;
1908
+ /** Uploads the image at an https address, which Findlane fetches. */
1909
+ uploadFromUrl: (url: string, signal?: AbortSignal) => Promise<UploadedImage>;
1910
+ /** Deletes an image by its key; refused (409) while a rule's banner shows it. */
1911
+ delete: (key: string, signal?: AbortSignal) => Promise<{
1912
+ deleted: true;
1913
+ }>;
1914
+ };
1915
+ /** The index's product feed (0.24.0): a store's Google or Meta product feed, or a JSON file of records, read on
1916
+ * a schedule (hourly, every 6 hours, or daily), replacing the index's records with only what changed. Reading
1917
+ * needs the `search` or `write` scope; the rest, `write`. */
1918
+ feed: {
1919
+ /** The feed and its last run, or null. */
1920
+ get: (signal?: AbortSignal) => Promise<ProductFeed | null>;
1921
+ /** Connects a feed or changes its setup; a new address, sign-in or variants setting reads it now. */
1922
+ set: (setup: FeedSetup, signal?: AbortSignal) => Promise<ProductFeed>;
1923
+ /** Disconnects it; the index keeps its records. */
1924
+ remove: (signal?: AbortSignal) => Promise<void>;
1925
+ /** Reads a feed's first 2,000 items without saving anything; without a url, the connected feed's. */
1926
+ check: (setup?: Pick<FeedSetup, "url" | "username" | "password" | "variants">, signal?: AbortSignal) => Promise<FeedCheck>;
1927
+ /** Reads it now, in full, in the background; `runs` shows how it went. */
1928
+ run: (signal?: AbortSignal) => Promise<FeedRun>;
1929
+ /** The last 20 runs, newest first. */
1930
+ runs: (signal?: AbortSignal) => Promise<FeedRun[]>;
1931
+ /** Imports a held run's copy of the feed as it is, without the checks that held it. */
1932
+ importHeld: (runId: string, signal?: AbortSignal) => Promise<FeedRun>;
1933
+ };
1934
+ lists: {
1935
+ /** One list by its ID; throws a FindlaneError with status 404 when there's none. `limit` shows fewer. */
1936
+ get: <R = S_2>(id: string, options?: {
1937
+ limit?: number;
1938
+ signal?: AbortSignal;
1939
+ }) => Promise<List<R>>;
1940
+ /** Several lists (up to 10) in the order asked, leaving out IDs without a list; without IDs, all of them. */
1941
+ getMany: <R = S_2>(ids?: string[], options?: {
1942
+ limit?: number;
1943
+ signal?: AbortSignal;
1944
+ }) => Promise<List<R>[]>;
1945
+ /** How the index's lists are set up, and their last build. */
1946
+ settings: (signal?: AbortSignal) => Promise<ListSettings>;
1947
+ /** Creates or changes a list and builds it; one whose filters, sort or field don't work on the index is
1948
+ * refused with why (400), and a new list past the plan's lists per index too (402). */
1949
+ save: (id: string, list: ListDefinition, signal?: AbortSignal) => Promise<ListSettings>;
1950
+ delete: (id: string, signal?: AbortSignal) => Promise<ListSettings>;
1951
+ /** Puts the lists in this order: every list's ID once. */
1952
+ order: (ids: string[], signal?: AbortSignal) => Promise<ListSettings>;
1953
+ /** Builds the lists again now, rather than within the minute they take to follow the index; once a minute. */
1954
+ refresh: (signal?: AbortSignal) => Promise<ListSettings>;
1955
+ /** What a list would hold, built without saving it. */
1956
+ preview: <R = S_2>(list: ListDefinition, signal?: AbortSignal) => Promise<{
1957
+ list: List<R>;
1958
+ tookMs: number;
1959
+ }>;
1960
+ };
1961
+ /** Events for the index's Events page and Bought together; the API key needs the `events` or `write`
1962
+ * scope. Orders count once each, however often they're sent. */
1963
+ events: {
1964
+ /** Sends events, 200 a request. One bad event doesn't refuse the rest: they're in `rejected`. Pass
1965
+ * `{ visitorId, visitId }` to link a shopper's events (see EventOptions). */
1966
+ send: (events: ServerEvent[], options?: AbortSignal | EventOptions) => Promise<EventsResult>;
1967
+ /** Sends past orders, up to 400 days old, from a list or an async iterable (such as a database
1968
+ * cursor), 200 a request. */
1969
+ importOrders: (orders: Iterable<Order> | AsyncIterable<Order>, signal?: AbortSignal) => Promise<EventsResult>;
1970
+ /** Takes a cancelled or refunded order out of Bought together. */
1971
+ cancelOrder: (orderID: string, signal?: AbortSignal) => Promise<EventsResult>;
1972
+ /** Deletes the events sent with these visitor or visit IDs, for shoppers who asked: Findlane does it
1973
+ * within a week. 1,000 IDs a request. */
1974
+ forget: (ids: string[], signal?: AbortSignal) => Promise<{
1975
+ forgotten: number;
1976
+ }>;
1977
+ /** A route on your own domain for the browser SDK's events (its `eventsUrl` option): ad blockers
1978
+ * block beacons to other sites, not to the page's own. Give it the browser's POST request (Next.js
1979
+ * route handlers, Workers, Hono, Bun, Deno); it finds the visitor's address in the headers
1980
+ * Cloudflare, Vercel and most proxies set. Where a visitor reaches your server directly, they can
1981
+ * set those too, so pass `{ ip }`. The API key needs the `events` or `write` scope. */
1982
+ proxy: (request: Request, visitor?: Partial<RelayedVisitor>) => Promise<Response>;
1983
+ /** `proxy` for servers without Fetch API requests, such as Express: the request's body as text,
1984
+ * and its visitor. Answers with the API's response. */
1985
+ relay: (body: string, visitor: RelayedVisitor, signal?: AbortSignal) => Promise<Response>;
1986
+ };
1987
+ /** The index's search analytics. The API key needs the `analytics` scope, and works only from a server:
1988
+ * requests from web pages are refused. */
1989
+ analytics: {
1990
+ /** Searches, searches without results and response times, beside the same span before, and a series per
1991
+ * hour (up to 7 days, by default) or day. */
1992
+ searches: (options?: AnalyticsOptions & {
1993
+ interval?: "hour" | "day";
1994
+ }) => Promise<SearchesReport>;
1995
+ /** Queries, the most searched first: `top` (by default) with their clicks, `noResults`, or `noClicks`, which
1996
+ * found something nobody clicked. `limit` is 1 to 1,000, 100 by default. */
1997
+ queries: <L extends keyof QueryLists = "top">(options?: AnalyticsOptions & {
1998
+ list?: L | undefined;
1999
+ limit?: number;
2000
+ }) => Promise<QueriesReport<L>>;
2001
+ /** The filter fields and sorts searches used. */
2002
+ filters: (options?: AnalyticsOptions) => Promise<FiltersReport>;
2003
+ /** Events of each type over time and by source, orders stored, and refused and bot events. */
2004
+ events: (options?: AnalyticsOptions & {
2005
+ interval?: "hour" | "day";
2006
+ }) => Promise<EventsReport>;
2007
+ /** The most viewed, most added to carts and most ordered products, with titles and images, and those
2008
+ * viewed but rarely bought. Exact, from every event kept (13 months, from 9 October 2026). */
2009
+ products: (options?: AnalyticsOptions) => Promise<ProductListsReport>;
2010
+ /** Every product with events or orders in the window, the most viewed first, up to 50,000: views,
2011
+ * viewers, clicks, add-to-carts and orders. Exact, like `products`. */
2012
+ productCounts: (options?: AnalyticsOptions) => Promise<ProductCountsReport>;
2013
+ /** One product's views, viewers, clicks, add-to-carts and orders per hour or day, the queries it was
2014
+ * clicked from, and its clicks in recommendations. Fast, for a product page in an admin: views and
2015
+ * clicks are estimates when `sampled`, and an add-to-cart of several products counts toward the first. */
2016
+ product: (objectID: string, options?: AnalyticsOptions & {
2017
+ interval?: "hour" | "day";
2018
+ }) => Promise<ProductReport>;
2019
+ /** Revenue from search: orders and add-to-carts of products found through search, per query and per
2020
+ * product (0.20.0). */
2021
+ revenue: (options?: Omit<AnalyticsOptions, "source">) => Promise<RevenueReport>;
2022
+ /** Sales by filter value: each facet value's clicks, add-to-carts, orders and revenue (0.26.0). */
2023
+ filterSales: (options?: Omit<AnalyticsOptions, "source">) => Promise<FilterSalesReport>;
2024
+ /** Each banner's shown (shoppers' searches that showed it, cache answers included) and clicks, by its rule,
2025
+ * over the last 7, 30 (by default) or 90 days (0.23.0). */
2026
+ banners: (options?: {
2027
+ range?: "7d" | "30d" | "90d";
2028
+ signal?: AbortSignal;
2029
+ }) => Promise<BannerStatsReport>;
2030
+ };
2031
+ upsert: (records: S_2[], signal?: AbortSignal) => Promise<WriteReceipt>;
2032
+ getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_2>>;
2033
+ upsertOne: (record: S_2, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
2034
+ deleteOne: (objectID: string, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
2035
+ replaceAll: (records: S_2[], signal?: AbortSignal) => Promise<WriteReceipt>;
2036
+ beginReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
2037
+ uploadReplacementBatch: (stageId: string, batchId: string, records: S_2[], signal?: AbortSignal) => Promise<ReplacementStage>;
2038
+ commitReplacement: (stageId: string, expectedBatches: number, expectedRecords: number, signal?: AbortSignal) => Promise<WriteReceipt>;
2039
+ abortReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
2040
+ replaceAllStaged: (records: Iterable<S_2> | AsyncIterable<S_2>, options?: StagedReplaceOptions) => Promise<WriteReceipt>;
2041
+ delete: (objectID: string, signal?: AbortSignal) => Promise<WriteReceipt>;
2042
+ getSettings: (signal?: AbortSignal) => Promise<CurrentSettings>;
2043
+ replaceSettings: (settings: IndexSettings, signal?: AbortSignal) => Promise<SavedSettings>;
2044
+ /** Compares settings with the index's own without saving them: its search tests, `queries`, and its 100
2045
+ * most searched queries of the last 30 days, each searched with both, for up to 20 seconds. Takes the
2046
+ * settings `replaceSettings` does, or only those that change; `{}` runs the tests with the current
2047
+ * settings. A change to what the index stores (new searchable, facet, filter, sort or location fields,
2048
+ * or normalization) throws a 409: save it first. Not counted as searches. */
2049
+ compareSettings: (settings: Partial<IndexSettings>, options?: CompareOptions) => Promise<SettingsComparison>;
2050
+ /** The index's search tests. */
2051
+ getSearchTests: (signal?: AbortSignal) => Promise<SearchTest[]>;
2052
+ /** Replaces the index's search tests, up to 200; `[]` deletes them. */
2053
+ setSearchTests: (tests: SearchTest[], signal?: AbortSignal) => Promise<SearchTest[]>;
2054
+ /** Waits until no settings rebuild is running; throws if it failed. */
2055
+ waitForSettings: (options?: {
2056
+ timeoutMs?: number;
2057
+ intervalMs?: number;
2058
+ signal?: AbortSignal;
2059
+ }) => Promise<CurrentSettings>;
2060
+ subindex: <S_3 extends {
2061
+ objectID: string;
2062
+ } = JsonRecord>(subindex: string) => {
2063
+ /** Searches the index; the API key needs the `search` scope. Pass `{ visitor }` when searching for
2064
+ * someone, such as a shopper loading a server-rendered page (see Visitor). */
2065
+ search: <R = S_3>(query?: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<SearchResponse<R>>;
2066
+ /** Did you mean: for a search that found nothing, a query that finds something, or null. Takes the
2067
+ * same request (its q, filters, and fields matter). Needs the `didYouMean` setting; not counted as
2068
+ * a search. */
2069
+ suggest: (query: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<DidYouMean | null>;
2070
+ /** Query suggestions: whole searches to offer as a shopper types `q`, the best first; with `q` empty, the
2071
+ * index's popular searches. The API key needs the `search` scope; not counted as searches. `limit`: 1 to
2072
+ * 10, 5 by default. */
2073
+ querySuggestions: (query: {
2074
+ q: string;
2075
+ limit?: number;
2076
+ }, options?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
2077
+ /** The index's popular searches, for an empty search box, with the owner's pinned searches first;
2078
+ * empty until the index has enough searches. The list changes daily. */
2079
+ popularSearches: (options?: {
2080
+ limit?: number;
2081
+ }, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
2082
+ /** A product's recommendations (the recommendations add-on): products that go with it, and similar products.
2083
+ * The API key needs the `search` scope; not counted as a search. */
2084
+ recommendations: <R = S_3>(objectID: string, options?: RecommendationsRequest, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<RecommendationsResponse<R>>;
2085
+ /** The index's lists: rows of products, such as Popular, and facet fields' values for menus, built ahead
2086
+ * and served from a cache, so reading them isn't counted as searches. Reading needs the `search` scope;
2087
+ * setting them up needs `write`. */
2088
+ /** Merchandising (0.23.0): category pages and searches arranged as the dashboard's Merchandising page does:
2089
+ * the products placed first, hidden products, a banner, and when. Saved as the page's rule within seconds,
2090
+ * keeping anything else the rule does. Reading needs the `search` or `write` scope; changing, `write`. */
2091
+ merchandising: {
2092
+ /** Every arranged category page and search. */
2093
+ list: (signal?: AbortSignal) => Promise<Arrangement[]>;
2094
+ /** One page's or search's arrangement; status "none" when nothing is arranged. */
2095
+ get: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
2096
+ /** Changes one: `order` up to 20 objectIDs placed first, `hidden` up to 100, `banner` ({ image, link?, title?,
2097
+ * position? } or null), `active` ({ from?, until? } or null), `enabled`. Fields left out stay as they are. */
2098
+ set: (target: MerchandisingTarget, change: ArrangementChange, signal?: AbortSignal) => Promise<Arrangement>;
2099
+ /** Stops arranging one: its order, hidden products and banner go; the rule's other actions stay. */
2100
+ remove: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
2101
+ };
2102
+ /** Images for the index's banners, hosted by Findlane at https://images.findlane.dev (0.23.0): JPEG, PNG,
2103
+ * WebP or AVIF, up to 2 MB each, 50 images and 100 MB an index. An image no rule shows is deleted a week
2104
+ * later. Uploading and deleting need the `write` scope. */
2105
+ images: {
2106
+ list: (signal?: AbortSignal) => Promise<ImageLibrary>;
2107
+ /** Uploads an image's bytes; the same image again gives the same URL. */
2108
+ upload: (image: Blob | ArrayBuffer | Uint8Array, options?: {
2109
+ contentType?: string;
2110
+ signal?: AbortSignal;
2111
+ }) => Promise<UploadedImage & {
2112
+ error?: string;
2113
+ }>;
2114
+ /** Uploads the image at an https address, which Findlane fetches. */
2115
+ uploadFromUrl: (url: string, signal?: AbortSignal) => Promise<UploadedImage>;
2116
+ /** Deletes an image by its key; refused (409) while a rule's banner shows it. */
2117
+ delete: (key: string, signal?: AbortSignal) => Promise<{
2118
+ deleted: true;
2119
+ }>;
2120
+ };
2121
+ /** The index's product feed (0.24.0): a store's Google or Meta product feed, or a JSON file of records, read on
2122
+ * a schedule (hourly, every 6 hours, or daily), replacing the index's records with only what changed. Reading
2123
+ * needs the `search` or `write` scope; the rest, `write`. */
2124
+ feed: {
2125
+ /** The feed and its last run, or null. */
2126
+ get: (signal?: AbortSignal) => Promise<ProductFeed | null>;
2127
+ /** Connects a feed or changes its setup; a new address, sign-in or variants setting reads it now. */
2128
+ set: (setup: FeedSetup, signal?: AbortSignal) => Promise<ProductFeed>;
2129
+ /** Disconnects it; the index keeps its records. */
2130
+ remove: (signal?: AbortSignal) => Promise<void>;
2131
+ /** Reads a feed's first 2,000 items without saving anything; without a url, the connected feed's. */
2132
+ check: (setup?: Pick<FeedSetup, "url" | "username" | "password" | "variants">, signal?: AbortSignal) => Promise<FeedCheck>;
2133
+ /** Reads it now, in full, in the background; `runs` shows how it went. */
2134
+ run: (signal?: AbortSignal) => Promise<FeedRun>;
2135
+ /** The last 20 runs, newest first. */
2136
+ runs: (signal?: AbortSignal) => Promise<FeedRun[]>;
2137
+ /** Imports a held run's copy of the feed as it is, without the checks that held it. */
2138
+ importHeld: (runId: string, signal?: AbortSignal) => Promise<FeedRun>;
2139
+ };
2140
+ lists: {
2141
+ /** One list by its ID; throws a FindlaneError with status 404 when there's none. `limit` shows fewer. */
2142
+ get: <R = S_3>(id: string, options?: {
2143
+ limit?: number;
2144
+ signal?: AbortSignal;
2145
+ }) => Promise<List<R>>;
2146
+ /** Several lists (up to 10) in the order asked, leaving out IDs without a list; without IDs, all of them. */
2147
+ getMany: <R = S_3>(ids?: string[], options?: {
2148
+ limit?: number;
2149
+ signal?: AbortSignal;
2150
+ }) => Promise<List<R>[]>;
2151
+ /** How the index's lists are set up, and their last build. */
2152
+ settings: (signal?: AbortSignal) => Promise<ListSettings>;
2153
+ /** Creates or changes a list and builds it; one whose filters, sort or field don't work on the index is
2154
+ * refused with why (400), and a new list past the plan's lists per index too (402). */
2155
+ save: (id: string, list: ListDefinition, signal?: AbortSignal) => Promise<ListSettings>;
2156
+ delete: (id: string, signal?: AbortSignal) => Promise<ListSettings>;
2157
+ /** Puts the lists in this order: every list's ID once. */
2158
+ order: (ids: string[], signal?: AbortSignal) => Promise<ListSettings>;
2159
+ /** Builds the lists again now, rather than within the minute they take to follow the index; once a minute. */
2160
+ refresh: (signal?: AbortSignal) => Promise<ListSettings>;
2161
+ /** What a list would hold, built without saving it. */
2162
+ preview: <R = S_3>(list: ListDefinition, signal?: AbortSignal) => Promise<{
2163
+ list: List<R>;
2164
+ tookMs: number;
2165
+ }>;
2166
+ };
2167
+ /** Events for the index's Events page and Bought together; the API key needs the `events` or `write`
2168
+ * scope. Orders count once each, however often they're sent. */
2169
+ events: {
2170
+ /** Sends events, 200 a request. One bad event doesn't refuse the rest: they're in `rejected`. Pass
2171
+ * `{ visitorId, visitId }` to link a shopper's events (see EventOptions). */
2172
+ send: (events: ServerEvent[], options?: AbortSignal | EventOptions) => Promise<EventsResult>;
2173
+ /** Sends past orders, up to 400 days old, from a list or an async iterable (such as a database
2174
+ * cursor), 200 a request. */
2175
+ importOrders: (orders: Iterable<Order> | AsyncIterable<Order>, signal?: AbortSignal) => Promise<EventsResult>;
2176
+ /** Takes a cancelled or refunded order out of Bought together. */
2177
+ cancelOrder: (orderID: string, signal?: AbortSignal) => Promise<EventsResult>;
2178
+ /** Deletes the events sent with these visitor or visit IDs, for shoppers who asked: Findlane does it
2179
+ * within a week. 1,000 IDs a request. */
2180
+ forget: (ids: string[], signal?: AbortSignal) => Promise<{
2181
+ forgotten: number;
2182
+ }>;
2183
+ /** A route on your own domain for the browser SDK's events (its `eventsUrl` option): ad blockers
2184
+ * block beacons to other sites, not to the page's own. Give it the browser's POST request (Next.js
2185
+ * route handlers, Workers, Hono, Bun, Deno); it finds the visitor's address in the headers
2186
+ * Cloudflare, Vercel and most proxies set. Where a visitor reaches your server directly, they can
2187
+ * set those too, so pass `{ ip }`. The API key needs the `events` or `write` scope. */
2188
+ proxy: (request: Request, visitor?: Partial<RelayedVisitor>) => Promise<Response>;
2189
+ /** `proxy` for servers without Fetch API requests, such as Express: the request's body as text,
2190
+ * and its visitor. Answers with the API's response. */
2191
+ relay: (body: string, visitor: RelayedVisitor, signal?: AbortSignal) => Promise<Response>;
2192
+ };
2193
+ /** The index's search analytics. The API key needs the `analytics` scope, and works only from a server:
2194
+ * requests from web pages are refused. */
2195
+ analytics: {
2196
+ /** Searches, searches without results and response times, beside the same span before, and a series per
2197
+ * hour (up to 7 days, by default) or day. */
2198
+ searches: (options?: AnalyticsOptions & {
2199
+ interval?: "hour" | "day";
2200
+ }) => Promise<SearchesReport>;
2201
+ /** Queries, the most searched first: `top` (by default) with their clicks, `noResults`, or `noClicks`, which
2202
+ * found something nobody clicked. `limit` is 1 to 1,000, 100 by default. */
2203
+ queries: <L extends keyof QueryLists = "top">(options?: AnalyticsOptions & {
2204
+ list?: L | undefined;
2205
+ limit?: number;
2206
+ }) => Promise<QueriesReport<L>>;
2207
+ /** The filter fields and sorts searches used. */
2208
+ filters: (options?: AnalyticsOptions) => Promise<FiltersReport>;
2209
+ /** Events of each type over time and by source, orders stored, and refused and bot events. */
2210
+ events: (options?: AnalyticsOptions & {
2211
+ interval?: "hour" | "day";
2212
+ }) => Promise<EventsReport>;
2213
+ /** The most viewed, most added to carts and most ordered products, with titles and images, and those
2214
+ * viewed but rarely bought. Exact, from every event kept (13 months, from 9 October 2026). */
2215
+ products: (options?: AnalyticsOptions) => Promise<ProductListsReport>;
2216
+ /** Every product with events or orders in the window, the most viewed first, up to 50,000: views,
2217
+ * viewers, clicks, add-to-carts and orders. Exact, like `products`. */
2218
+ productCounts: (options?: AnalyticsOptions) => Promise<ProductCountsReport>;
2219
+ /** One product's views, viewers, clicks, add-to-carts and orders per hour or day, the queries it was
2220
+ * clicked from, and its clicks in recommendations. Fast, for a product page in an admin: views and
2221
+ * clicks are estimates when `sampled`, and an add-to-cart of several products counts toward the first. */
2222
+ product: (objectID: string, options?: AnalyticsOptions & {
2223
+ interval?: "hour" | "day";
2224
+ }) => Promise<ProductReport>;
2225
+ /** Revenue from search: orders and add-to-carts of products found through search, per query and per
2226
+ * product (0.20.0). */
2227
+ revenue: (options?: Omit<AnalyticsOptions, "source">) => Promise<RevenueReport>;
2228
+ /** Sales by filter value: each facet value's clicks, add-to-carts, orders and revenue (0.26.0). */
2229
+ filterSales: (options?: Omit<AnalyticsOptions, "source">) => Promise<FilterSalesReport>;
2230
+ /** Each banner's shown (shoppers' searches that showed it, cache answers included) and clicks, by its rule,
2231
+ * over the last 7, 30 (by default) or 90 days (0.23.0). */
2232
+ banners: (options?: {
2233
+ range?: "7d" | "30d" | "90d";
2234
+ signal?: AbortSignal;
2235
+ }) => Promise<BannerStatsReport>;
2236
+ };
2237
+ upsert: (records: S_3[], signal?: AbortSignal) => Promise<WriteReceipt>;
2238
+ getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_3>>;
2239
+ upsertOne: (record: S_3, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
2240
+ deleteOne: (objectID: string, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
2241
+ replaceAll: (records: S_3[], signal?: AbortSignal) => Promise<WriteReceipt>;
2242
+ beginReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
2243
+ uploadReplacementBatch: (stageId: string, batchId: string, records: S_3[], signal?: AbortSignal) => Promise<ReplacementStage>;
2244
+ commitReplacement: (stageId: string, expectedBatches: number, expectedRecords: number, signal?: AbortSignal) => Promise<WriteReceipt>;
2245
+ abortReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
2246
+ replaceAllStaged: (records: Iterable<S_3> | AsyncIterable<S_3>, options?: StagedReplaceOptions) => Promise<WriteReceipt>;
2247
+ delete: (objectID: string, signal?: AbortSignal) => Promise<WriteReceipt>;
2248
+ getSettings: (signal?: AbortSignal) => Promise<CurrentSettings>;
2249
+ replaceSettings: (settings: IndexSettings, signal?: AbortSignal) => Promise<SavedSettings>;
2250
+ /** Compares settings with the index's own without saving them: its search tests, `queries`, and its 100
2251
+ * most searched queries of the last 30 days, each searched with both, for up to 20 seconds. Takes the
2252
+ * settings `replaceSettings` does, or only those that change; `{}` runs the tests with the current
2253
+ * settings. A change to what the index stores (new searchable, facet, filter, sort or location fields,
2254
+ * or normalization) throws a 409: save it first. Not counted as searches. */
2255
+ compareSettings: (settings: Partial<IndexSettings>, options?: CompareOptions) => Promise<SettingsComparison>;
2256
+ /** The index's search tests. */
2257
+ getSearchTests: (signal?: AbortSignal) => Promise<SearchTest[]>;
2258
+ /** Replaces the index's search tests, up to 200; `[]` deletes them. */
2259
+ setSearchTests: (tests: SearchTest[], signal?: AbortSignal) => Promise<SearchTest[]>;
2260
+ /** Waits until no settings rebuild is running; throws if it failed. */
2261
+ waitForSettings: (options?: {
2262
+ timeoutMs?: number;
2263
+ intervalMs?: number;
2264
+ signal?: AbortSignal;
2265
+ }) => Promise<CurrentSettings>;
2266
+ subindex: <S_4 extends {
2267
+ objectID: string;
2268
+ } = JsonRecord>(subindex: string) => {
2269
+ /** Searches the index; the API key needs the `search` scope. Pass `{ visitor }` when searching for
2270
+ * someone, such as a shopper loading a server-rendered page (see Visitor). */
2271
+ search: <R = S_4>(query?: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<SearchResponse<R>>;
2272
+ /** Did you mean: for a search that found nothing, a query that finds something, or null. Takes the
2273
+ * same request (its q, filters, and fields matter). Needs the `didYouMean` setting; not counted as
2274
+ * a search. */
2275
+ suggest: (query: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<DidYouMean | null>;
2276
+ /** Query suggestions: whole searches to offer as a shopper types `q`, the best first; with `q` empty, the
2277
+ * index's popular searches. The API key needs the `search` scope; not counted as searches. `limit`: 1 to
2278
+ * 10, 5 by default. */
2279
+ querySuggestions: (query: {
2280
+ q: string;
2281
+ limit?: number;
2282
+ }, options?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
2283
+ /** The index's popular searches, for an empty search box, with the owner's pinned searches first;
2284
+ * empty until the index has enough searches. The list changes daily. */
2285
+ popularSearches: (options?: {
2286
+ limit?: number;
2287
+ }, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
2288
+ /** A product's recommendations (the recommendations add-on): products that go with it, and similar products.
2289
+ * The API key needs the `search` scope; not counted as a search. */
2290
+ recommendations: <R = S_4>(objectID: string, options?: RecommendationsRequest, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<RecommendationsResponse<R>>;
2291
+ /** The index's lists: rows of products, such as Popular, and facet fields' values for menus, built ahead
2292
+ * and served from a cache, so reading them isn't counted as searches. Reading needs the `search` scope;
2293
+ * setting them up needs `write`. */
2294
+ /** Merchandising (0.23.0): category pages and searches arranged as the dashboard's Merchandising page does:
2295
+ * the products placed first, hidden products, a banner, and when. Saved as the page's rule within seconds,
2296
+ * keeping anything else the rule does. Reading needs the `search` or `write` scope; changing, `write`. */
2297
+ merchandising: {
2298
+ /** Every arranged category page and search. */
2299
+ list: (signal?: AbortSignal) => Promise<Arrangement[]>;
2300
+ /** One page's or search's arrangement; status "none" when nothing is arranged. */
2301
+ get: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
2302
+ /** Changes one: `order` up to 20 objectIDs placed first, `hidden` up to 100, `banner` ({ image, link?, title?,
2303
+ * position? } or null), `active` ({ from?, until? } or null), `enabled`. Fields left out stay as they are. */
2304
+ set: (target: MerchandisingTarget, change: ArrangementChange, signal?: AbortSignal) => Promise<Arrangement>;
2305
+ /** Stops arranging one: its order, hidden products and banner go; the rule's other actions stay. */
2306
+ remove: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
2307
+ };
2308
+ /** Images for the index's banners, hosted by Findlane at https://images.findlane.dev (0.23.0): JPEG, PNG,
2309
+ * WebP or AVIF, up to 2 MB each, 50 images and 100 MB an index. An image no rule shows is deleted a week
2310
+ * later. Uploading and deleting need the `write` scope. */
2311
+ images: {
2312
+ list: (signal?: AbortSignal) => Promise<ImageLibrary>;
2313
+ /** Uploads an image's bytes; the same image again gives the same URL. */
2314
+ upload: (image: Blob | ArrayBuffer | Uint8Array, options?: {
2315
+ contentType?: string;
2316
+ signal?: AbortSignal;
2317
+ }) => Promise<UploadedImage & {
2318
+ error?: string;
2319
+ }>;
2320
+ /** Uploads the image at an https address, which Findlane fetches. */
2321
+ uploadFromUrl: (url: string, signal?: AbortSignal) => Promise<UploadedImage>;
2322
+ /** Deletes an image by its key; refused (409) while a rule's banner shows it. */
2323
+ delete: (key: string, signal?: AbortSignal) => Promise<{
2324
+ deleted: true;
2325
+ }>;
2326
+ };
2327
+ /** The index's product feed (0.24.0): a store's Google or Meta product feed, or a JSON file of records, read on
2328
+ * a schedule (hourly, every 6 hours, or daily), replacing the index's records with only what changed. Reading
2329
+ * needs the `search` or `write` scope; the rest, `write`. */
2330
+ feed: {
2331
+ /** The feed and its last run, or null. */
2332
+ get: (signal?: AbortSignal) => Promise<ProductFeed | null>;
2333
+ /** Connects a feed or changes its setup; a new address, sign-in or variants setting reads it now. */
2334
+ set: (setup: FeedSetup, signal?: AbortSignal) => Promise<ProductFeed>;
2335
+ /** Disconnects it; the index keeps its records. */
2336
+ remove: (signal?: AbortSignal) => Promise<void>;
2337
+ /** Reads a feed's first 2,000 items without saving anything; without a url, the connected feed's. */
2338
+ check: (setup?: Pick<FeedSetup, "url" | "username" | "password" | "variants">, signal?: AbortSignal) => Promise<FeedCheck>;
2339
+ /** Reads it now, in full, in the background; `runs` shows how it went. */
2340
+ run: (signal?: AbortSignal) => Promise<FeedRun>;
2341
+ /** The last 20 runs, newest first. */
2342
+ runs: (signal?: AbortSignal) => Promise<FeedRun[]>;
2343
+ /** Imports a held run's copy of the feed as it is, without the checks that held it. */
2344
+ importHeld: (runId: string, signal?: AbortSignal) => Promise<FeedRun>;
2345
+ };
2346
+ lists: {
2347
+ /** One list by its ID; throws a FindlaneError with status 404 when there's none. `limit` shows fewer. */
2348
+ get: <R = S_4>(id: string, options?: {
2349
+ limit?: number;
2350
+ signal?: AbortSignal;
2351
+ }) => Promise<List<R>>;
2352
+ /** Several lists (up to 10) in the order asked, leaving out IDs without a list; without IDs, all of them. */
2353
+ getMany: <R = S_4>(ids?: string[], options?: {
2354
+ limit?: number;
2355
+ signal?: AbortSignal;
2356
+ }) => Promise<List<R>[]>;
2357
+ /** How the index's lists are set up, and their last build. */
2358
+ settings: (signal?: AbortSignal) => Promise<ListSettings>;
2359
+ /** Creates or changes a list and builds it; one whose filters, sort or field don't work on the index is
2360
+ * refused with why (400), and a new list past the plan's lists per index too (402). */
2361
+ save: (id: string, list: ListDefinition, signal?: AbortSignal) => Promise<ListSettings>;
2362
+ delete: (id: string, signal?: AbortSignal) => Promise<ListSettings>;
2363
+ /** Puts the lists in this order: every list's ID once. */
2364
+ order: (ids: string[], signal?: AbortSignal) => Promise<ListSettings>;
2365
+ /** Builds the lists again now, rather than within the minute they take to follow the index; once a minute. */
2366
+ refresh: (signal?: AbortSignal) => Promise<ListSettings>;
2367
+ /** What a list would hold, built without saving it. */
2368
+ preview: <R = S_4>(list: ListDefinition, signal?: AbortSignal) => Promise<{
2369
+ list: List<R>;
2370
+ tookMs: number;
2371
+ }>;
2372
+ };
2373
+ /** Events for the index's Events page and Bought together; the API key needs the `events` or `write`
2374
+ * scope. Orders count once each, however often they're sent. */
2375
+ events: {
2376
+ /** Sends events, 200 a request. One bad event doesn't refuse the rest: they're in `rejected`. Pass
2377
+ * `{ visitorId, visitId }` to link a shopper's events (see EventOptions). */
2378
+ send: (events: ServerEvent[], options?: AbortSignal | EventOptions) => Promise<EventsResult>;
2379
+ /** Sends past orders, up to 400 days old, from a list or an async iterable (such as a database
2380
+ * cursor), 200 a request. */
2381
+ importOrders: (orders: Iterable<Order> | AsyncIterable<Order>, signal?: AbortSignal) => Promise<EventsResult>;
2382
+ /** Takes a cancelled or refunded order out of Bought together. */
2383
+ cancelOrder: (orderID: string, signal?: AbortSignal) => Promise<EventsResult>;
2384
+ /** Deletes the events sent with these visitor or visit IDs, for shoppers who asked: Findlane does it
2385
+ * within a week. 1,000 IDs a request. */
2386
+ forget: (ids: string[], signal?: AbortSignal) => Promise<{
2387
+ forgotten: number;
2388
+ }>;
2389
+ /** A route on your own domain for the browser SDK's events (its `eventsUrl` option): ad blockers
2390
+ * block beacons to other sites, not to the page's own. Give it the browser's POST request (Next.js
2391
+ * route handlers, Workers, Hono, Bun, Deno); it finds the visitor's address in the headers
2392
+ * Cloudflare, Vercel and most proxies set. Where a visitor reaches your server directly, they can
2393
+ * set those too, so pass `{ ip }`. The API key needs the `events` or `write` scope. */
2394
+ proxy: (request: Request, visitor?: Partial<RelayedVisitor>) => Promise<Response>;
2395
+ /** `proxy` for servers without Fetch API requests, such as Express: the request's body as text,
2396
+ * and its visitor. Answers with the API's response. */
2397
+ relay: (body: string, visitor: RelayedVisitor, signal?: AbortSignal) => Promise<Response>;
2398
+ };
2399
+ /** The index's search analytics. The API key needs the `analytics` scope, and works only from a server:
2400
+ * requests from web pages are refused. */
2401
+ analytics: {
2402
+ /** Searches, searches without results and response times, beside the same span before, and a series per
2403
+ * hour (up to 7 days, by default) or day. */
2404
+ searches: (options?: AnalyticsOptions & {
2405
+ interval?: "hour" | "day";
2406
+ }) => Promise<SearchesReport>;
2407
+ /** Queries, the most searched first: `top` (by default) with their clicks, `noResults`, or `noClicks`, which
2408
+ * found something nobody clicked. `limit` is 1 to 1,000, 100 by default. */
2409
+ queries: <L extends keyof QueryLists = "top">(options?: AnalyticsOptions & {
2410
+ list?: L | undefined;
2411
+ limit?: number;
2412
+ }) => Promise<QueriesReport<L>>;
2413
+ /** The filter fields and sorts searches used. */
2414
+ filters: (options?: AnalyticsOptions) => Promise<FiltersReport>;
2415
+ /** Events of each type over time and by source, orders stored, and refused and bot events. */
2416
+ events: (options?: AnalyticsOptions & {
2417
+ interval?: "hour" | "day";
2418
+ }) => Promise<EventsReport>;
2419
+ /** The most viewed, most added to carts and most ordered products, with titles and images, and those
2420
+ * viewed but rarely bought. Exact, from every event kept (13 months, from 9 October 2026). */
2421
+ products: (options?: AnalyticsOptions) => Promise<ProductListsReport>;
2422
+ /** Every product with events or orders in the window, the most viewed first, up to 50,000: views,
2423
+ * viewers, clicks, add-to-carts and orders. Exact, like `products`. */
2424
+ productCounts: (options?: AnalyticsOptions) => Promise<ProductCountsReport>;
2425
+ /** One product's views, viewers, clicks, add-to-carts and orders per hour or day, the queries it was
2426
+ * clicked from, and its clicks in recommendations. Fast, for a product page in an admin: views and
2427
+ * clicks are estimates when `sampled`, and an add-to-cart of several products counts toward the first. */
2428
+ product: (objectID: string, options?: AnalyticsOptions & {
2429
+ interval?: "hour" | "day";
2430
+ }) => Promise<ProductReport>;
2431
+ /** Revenue from search: orders and add-to-carts of products found through search, per query and per
2432
+ * product (0.20.0). */
2433
+ revenue: (options?: Omit<AnalyticsOptions, "source">) => Promise<RevenueReport>;
2434
+ /** Sales by filter value: each facet value's clicks, add-to-carts, orders and revenue (0.26.0). */
2435
+ filterSales: (options?: Omit<AnalyticsOptions, "source">) => Promise<FilterSalesReport>;
2436
+ /** Each banner's shown (shoppers' searches that showed it, cache answers included) and clicks, by its rule,
2437
+ * over the last 7, 30 (by default) or 90 days (0.23.0). */
2438
+ banners: (options?: {
2439
+ range?: "7d" | "30d" | "90d";
2440
+ signal?: AbortSignal;
2441
+ }) => Promise<BannerStatsReport>;
2442
+ };
2443
+ upsert: (records: S_4[], signal?: AbortSignal) => Promise<WriteReceipt>;
2444
+ getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_4>>;
2445
+ upsertOne: (record: S_4, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
2446
+ deleteOne: (objectID: string, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
2447
+ replaceAll: (records: S_4[], signal?: AbortSignal) => Promise<WriteReceipt>;
2448
+ beginReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
2449
+ uploadReplacementBatch: (stageId: string, batchId: string, records: S_4[], signal?: AbortSignal) => Promise<ReplacementStage>;
2450
+ commitReplacement: (stageId: string, expectedBatches: number, expectedRecords: number, signal?: AbortSignal) => Promise<WriteReceipt>;
2451
+ abortReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
2452
+ replaceAllStaged: (records: Iterable<S_4> | AsyncIterable<S_4>, options?: StagedReplaceOptions) => Promise<WriteReceipt>;
2453
+ delete: (objectID: string, signal?: AbortSignal) => Promise<WriteReceipt>;
2454
+ getSettings: (signal?: AbortSignal) => Promise<CurrentSettings>;
2455
+ replaceSettings: (settings: IndexSettings, signal?: AbortSignal) => Promise<SavedSettings>;
2456
+ /** Compares settings with the index's own without saving them: its search tests, `queries`, and its 100
2457
+ * most searched queries of the last 30 days, each searched with both, for up to 20 seconds. Takes the
2458
+ * settings `replaceSettings` does, or only those that change; `{}` runs the tests with the current
2459
+ * settings. A change to what the index stores (new searchable, facet, filter, sort or location fields,
2460
+ * or normalization) throws a 409: save it first. Not counted as searches. */
2461
+ compareSettings: (settings: Partial<IndexSettings>, options?: CompareOptions) => Promise<SettingsComparison>;
2462
+ /** The index's search tests. */
2463
+ getSearchTests: (signal?: AbortSignal) => Promise<SearchTest[]>;
2464
+ /** Replaces the index's search tests, up to 200; `[]` deletes them. */
2465
+ setSearchTests: (tests: SearchTest[], signal?: AbortSignal) => Promise<SearchTest[]>;
2466
+ /** Waits until no settings rebuild is running; throws if it failed. */
2467
+ waitForSettings: (options?: {
2468
+ timeoutMs?: number;
2469
+ intervalMs?: number;
2470
+ signal?: AbortSignal;
2471
+ }) => Promise<CurrentSettings>;
2472
+ subindex: <S_5 extends {
2473
+ objectID: string;
2474
+ } = JsonRecord>(subindex: string) => {
2475
+ /** Searches the index; the API key needs the `search` scope. Pass `{ visitor }` when searching for
2476
+ * someone, such as a shopper loading a server-rendered page (see Visitor). */
2477
+ search: <R = S_5>(query?: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<SearchResponse<R>>;
2478
+ /** Did you mean: for a search that found nothing, a query that finds something, or null. Takes the
2479
+ * same request (its q, filters, and fields matter). Needs the `didYouMean` setting; not counted as
2480
+ * a search. */
2481
+ suggest: (query: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<DidYouMean | null>;
2482
+ /** Query suggestions: whole searches to offer as a shopper types `q`, the best first; with `q` empty, the
2483
+ * index's popular searches. The API key needs the `search` scope; not counted as searches. `limit`: 1 to
2484
+ * 10, 5 by default. */
2485
+ querySuggestions: (query: {
2486
+ q: string;
2487
+ limit?: number;
2488
+ }, options?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
2489
+ /** The index's popular searches, for an empty search box, with the owner's pinned searches first;
2490
+ * empty until the index has enough searches. The list changes daily. */
2491
+ popularSearches: (options?: {
2492
+ limit?: number;
2493
+ }, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
2494
+ /** A product's recommendations (the recommendations add-on): products that go with it, and similar products.
2495
+ * The API key needs the `search` scope; not counted as a search. */
2496
+ recommendations: <R = S_5>(objectID: string, options?: RecommendationsRequest, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<RecommendationsResponse<R>>;
2497
+ /** The index's lists: rows of products, such as Popular, and facet fields' values for menus, built ahead
2498
+ * and served from a cache, so reading them isn't counted as searches. Reading needs the `search` scope;
2499
+ * setting them up needs `write`. */
2500
+ /** Merchandising (0.23.0): category pages and searches arranged as the dashboard's Merchandising page does:
2501
+ * the products placed first, hidden products, a banner, and when. Saved as the page's rule within seconds,
2502
+ * keeping anything else the rule does. Reading needs the `search` or `write` scope; changing, `write`. */
2503
+ merchandising: {
2504
+ /** Every arranged category page and search. */
2505
+ list: (signal?: AbortSignal) => Promise<Arrangement[]>;
2506
+ /** One page's or search's arrangement; status "none" when nothing is arranged. */
2507
+ get: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
2508
+ /** Changes one: `order` up to 20 objectIDs placed first, `hidden` up to 100, `banner` ({ image, link?, title?,
2509
+ * position? } or null), `active` ({ from?, until? } or null), `enabled`. Fields left out stay as they are. */
2510
+ set: (target: MerchandisingTarget, change: ArrangementChange, signal?: AbortSignal) => Promise<Arrangement>;
2511
+ /** Stops arranging one: its order, hidden products and banner go; the rule's other actions stay. */
2512
+ remove: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
2513
+ };
2514
+ /** Images for the index's banners, hosted by Findlane at https://images.findlane.dev (0.23.0): JPEG, PNG,
2515
+ * WebP or AVIF, up to 2 MB each, 50 images and 100 MB an index. An image no rule shows is deleted a week
2516
+ * later. Uploading and deleting need the `write` scope. */
2517
+ images: {
2518
+ list: (signal?: AbortSignal) => Promise<ImageLibrary>;
2519
+ /** Uploads an image's bytes; the same image again gives the same URL. */
2520
+ upload: (image: Blob | ArrayBuffer | Uint8Array, options?: {
2521
+ contentType?: string;
2522
+ signal?: AbortSignal;
2523
+ }) => Promise<UploadedImage & {
2524
+ error?: string;
2525
+ }>;
2526
+ /** Uploads the image at an https address, which Findlane fetches. */
2527
+ uploadFromUrl: (url: string, signal?: AbortSignal) => Promise<UploadedImage>;
2528
+ /** Deletes an image by its key; refused (409) while a rule's banner shows it. */
2529
+ delete: (key: string, signal?: AbortSignal) => Promise<{
2530
+ deleted: true;
2531
+ }>;
2532
+ };
2533
+ /** The index's product feed (0.24.0): a store's Google or Meta product feed, or a JSON file of records, read on
2534
+ * a schedule (hourly, every 6 hours, or daily), replacing the index's records with only what changed. Reading
2535
+ * needs the `search` or `write` scope; the rest, `write`. */
2536
+ feed: {
2537
+ /** The feed and its last run, or null. */
2538
+ get: (signal?: AbortSignal) => Promise<ProductFeed | null>;
2539
+ /** Connects a feed or changes its setup; a new address, sign-in or variants setting reads it now. */
2540
+ set: (setup: FeedSetup, signal?: AbortSignal) => Promise<ProductFeed>;
2541
+ /** Disconnects it; the index keeps its records. */
2542
+ remove: (signal?: AbortSignal) => Promise<void>;
2543
+ /** Reads a feed's first 2,000 items without saving anything; without a url, the connected feed's. */
2544
+ check: (setup?: Pick<FeedSetup, "url" | "username" | "password" | "variants">, signal?: AbortSignal) => Promise<FeedCheck>;
2545
+ /** Reads it now, in full, in the background; `runs` shows how it went. */
2546
+ run: (signal?: AbortSignal) => Promise<FeedRun>;
2547
+ /** The last 20 runs, newest first. */
2548
+ runs: (signal?: AbortSignal) => Promise<FeedRun[]>;
2549
+ /** Imports a held run's copy of the feed as it is, without the checks that held it. */
2550
+ importHeld: (runId: string, signal?: AbortSignal) => Promise<FeedRun>;
2551
+ };
2552
+ lists: {
2553
+ /** One list by its ID; throws a FindlaneError with status 404 when there's none. `limit` shows fewer. */
2554
+ get: <R = S_5>(id: string, options?: {
2555
+ limit?: number;
2556
+ signal?: AbortSignal;
2557
+ }) => Promise<List<R>>;
2558
+ /** Several lists (up to 10) in the order asked, leaving out IDs without a list; without IDs, all of them. */
2559
+ getMany: <R = S_5>(ids?: string[], options?: {
2560
+ limit?: number;
2561
+ signal?: AbortSignal;
2562
+ }) => Promise<List<R>[]>;
2563
+ /** How the index's lists are set up, and their last build. */
2564
+ settings: (signal?: AbortSignal) => Promise<ListSettings>;
2565
+ /** Creates or changes a list and builds it; one whose filters, sort or field don't work on the index is
2566
+ * refused with why (400), and a new list past the plan's lists per index too (402). */
2567
+ save: (id: string, list: ListDefinition, signal?: AbortSignal) => Promise<ListSettings>;
2568
+ delete: (id: string, signal?: AbortSignal) => Promise<ListSettings>;
2569
+ /** Puts the lists in this order: every list's ID once. */
2570
+ order: (ids: string[], signal?: AbortSignal) => Promise<ListSettings>;
2571
+ /** Builds the lists again now, rather than within the minute they take to follow the index; once a minute. */
2572
+ refresh: (signal?: AbortSignal) => Promise<ListSettings>;
2573
+ /** What a list would hold, built without saving it. */
2574
+ preview: <R = S_5>(list: ListDefinition, signal?: AbortSignal) => Promise<{
2575
+ list: List<R>;
2576
+ tookMs: number;
2577
+ }>;
2578
+ };
2579
+ /** Events for the index's Events page and Bought together; the API key needs the `events` or `write`
2580
+ * scope. Orders count once each, however often they're sent. */
2581
+ events: {
2582
+ /** Sends events, 200 a request. One bad event doesn't refuse the rest: they're in `rejected`. Pass
2583
+ * `{ visitorId, visitId }` to link a shopper's events (see EventOptions). */
2584
+ send: (events: ServerEvent[], options?: AbortSignal | EventOptions) => Promise<EventsResult>;
2585
+ /** Sends past orders, up to 400 days old, from a list or an async iterable (such as a database
2586
+ * cursor), 200 a request. */
2587
+ importOrders: (orders: Iterable<Order> | AsyncIterable<Order>, signal?: AbortSignal) => Promise<EventsResult>;
2588
+ /** Takes a cancelled or refunded order out of Bought together. */
2589
+ cancelOrder: (orderID: string, signal?: AbortSignal) => Promise<EventsResult>;
2590
+ /** Deletes the events sent with these visitor or visit IDs, for shoppers who asked: Findlane does it
2591
+ * within a week. 1,000 IDs a request. */
2592
+ forget: (ids: string[], signal?: AbortSignal) => Promise<{
2593
+ forgotten: number;
2594
+ }>;
2595
+ /** A route on your own domain for the browser SDK's events (its `eventsUrl` option): ad blockers
2596
+ * block beacons to other sites, not to the page's own. Give it the browser's POST request (Next.js
2597
+ * route handlers, Workers, Hono, Bun, Deno); it finds the visitor's address in the headers
2598
+ * Cloudflare, Vercel and most proxies set. Where a visitor reaches your server directly, they can
2599
+ * set those too, so pass `{ ip }`. The API key needs the `events` or `write` scope. */
2600
+ proxy: (request: Request, visitor?: Partial<RelayedVisitor>) => Promise<Response>;
2601
+ /** `proxy` for servers without Fetch API requests, such as Express: the request's body as text,
2602
+ * and its visitor. Answers with the API's response. */
2603
+ relay: (body: string, visitor: RelayedVisitor, signal?: AbortSignal) => Promise<Response>;
2604
+ };
2605
+ /** The index's search analytics. The API key needs the `analytics` scope, and works only from a server:
2606
+ * requests from web pages are refused. */
2607
+ analytics: {
2608
+ /** Searches, searches without results and response times, beside the same span before, and a series per
2609
+ * hour (up to 7 days, by default) or day. */
2610
+ searches: (options?: AnalyticsOptions & {
2611
+ interval?: "hour" | "day";
2612
+ }) => Promise<SearchesReport>;
2613
+ /** Queries, the most searched first: `top` (by default) with their clicks, `noResults`, or `noClicks`, which
2614
+ * found something nobody clicked. `limit` is 1 to 1,000, 100 by default. */
2615
+ queries: <L extends keyof QueryLists = "top">(options?: AnalyticsOptions & {
2616
+ list?: L | undefined;
2617
+ limit?: number;
2618
+ }) => Promise<QueriesReport<L>>;
2619
+ /** The filter fields and sorts searches used. */
2620
+ filters: (options?: AnalyticsOptions) => Promise<FiltersReport>;
2621
+ /** Events of each type over time and by source, orders stored, and refused and bot events. */
2622
+ events: (options?: AnalyticsOptions & {
2623
+ interval?: "hour" | "day";
2624
+ }) => Promise<EventsReport>;
2625
+ /** The most viewed, most added to carts and most ordered products, with titles and images, and those
2626
+ * viewed but rarely bought. Exact, from every event kept (13 months, from 9 October 2026). */
2627
+ products: (options?: AnalyticsOptions) => Promise<ProductListsReport>;
2628
+ /** Every product with events or orders in the window, the most viewed first, up to 50,000: views,
2629
+ * viewers, clicks, add-to-carts and orders. Exact, like `products`. */
2630
+ productCounts: (options?: AnalyticsOptions) => Promise<ProductCountsReport>;
2631
+ /** One product's views, viewers, clicks, add-to-carts and orders per hour or day, the queries it was
2632
+ * clicked from, and its clicks in recommendations. Fast, for a product page in an admin: views and
2633
+ * clicks are estimates when `sampled`, and an add-to-cart of several products counts toward the first. */
2634
+ product: (objectID: string, options?: AnalyticsOptions & {
2635
+ interval?: "hour" | "day";
2636
+ }) => Promise<ProductReport>;
2637
+ /** Revenue from search: orders and add-to-carts of products found through search, per query and per
2638
+ * product (0.20.0). */
2639
+ revenue: (options?: Omit<AnalyticsOptions, "source">) => Promise<RevenueReport>;
2640
+ /** Sales by filter value: each facet value's clicks, add-to-carts, orders and revenue (0.26.0). */
2641
+ filterSales: (options?: Omit<AnalyticsOptions, "source">) => Promise<FilterSalesReport>;
2642
+ /** Each banner's shown (shoppers' searches that showed it, cache answers included) and clicks, by its rule,
2643
+ * over the last 7, 30 (by default) or 90 days (0.23.0). */
2644
+ banners: (options?: {
2645
+ range?: "7d" | "30d" | "90d";
2646
+ signal?: AbortSignal;
2647
+ }) => Promise<BannerStatsReport>;
2648
+ };
2649
+ upsert: (records: S_5[], signal?: AbortSignal) => Promise<WriteReceipt>;
2650
+ getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_5>>;
2651
+ upsertOne: (record: S_5, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
2652
+ deleteOne: (objectID: string, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
2653
+ replaceAll: (records: S_5[], signal?: AbortSignal) => Promise<WriteReceipt>;
2654
+ beginReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
2655
+ uploadReplacementBatch: (stageId: string, batchId: string, records: S_5[], signal?: AbortSignal) => Promise<ReplacementStage>;
2656
+ commitReplacement: (stageId: string, expectedBatches: number, expectedRecords: number, signal?: AbortSignal) => Promise<WriteReceipt>;
2657
+ abortReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
2658
+ replaceAllStaged: (records: Iterable<S_5> | AsyncIterable<S_5>, options?: StagedReplaceOptions) => Promise<WriteReceipt>;
2659
+ delete: (objectID: string, signal?: AbortSignal) => Promise<WriteReceipt>;
2660
+ getSettings: (signal?: AbortSignal) => Promise<CurrentSettings>;
2661
+ replaceSettings: (settings: IndexSettings, signal?: AbortSignal) => Promise<SavedSettings>;
2662
+ /** Compares settings with the index's own without saving them: its search tests, `queries`, and its 100
2663
+ * most searched queries of the last 30 days, each searched with both, for up to 20 seconds. Takes the
2664
+ * settings `replaceSettings` does, or only those that change; `{}` runs the tests with the current
2665
+ * settings. A change to what the index stores (new searchable, facet, filter, sort or location fields,
2666
+ * or normalization) throws a 409: save it first. Not counted as searches. */
2667
+ compareSettings: (settings: Partial<IndexSettings>, options?: CompareOptions) => Promise<SettingsComparison>;
2668
+ /** The index's search tests. */
2669
+ getSearchTests: (signal?: AbortSignal) => Promise<SearchTest[]>;
2670
+ /** Replaces the index's search tests, up to 200; `[]` deletes them. */
2671
+ setSearchTests: (tests: SearchTest[], signal?: AbortSignal) => Promise<SearchTest[]>;
2672
+ /** Waits until no settings rebuild is running; throws if it failed. */
2673
+ waitForSettings: (options?: {
2674
+ timeoutMs?: number;
2675
+ intervalMs?: number;
2676
+ signal?: AbortSignal;
2677
+ }) => Promise<CurrentSettings>;
2678
+ subindex: <S_6 extends {
2679
+ objectID: string;
2680
+ } = JsonRecord>(subindex: string) => {
2681
+ /** Searches the index; the API key needs the `search` scope. Pass `{ visitor }` when searching for
2682
+ * someone, such as a shopper loading a server-rendered page (see Visitor). */
2683
+ search: <R = S_6>(query?: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<SearchResponse<R>>;
2684
+ /** Did you mean: for a search that found nothing, a query that finds something, or null. Takes the
2685
+ * same request (its q, filters, and fields matter). Needs the `didYouMean` setting; not counted as
2686
+ * a search. */
2687
+ suggest: (query: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<DidYouMean | null>;
2688
+ /** Query suggestions: whole searches to offer as a shopper types `q`, the best first; with `q` empty, the
2689
+ * index's popular searches. The API key needs the `search` scope; not counted as searches. `limit`: 1 to
2690
+ * 10, 5 by default. */
2691
+ querySuggestions: (query: {
2692
+ q: string;
2693
+ limit?: number;
2694
+ }, options?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
2695
+ /** The index's popular searches, for an empty search box, with the owner's pinned searches first;
2696
+ * empty until the index has enough searches. The list changes daily. */
2697
+ popularSearches: (options?: {
2698
+ limit?: number;
2699
+ }, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
2700
+ /** A product's recommendations (the recommendations add-on): products that go with it, and similar products.
2701
+ * The API key needs the `search` scope; not counted as a search. */
2702
+ recommendations: <R = S_6>(objectID: string, options?: RecommendationsRequest, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<RecommendationsResponse<R>>;
2703
+ /** The index's lists: rows of products, such as Popular, and facet fields' values for menus, built ahead
2704
+ * and served from a cache, so reading them isn't counted as searches. Reading needs the `search` scope;
2705
+ * setting them up needs `write`. */
2706
+ /** Merchandising (0.23.0): category pages and searches arranged as the dashboard's Merchandising page does:
2707
+ * the products placed first, hidden products, a banner, and when. Saved as the page's rule within seconds,
2708
+ * keeping anything else the rule does. Reading needs the `search` or `write` scope; changing, `write`. */
2709
+ merchandising: {
2710
+ /** Every arranged category page and search. */
2711
+ list: (signal?: AbortSignal) => Promise<Arrangement[]>;
2712
+ /** One page's or search's arrangement; status "none" when nothing is arranged. */
2713
+ get: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
2714
+ /** Changes one: `order` up to 20 objectIDs placed first, `hidden` up to 100, `banner` ({ image, link?, title?,
2715
+ * position? } or null), `active` ({ from?, until? } or null), `enabled`. Fields left out stay as they are. */
2716
+ set: (target: MerchandisingTarget, change: ArrangementChange, signal?: AbortSignal) => Promise<Arrangement>;
2717
+ /** Stops arranging one: its order, hidden products and banner go; the rule's other actions stay. */
2718
+ remove: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
2719
+ };
2720
+ /** Images for the index's banners, hosted by Findlane at https://images.findlane.dev (0.23.0): JPEG, PNG,
2721
+ * WebP or AVIF, up to 2 MB each, 50 images and 100 MB an index. An image no rule shows is deleted a week
2722
+ * later. Uploading and deleting need the `write` scope. */
2723
+ images: {
2724
+ list: (signal?: AbortSignal) => Promise<ImageLibrary>;
2725
+ /** Uploads an image's bytes; the same image again gives the same URL. */
2726
+ upload: (image: Blob | ArrayBuffer | Uint8Array, options?: {
2727
+ contentType?: string;
2728
+ signal?: AbortSignal;
2729
+ }) => Promise<UploadedImage & {
2730
+ error?: string;
2731
+ }>;
2732
+ /** Uploads the image at an https address, which Findlane fetches. */
2733
+ uploadFromUrl: (url: string, signal?: AbortSignal) => Promise<UploadedImage>;
2734
+ /** Deletes an image by its key; refused (409) while a rule's banner shows it. */
2735
+ delete: (key: string, signal?: AbortSignal) => Promise<{
2736
+ deleted: true;
2737
+ }>;
2738
+ };
2739
+ /** The index's product feed (0.24.0): a store's Google or Meta product feed, or a JSON file of records, read on
2740
+ * a schedule (hourly, every 6 hours, or daily), replacing the index's records with only what changed. Reading
2741
+ * needs the `search` or `write` scope; the rest, `write`. */
2742
+ feed: {
2743
+ /** The feed and its last run, or null. */
2744
+ get: (signal?: AbortSignal) => Promise<ProductFeed | null>;
2745
+ /** Connects a feed or changes its setup; a new address, sign-in or variants setting reads it now. */
2746
+ set: (setup: FeedSetup, signal?: AbortSignal) => Promise<ProductFeed>;
2747
+ /** Disconnects it; the index keeps its records. */
2748
+ remove: (signal?: AbortSignal) => Promise<void>;
2749
+ /** Reads a feed's first 2,000 items without saving anything; without a url, the connected feed's. */
2750
+ check: (setup?: Pick<FeedSetup, "url" | "username" | "password" | "variants">, signal?: AbortSignal) => Promise<FeedCheck>;
2751
+ /** Reads it now, in full, in the background; `runs` shows how it went. */
2752
+ run: (signal?: AbortSignal) => Promise<FeedRun>;
2753
+ /** The last 20 runs, newest first. */
2754
+ runs: (signal?: AbortSignal) => Promise<FeedRun[]>;
2755
+ /** Imports a held run's copy of the feed as it is, without the checks that held it. */
2756
+ importHeld: (runId: string, signal?: AbortSignal) => Promise<FeedRun>;
2757
+ };
2758
+ lists: {
2759
+ /** One list by its ID; throws a FindlaneError with status 404 when there's none. `limit` shows fewer. */
2760
+ get: <R = S_6>(id: string, options?: {
2761
+ limit?: number;
2762
+ signal?: AbortSignal;
2763
+ }) => Promise<List<R>>;
2764
+ /** Several lists (up to 10) in the order asked, leaving out IDs without a list; without IDs, all of them. */
2765
+ getMany: <R = S_6>(ids?: string[], options?: {
2766
+ limit?: number;
2767
+ signal?: AbortSignal;
2768
+ }) => Promise<List<R>[]>;
2769
+ /** How the index's lists are set up, and their last build. */
2770
+ settings: (signal?: AbortSignal) => Promise<ListSettings>;
2771
+ /** Creates or changes a list and builds it; one whose filters, sort or field don't work on the index is
2772
+ * refused with why (400), and a new list past the plan's lists per index too (402). */
2773
+ save: (id: string, list: ListDefinition, signal?: AbortSignal) => Promise<ListSettings>;
2774
+ delete: (id: string, signal?: AbortSignal) => Promise<ListSettings>;
2775
+ /** Puts the lists in this order: every list's ID once. */
2776
+ order: (ids: string[], signal?: AbortSignal) => Promise<ListSettings>;
2777
+ /** Builds the lists again now, rather than within the minute they take to follow the index; once a minute. */
2778
+ refresh: (signal?: AbortSignal) => Promise<ListSettings>;
2779
+ /** What a list would hold, built without saving it. */
2780
+ preview: <R = S_6>(list: ListDefinition, signal?: AbortSignal) => Promise<{
2781
+ list: List<R>;
2782
+ tookMs: number;
2783
+ }>;
2784
+ };
2785
+ /** Events for the index's Events page and Bought together; the API key needs the `events` or `write`
2786
+ * scope. Orders count once each, however often they're sent. */
2787
+ events: {
2788
+ /** Sends events, 200 a request. One bad event doesn't refuse the rest: they're in `rejected`. Pass
2789
+ * `{ visitorId, visitId }` to link a shopper's events (see EventOptions). */
2790
+ send: (events: ServerEvent[], options?: AbortSignal | EventOptions) => Promise<EventsResult>;
2791
+ /** Sends past orders, up to 400 days old, from a list or an async iterable (such as a database
2792
+ * cursor), 200 a request. */
2793
+ importOrders: (orders: Iterable<Order> | AsyncIterable<Order>, signal?: AbortSignal) => Promise<EventsResult>;
2794
+ /** Takes a cancelled or refunded order out of Bought together. */
2795
+ cancelOrder: (orderID: string, signal?: AbortSignal) => Promise<EventsResult>;
2796
+ /** Deletes the events sent with these visitor or visit IDs, for shoppers who asked: Findlane does it
2797
+ * within a week. 1,000 IDs a request. */
2798
+ forget: (ids: string[], signal?: AbortSignal) => Promise<{
2799
+ forgotten: number;
2800
+ }>;
2801
+ /** A route on your own domain for the browser SDK's events (its `eventsUrl` option): ad blockers
2802
+ * block beacons to other sites, not to the page's own. Give it the browser's POST request (Next.js
2803
+ * route handlers, Workers, Hono, Bun, Deno); it finds the visitor's address in the headers
2804
+ * Cloudflare, Vercel and most proxies set. Where a visitor reaches your server directly, they can
2805
+ * set those too, so pass `{ ip }`. The API key needs the `events` or `write` scope. */
2806
+ proxy: (request: Request, visitor?: Partial<RelayedVisitor>) => Promise<Response>;
2807
+ /** `proxy` for servers without Fetch API requests, such as Express: the request's body as text,
2808
+ * and its visitor. Answers with the API's response. */
2809
+ relay: (body: string, visitor: RelayedVisitor, signal?: AbortSignal) => Promise<Response>;
2810
+ };
2811
+ /** The index's search analytics. The API key needs the `analytics` scope, and works only from a server:
2812
+ * requests from web pages are refused. */
2813
+ analytics: {
2814
+ /** Searches, searches without results and response times, beside the same span before, and a series per
2815
+ * hour (up to 7 days, by default) or day. */
2816
+ searches: (options?: AnalyticsOptions & {
2817
+ interval?: "hour" | "day";
2818
+ }) => Promise<SearchesReport>;
2819
+ /** Queries, the most searched first: `top` (by default) with their clicks, `noResults`, or `noClicks`, which
2820
+ * found something nobody clicked. `limit` is 1 to 1,000, 100 by default. */
2821
+ queries: <L extends keyof QueryLists = "top">(options?: AnalyticsOptions & {
2822
+ list?: L | undefined;
2823
+ limit?: number;
2824
+ }) => Promise<QueriesReport<L>>;
2825
+ /** The filter fields and sorts searches used. */
2826
+ filters: (options?: AnalyticsOptions) => Promise<FiltersReport>;
2827
+ /** Events of each type over time and by source, orders stored, and refused and bot events. */
2828
+ events: (options?: AnalyticsOptions & {
2829
+ interval?: "hour" | "day";
2830
+ }) => Promise<EventsReport>;
2831
+ /** The most viewed, most added to carts and most ordered products, with titles and images, and those
2832
+ * viewed but rarely bought. Exact, from every event kept (13 months, from 9 October 2026). */
2833
+ products: (options?: AnalyticsOptions) => Promise<ProductListsReport>;
2834
+ /** Every product with events or orders in the window, the most viewed first, up to 50,000: views,
2835
+ * viewers, clicks, add-to-carts and orders. Exact, like `products`. */
2836
+ productCounts: (options?: AnalyticsOptions) => Promise<ProductCountsReport>;
2837
+ /** One product's views, viewers, clicks, add-to-carts and orders per hour or day, the queries it was
2838
+ * clicked from, and its clicks in recommendations. Fast, for a product page in an admin: views and
2839
+ * clicks are estimates when `sampled`, and an add-to-cart of several products counts toward the first. */
2840
+ product: (objectID: string, options?: AnalyticsOptions & {
2841
+ interval?: "hour" | "day";
2842
+ }) => Promise<ProductReport>;
2843
+ /** Revenue from search: orders and add-to-carts of products found through search, per query and per
2844
+ * product (0.20.0). */
2845
+ revenue: (options?: Omit<AnalyticsOptions, "source">) => Promise<RevenueReport>;
2846
+ /** Sales by filter value: each facet value's clicks, add-to-carts, orders and revenue (0.26.0). */
2847
+ filterSales: (options?: Omit<AnalyticsOptions, "source">) => Promise<FilterSalesReport>;
2848
+ /** Each banner's shown (shoppers' searches that showed it, cache answers included) and clicks, by its rule,
2849
+ * over the last 7, 30 (by default) or 90 days (0.23.0). */
2850
+ banners: (options?: {
2851
+ range?: "7d" | "30d" | "90d";
2852
+ signal?: AbortSignal;
2853
+ }) => Promise<BannerStatsReport>;
2854
+ };
2855
+ upsert: (records: S_6[], signal?: AbortSignal) => Promise<WriteReceipt>;
2856
+ getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_6>>;
2857
+ upsertOne: (record: S_6, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
2858
+ deleteOne: (objectID: string, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
2859
+ replaceAll: (records: S_6[], signal?: AbortSignal) => Promise<WriteReceipt>;
2860
+ beginReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
2861
+ uploadReplacementBatch: (stageId: string, batchId: string, records: S_6[], signal?: AbortSignal) => Promise<ReplacementStage>;
2862
+ commitReplacement: (stageId: string, expectedBatches: number, expectedRecords: number, signal?: AbortSignal) => Promise<WriteReceipt>;
2863
+ abortReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
2864
+ replaceAllStaged: (records: Iterable<S_6> | AsyncIterable<S_6>, options?: StagedReplaceOptions) => Promise<WriteReceipt>;
2865
+ delete: (objectID: string, signal?: AbortSignal) => Promise<WriteReceipt>;
2866
+ getSettings: (signal?: AbortSignal) => Promise<CurrentSettings>;
2867
+ replaceSettings: (settings: IndexSettings, signal?: AbortSignal) => Promise<SavedSettings>;
2868
+ /** Compares settings with the index's own without saving them: its search tests, `queries`, and its 100
2869
+ * most searched queries of the last 30 days, each searched with both, for up to 20 seconds. Takes the
2870
+ * settings `replaceSettings` does, or only those that change; `{}` runs the tests with the current
2871
+ * settings. A change to what the index stores (new searchable, facet, filter, sort or location fields,
2872
+ * or normalization) throws a 409: save it first. Not counted as searches. */
2873
+ compareSettings: (settings: Partial<IndexSettings>, options?: CompareOptions) => Promise<SettingsComparison>;
2874
+ /** The index's search tests. */
2875
+ getSearchTests: (signal?: AbortSignal) => Promise<SearchTest[]>;
2876
+ /** Replaces the index's search tests, up to 200; `[]` deletes them. */
2877
+ setSearchTests: (tests: SearchTest[], signal?: AbortSignal) => Promise<SearchTest[]>;
2878
+ /** Waits until no settings rebuild is running; throws if it failed. */
2879
+ waitForSettings: (options?: {
2880
+ timeoutMs?: number;
2881
+ intervalMs?: number;
2882
+ signal?: AbortSignal;
2883
+ }) => Promise<CurrentSettings>;
2884
+ subindex: <S_7 extends {
2885
+ objectID: string;
2886
+ } = JsonRecord>(subindex: string) => {
2887
+ /** Searches the index; the API key needs the `search` scope. Pass `{ visitor }` when searching for
2888
+ * someone, such as a shopper loading a server-rendered page (see Visitor). */
2889
+ search: <R = S_7>(query?: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<SearchResponse<R>>;
2890
+ /** Did you mean: for a search that found nothing, a query that finds something, or null. Takes the
2891
+ * same request (its q, filters, and fields matter). Needs the `didYouMean` setting; not counted as
2892
+ * a search. */
2893
+ suggest: (query: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<DidYouMean | null>;
2894
+ /** Query suggestions: whole searches to offer as a shopper types `q`, the best first; with `q` empty, the
2895
+ * index's popular searches. The API key needs the `search` scope; not counted as searches. `limit`: 1 to
2896
+ * 10, 5 by default. */
2897
+ querySuggestions: (query: {
2898
+ q: string;
2899
+ limit?: number;
2900
+ }, options?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
2901
+ /** The index's popular searches, for an empty search box, with the owner's pinned searches first;
2902
+ * empty until the index has enough searches. The list changes daily. */
2903
+ popularSearches: (options?: {
2904
+ limit?: number;
2905
+ }, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
2906
+ /** A product's recommendations (the recommendations add-on): products that go with it, and similar products.
2907
+ * The API key needs the `search` scope; not counted as a search. */
2908
+ recommendations: <R = S_7>(objectID: string, options?: RecommendationsRequest, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<RecommendationsResponse<R>>;
2909
+ /** The index's lists: rows of products, such as Popular, and facet fields' values for menus, built ahead
2910
+ * and served from a cache, so reading them isn't counted as searches. Reading needs the `search` scope;
2911
+ * setting them up needs `write`. */
2912
+ /** Merchandising (0.23.0): category pages and searches arranged as the dashboard's Merchandising page does:
2913
+ * the products placed first, hidden products, a banner, and when. Saved as the page's rule within seconds,
2914
+ * keeping anything else the rule does. Reading needs the `search` or `write` scope; changing, `write`. */
2915
+ merchandising: {
2916
+ /** Every arranged category page and search. */
2917
+ list: (signal?: AbortSignal) => Promise<Arrangement[]>;
2918
+ /** One page's or search's arrangement; status "none" when nothing is arranged. */
2919
+ get: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
2920
+ /** Changes one: `order` up to 20 objectIDs placed first, `hidden` up to 100, `banner` ({ image, link?, title?,
2921
+ * position? } or null), `active` ({ from?, until? } or null), `enabled`. Fields left out stay as they are. */
2922
+ set: (target: MerchandisingTarget, change: ArrangementChange, signal?: AbortSignal) => Promise<Arrangement>;
2923
+ /** Stops arranging one: its order, hidden products and banner go; the rule's other actions stay. */
2924
+ remove: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
2925
+ };
2926
+ /** Images for the index's banners, hosted by Findlane at https://images.findlane.dev (0.23.0): JPEG, PNG,
2927
+ * WebP or AVIF, up to 2 MB each, 50 images and 100 MB an index. An image no rule shows is deleted a week
2928
+ * later. Uploading and deleting need the `write` scope. */
2929
+ images: {
2930
+ list: (signal?: AbortSignal) => Promise<ImageLibrary>;
2931
+ /** Uploads an image's bytes; the same image again gives the same URL. */
2932
+ upload: (image: Blob | ArrayBuffer | Uint8Array, options?: {
2933
+ contentType?: string;
2934
+ signal?: AbortSignal;
2935
+ }) => Promise<UploadedImage & {
2936
+ error?: string;
2937
+ }>;
2938
+ /** Uploads the image at an https address, which Findlane fetches. */
2939
+ uploadFromUrl: (url: string, signal?: AbortSignal) => Promise<UploadedImage>;
2940
+ /** Deletes an image by its key; refused (409) while a rule's banner shows it. */
2941
+ delete: (key: string, signal?: AbortSignal) => Promise<{
2942
+ deleted: true;
2943
+ }>;
2944
+ };
2945
+ /** The index's product feed (0.24.0): a store's Google or Meta product feed, or a JSON file of records, read on
2946
+ * a schedule (hourly, every 6 hours, or daily), replacing the index's records with only what changed. Reading
2947
+ * needs the `search` or `write` scope; the rest, `write`. */
2948
+ feed: {
2949
+ /** The feed and its last run, or null. */
2950
+ get: (signal?: AbortSignal) => Promise<ProductFeed | null>;
2951
+ /** Connects a feed or changes its setup; a new address, sign-in or variants setting reads it now. */
2952
+ set: (setup: FeedSetup, signal?: AbortSignal) => Promise<ProductFeed>;
2953
+ /** Disconnects it; the index keeps its records. */
2954
+ remove: (signal?: AbortSignal) => Promise<void>;
2955
+ /** Reads a feed's first 2,000 items without saving anything; without a url, the connected feed's. */
2956
+ check: (setup?: Pick<FeedSetup, "url" | "username" | "password" | "variants">, signal?: AbortSignal) => Promise<FeedCheck>;
2957
+ /** Reads it now, in full, in the background; `runs` shows how it went. */
2958
+ run: (signal?: AbortSignal) => Promise<FeedRun>;
2959
+ /** The last 20 runs, newest first. */
2960
+ runs: (signal?: AbortSignal) => Promise<FeedRun[]>;
2961
+ /** Imports a held run's copy of the feed as it is, without the checks that held it. */
2962
+ importHeld: (runId: string, signal?: AbortSignal) => Promise<FeedRun>;
2963
+ };
2964
+ lists: {
2965
+ /** One list by its ID; throws a FindlaneError with status 404 when there's none. `limit` shows fewer. */
2966
+ get: <R = S_7>(id: string, options?: {
2967
+ limit?: number;
2968
+ signal?: AbortSignal;
2969
+ }) => Promise<List<R>>;
2970
+ /** Several lists (up to 10) in the order asked, leaving out IDs without a list; without IDs, all of them. */
2971
+ getMany: <R = S_7>(ids?: string[], options?: {
2972
+ limit?: number;
2973
+ signal?: AbortSignal;
2974
+ }) => Promise<List<R>[]>;
2975
+ /** How the index's lists are set up, and their last build. */
2976
+ settings: (signal?: AbortSignal) => Promise<ListSettings>;
2977
+ /** Creates or changes a list and builds it; one whose filters, sort or field don't work on the index is
2978
+ * refused with why (400), and a new list past the plan's lists per index too (402). */
2979
+ save: (id: string, list: ListDefinition, signal?: AbortSignal) => Promise<ListSettings>;
2980
+ delete: (id: string, signal?: AbortSignal) => Promise<ListSettings>;
2981
+ /** Puts the lists in this order: every list's ID once. */
2982
+ order: (ids: string[], signal?: AbortSignal) => Promise<ListSettings>;
2983
+ /** Builds the lists again now, rather than within the minute they take to follow the index; once a minute. */
2984
+ refresh: (signal?: AbortSignal) => Promise<ListSettings>;
2985
+ /** What a list would hold, built without saving it. */
2986
+ preview: <R = S_7>(list: ListDefinition, signal?: AbortSignal) => Promise<{
2987
+ list: List<R>;
2988
+ tookMs: number;
2989
+ }>;
2990
+ };
2991
+ /** Events for the index's Events page and Bought together; the API key needs the `events` or `write`
2992
+ * scope. Orders count once each, however often they're sent. */
2993
+ events: {
2994
+ /** Sends events, 200 a request. One bad event doesn't refuse the rest: they're in `rejected`. Pass
2995
+ * `{ visitorId, visitId }` to link a shopper's events (see EventOptions). */
2996
+ send: (events: ServerEvent[], options?: AbortSignal | EventOptions) => Promise<EventsResult>;
2997
+ /** Sends past orders, up to 400 days old, from a list or an async iterable (such as a database
2998
+ * cursor), 200 a request. */
2999
+ importOrders: (orders: Iterable<Order> | AsyncIterable<Order>, signal?: AbortSignal) => Promise<EventsResult>;
3000
+ /** Takes a cancelled or refunded order out of Bought together. */
3001
+ cancelOrder: (orderID: string, signal?: AbortSignal) => Promise<EventsResult>;
3002
+ /** Deletes the events sent with these visitor or visit IDs, for shoppers who asked: Findlane does it
3003
+ * within a week. 1,000 IDs a request. */
3004
+ forget: (ids: string[], signal?: AbortSignal) => Promise<{
3005
+ forgotten: number;
3006
+ }>;
3007
+ /** A route on your own domain for the browser SDK's events (its `eventsUrl` option): ad blockers
3008
+ * block beacons to other sites, not to the page's own. Give it the browser's POST request (Next.js
3009
+ * route handlers, Workers, Hono, Bun, Deno); it finds the visitor's address in the headers
3010
+ * Cloudflare, Vercel and most proxies set. Where a visitor reaches your server directly, they can
3011
+ * set those too, so pass `{ ip }`. The API key needs the `events` or `write` scope. */
3012
+ proxy: (request: Request, visitor?: Partial<RelayedVisitor>) => Promise<Response>;
3013
+ /** `proxy` for servers without Fetch API requests, such as Express: the request's body as text,
3014
+ * and its visitor. Answers with the API's response. */
3015
+ relay: (body: string, visitor: RelayedVisitor, signal?: AbortSignal) => Promise<Response>;
3016
+ };
3017
+ /** The index's search analytics. The API key needs the `analytics` scope, and works only from a server:
3018
+ * requests from web pages are refused. */
3019
+ analytics: {
3020
+ /** Searches, searches without results and response times, beside the same span before, and a series per
3021
+ * hour (up to 7 days, by default) or day. */
3022
+ searches: (options?: AnalyticsOptions & {
3023
+ interval?: "hour" | "day";
3024
+ }) => Promise<SearchesReport>;
3025
+ /** Queries, the most searched first: `top` (by default) with their clicks, `noResults`, or `noClicks`, which
3026
+ * found something nobody clicked. `limit` is 1 to 1,000, 100 by default. */
3027
+ queries: <L extends keyof QueryLists = "top">(options?: AnalyticsOptions & {
3028
+ list?: L | undefined;
3029
+ limit?: number;
3030
+ }) => Promise<QueriesReport<L>>;
3031
+ /** The filter fields and sorts searches used. */
3032
+ filters: (options?: AnalyticsOptions) => Promise<FiltersReport>;
3033
+ /** Events of each type over time and by source, orders stored, and refused and bot events. */
3034
+ events: (options?: AnalyticsOptions & {
3035
+ interval?: "hour" | "day";
3036
+ }) => Promise<EventsReport>;
3037
+ /** The most viewed, most added to carts and most ordered products, with titles and images, and those
3038
+ * viewed but rarely bought. Exact, from every event kept (13 months, from 9 October 2026). */
3039
+ products: (options?: AnalyticsOptions) => Promise<ProductListsReport>;
3040
+ /** Every product with events or orders in the window, the most viewed first, up to 50,000: views,
3041
+ * viewers, clicks, add-to-carts and orders. Exact, like `products`. */
3042
+ productCounts: (options?: AnalyticsOptions) => Promise<ProductCountsReport>;
3043
+ /** One product's views, viewers, clicks, add-to-carts and orders per hour or day, the queries it was
3044
+ * clicked from, and its clicks in recommendations. Fast, for a product page in an admin: views and
3045
+ * clicks are estimates when `sampled`, and an add-to-cart of several products counts toward the first. */
3046
+ product: (objectID: string, options?: AnalyticsOptions & {
3047
+ interval?: "hour" | "day";
3048
+ }) => Promise<ProductReport>;
3049
+ /** Revenue from search: orders and add-to-carts of products found through search, per query and per
3050
+ * product (0.20.0). */
3051
+ revenue: (options?: Omit<AnalyticsOptions, "source">) => Promise<RevenueReport>;
3052
+ /** Sales by filter value: each facet value's clicks, add-to-carts, orders and revenue (0.26.0). */
3053
+ filterSales: (options?: Omit<AnalyticsOptions, "source">) => Promise<FilterSalesReport>;
3054
+ /** Each banner's shown (shoppers' searches that showed it, cache answers included) and clicks, by its rule,
3055
+ * over the last 7, 30 (by default) or 90 days (0.23.0). */
3056
+ banners: (options?: {
3057
+ range?: "7d" | "30d" | "90d";
3058
+ signal?: AbortSignal;
3059
+ }) => Promise<BannerStatsReport>;
3060
+ };
3061
+ upsert: (records: S_7[], signal?: AbortSignal) => Promise<WriteReceipt>;
3062
+ getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_7>>;
3063
+ upsertOne: (record: S_7, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
3064
+ deleteOne: (objectID: string, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
3065
+ replaceAll: (records: S_7[], signal?: AbortSignal) => Promise<WriteReceipt>;
3066
+ beginReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
3067
+ uploadReplacementBatch: (stageId: string, batchId: string, records: S_7[], signal?: AbortSignal) => Promise<ReplacementStage>;
3068
+ commitReplacement: (stageId: string, expectedBatches: number, expectedRecords: number, signal?: AbortSignal) => Promise<WriteReceipt>;
3069
+ abortReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
3070
+ replaceAllStaged: (records: Iterable<S_7> | AsyncIterable<S_7>, options?: StagedReplaceOptions) => Promise<WriteReceipt>;
3071
+ delete: (objectID: string, signal?: AbortSignal) => Promise<WriteReceipt>;
3072
+ getSettings: (signal?: AbortSignal) => Promise<CurrentSettings>;
3073
+ replaceSettings: (settings: IndexSettings, signal?: AbortSignal) => Promise<SavedSettings>;
3074
+ /** Compares settings with the index's own without saving them: its search tests, `queries`, and its 100
3075
+ * most searched queries of the last 30 days, each searched with both, for up to 20 seconds. Takes the
3076
+ * settings `replaceSettings` does, or only those that change; `{}` runs the tests with the current
3077
+ * settings. A change to what the index stores (new searchable, facet, filter, sort or location fields,
3078
+ * or normalization) throws a 409: save it first. Not counted as searches. */
3079
+ compareSettings: (settings: Partial<IndexSettings>, options?: CompareOptions) => Promise<SettingsComparison>;
3080
+ /** The index's search tests. */
3081
+ getSearchTests: (signal?: AbortSignal) => Promise<SearchTest[]>;
3082
+ /** Replaces the index's search tests, up to 200; `[]` deletes them. */
3083
+ setSearchTests: (tests: SearchTest[], signal?: AbortSignal) => Promise<SearchTest[]>;
3084
+ /** Waits until no settings rebuild is running; throws if it failed. */
3085
+ waitForSettings: (options?: {
3086
+ timeoutMs?: number;
3087
+ intervalMs?: number;
3088
+ signal?: AbortSignal;
3089
+ }) => Promise<CurrentSettings>;
3090
+ subindex: <S_8 extends {
3091
+ objectID: string;
3092
+ } = JsonRecord>(subindex: string) => {
3093
+ /** Searches the index; the API key needs the `search` scope. Pass `{ visitor }` when searching for
3094
+ * someone, such as a shopper loading a server-rendered page (see Visitor). */
3095
+ search: <R = S_8>(query?: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<SearchResponse<R>>;
3096
+ /** Did you mean: for a search that found nothing, a query that finds something, or null. Takes the
3097
+ * same request (its q, filters, and fields matter). Needs the `didYouMean` setting; not counted as
3098
+ * a search. */
3099
+ suggest: (query: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<DidYouMean | null>;
3100
+ /** Query suggestions: whole searches to offer as a shopper types `q`, the best first; with `q` empty, the
3101
+ * index's popular searches. The API key needs the `search` scope; not counted as searches. `limit`: 1 to
3102
+ * 10, 5 by default. */
3103
+ querySuggestions: (query: {
3104
+ q: string;
3105
+ limit?: number;
3106
+ }, options?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
3107
+ /** The index's popular searches, for an empty search box, with the owner's pinned searches first;
3108
+ * empty until the index has enough searches. The list changes daily. */
3109
+ popularSearches: (options?: {
3110
+ limit?: number;
3111
+ }, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
3112
+ /** A product's recommendations (the recommendations add-on): products that go with it, and similar products.
3113
+ * The API key needs the `search` scope; not counted as a search. */
3114
+ recommendations: <R = S_8>(objectID: string, options?: RecommendationsRequest, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<RecommendationsResponse<R>>;
3115
+ /** The index's lists: rows of products, such as Popular, and facet fields' values for menus, built ahead
3116
+ * and served from a cache, so reading them isn't counted as searches. Reading needs the `search` scope;
3117
+ * setting them up needs `write`. */
3118
+ /** Merchandising (0.23.0): category pages and searches arranged as the dashboard's Merchandising page does:
3119
+ * the products placed first, hidden products, a banner, and when. Saved as the page's rule within seconds,
3120
+ * keeping anything else the rule does. Reading needs the `search` or `write` scope; changing, `write`. */
3121
+ merchandising: {
3122
+ /** Every arranged category page and search. */
3123
+ list: (signal?: AbortSignal) => Promise<Arrangement[]>;
3124
+ /** One page's or search's arrangement; status "none" when nothing is arranged. */
3125
+ get: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
3126
+ /** Changes one: `order` up to 20 objectIDs placed first, `hidden` up to 100, `banner` ({ image, link?, title?,
3127
+ * position? } or null), `active` ({ from?, until? } or null), `enabled`. Fields left out stay as they are. */
3128
+ set: (target: MerchandisingTarget, change: ArrangementChange, signal?: AbortSignal) => Promise<Arrangement>;
3129
+ /** Stops arranging one: its order, hidden products and banner go; the rule's other actions stay. */
3130
+ remove: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
3131
+ };
3132
+ /** Images for the index's banners, hosted by Findlane at https://images.findlane.dev (0.23.0): JPEG, PNG,
3133
+ * WebP or AVIF, up to 2 MB each, 50 images and 100 MB an index. An image no rule shows is deleted a week
3134
+ * later. Uploading and deleting need the `write` scope. */
3135
+ images: {
3136
+ list: (signal?: AbortSignal) => Promise<ImageLibrary>;
3137
+ /** Uploads an image's bytes; the same image again gives the same URL. */
3138
+ upload: (image: Blob | ArrayBuffer | Uint8Array, options?: {
3139
+ contentType?: string;
3140
+ signal?: AbortSignal;
3141
+ }) => Promise<UploadedImage & {
3142
+ error?: string;
3143
+ }>;
3144
+ /** Uploads the image at an https address, which Findlane fetches. */
3145
+ uploadFromUrl: (url: string, signal?: AbortSignal) => Promise<UploadedImage>;
3146
+ /** Deletes an image by its key; refused (409) while a rule's banner shows it. */
3147
+ delete: (key: string, signal?: AbortSignal) => Promise<{
3148
+ deleted: true;
3149
+ }>;
3150
+ };
3151
+ /** The index's product feed (0.24.0): a store's Google or Meta product feed, or a JSON file of records, read on
3152
+ * a schedule (hourly, every 6 hours, or daily), replacing the index's records with only what changed. Reading
3153
+ * needs the `search` or `write` scope; the rest, `write`. */
3154
+ feed: {
3155
+ /** The feed and its last run, or null. */
3156
+ get: (signal?: AbortSignal) => Promise<ProductFeed | null>;
3157
+ /** Connects a feed or changes its setup; a new address, sign-in or variants setting reads it now. */
3158
+ set: (setup: FeedSetup, signal?: AbortSignal) => Promise<ProductFeed>;
3159
+ /** Disconnects it; the index keeps its records. */
3160
+ remove: (signal?: AbortSignal) => Promise<void>;
3161
+ /** Reads a feed's first 2,000 items without saving anything; without a url, the connected feed's. */
3162
+ check: (setup?: Pick<FeedSetup, "url" | "username" | "password" | "variants">, signal?: AbortSignal) => Promise<FeedCheck>;
3163
+ /** Reads it now, in full, in the background; `runs` shows how it went. */
3164
+ run: (signal?: AbortSignal) => Promise<FeedRun>;
3165
+ /** The last 20 runs, newest first. */
3166
+ runs: (signal?: AbortSignal) => Promise<FeedRun[]>;
3167
+ /** Imports a held run's copy of the feed as it is, without the checks that held it. */
3168
+ importHeld: (runId: string, signal?: AbortSignal) => Promise<FeedRun>;
3169
+ };
3170
+ lists: {
3171
+ /** One list by its ID; throws a FindlaneError with status 404 when there's none. `limit` shows fewer. */
3172
+ get: <R = S_8>(id: string, options?: {
3173
+ limit?: number;
3174
+ signal?: AbortSignal;
3175
+ }) => Promise<List<R>>;
3176
+ /** Several lists (up to 10) in the order asked, leaving out IDs without a list; without IDs, all of them. */
3177
+ getMany: <R = S_8>(ids?: string[], options?: {
3178
+ limit?: number;
3179
+ signal?: AbortSignal;
3180
+ }) => Promise<List<R>[]>;
3181
+ /** How the index's lists are set up, and their last build. */
3182
+ settings: (signal?: AbortSignal) => Promise<ListSettings>;
3183
+ /** Creates or changes a list and builds it; one whose filters, sort or field don't work on the index is
3184
+ * refused with why (400), and a new list past the plan's lists per index too (402). */
3185
+ save: (id: string, list: ListDefinition, signal?: AbortSignal) => Promise<ListSettings>;
3186
+ delete: (id: string, signal?: AbortSignal) => Promise<ListSettings>;
3187
+ /** Puts the lists in this order: every list's ID once. */
3188
+ order: (ids: string[], signal?: AbortSignal) => Promise<ListSettings>;
3189
+ /** Builds the lists again now, rather than within the minute they take to follow the index; once a minute. */
3190
+ refresh: (signal?: AbortSignal) => Promise<ListSettings>;
3191
+ /** What a list would hold, built without saving it. */
3192
+ preview: <R = S_8>(list: ListDefinition, signal?: AbortSignal) => Promise<{
3193
+ list: List<R>;
3194
+ tookMs: number;
3195
+ }>;
3196
+ };
3197
+ /** Events for the index's Events page and Bought together; the API key needs the `events` or `write`
3198
+ * scope. Orders count once each, however often they're sent. */
3199
+ events: {
3200
+ /** Sends events, 200 a request. One bad event doesn't refuse the rest: they're in `rejected`. Pass
3201
+ * `{ visitorId, visitId }` to link a shopper's events (see EventOptions). */
3202
+ send: (events: ServerEvent[], options?: AbortSignal | EventOptions) => Promise<EventsResult>;
3203
+ /** Sends past orders, up to 400 days old, from a list or an async iterable (such as a database
3204
+ * cursor), 200 a request. */
3205
+ importOrders: (orders: Iterable<Order> | AsyncIterable<Order>, signal?: AbortSignal) => Promise<EventsResult>;
3206
+ /** Takes a cancelled or refunded order out of Bought together. */
3207
+ cancelOrder: (orderID: string, signal?: AbortSignal) => Promise<EventsResult>;
3208
+ /** Deletes the events sent with these visitor or visit IDs, for shoppers who asked: Findlane does it
3209
+ * within a week. 1,000 IDs a request. */
3210
+ forget: (ids: string[], signal?: AbortSignal) => Promise<{
3211
+ forgotten: number;
3212
+ }>;
3213
+ /** A route on your own domain for the browser SDK's events (its `eventsUrl` option): ad blockers
3214
+ * block beacons to other sites, not to the page's own. Give it the browser's POST request (Next.js
3215
+ * route handlers, Workers, Hono, Bun, Deno); it finds the visitor's address in the headers
3216
+ * Cloudflare, Vercel and most proxies set. Where a visitor reaches your server directly, they can
3217
+ * set those too, so pass `{ ip }`. The API key needs the `events` or `write` scope. */
3218
+ proxy: (request: Request, visitor?: Partial<RelayedVisitor>) => Promise<Response>;
3219
+ /** `proxy` for servers without Fetch API requests, such as Express: the request's body as text,
3220
+ * and its visitor. Answers with the API's response. */
3221
+ relay: (body: string, visitor: RelayedVisitor, signal?: AbortSignal) => Promise<Response>;
3222
+ };
3223
+ /** The index's search analytics. The API key needs the `analytics` scope, and works only from a server:
3224
+ * requests from web pages are refused. */
3225
+ analytics: {
3226
+ /** Searches, searches without results and response times, beside the same span before, and a series per
3227
+ * hour (up to 7 days, by default) or day. */
3228
+ searches: (options?: AnalyticsOptions & {
3229
+ interval?: "hour" | "day";
3230
+ }) => Promise<SearchesReport>;
3231
+ /** Queries, the most searched first: `top` (by default) with their clicks, `noResults`, or `noClicks`, which
3232
+ * found something nobody clicked. `limit` is 1 to 1,000, 100 by default. */
3233
+ queries: <L extends keyof QueryLists = "top">(options?: AnalyticsOptions & {
3234
+ list?: L | undefined;
3235
+ limit?: number;
3236
+ }) => Promise<QueriesReport<L>>;
3237
+ /** The filter fields and sorts searches used. */
3238
+ filters: (options?: AnalyticsOptions) => Promise<FiltersReport>;
3239
+ /** Events of each type over time and by source, orders stored, and refused and bot events. */
3240
+ events: (options?: AnalyticsOptions & {
3241
+ interval?: "hour" | "day";
3242
+ }) => Promise<EventsReport>;
3243
+ /** The most viewed, most added to carts and most ordered products, with titles and images, and those
3244
+ * viewed but rarely bought. Exact, from every event kept (13 months, from 9 October 2026). */
3245
+ products: (options?: AnalyticsOptions) => Promise<ProductListsReport>;
3246
+ /** Every product with events or orders in the window, the most viewed first, up to 50,000: views,
3247
+ * viewers, clicks, add-to-carts and orders. Exact, like `products`. */
3248
+ productCounts: (options?: AnalyticsOptions) => Promise<ProductCountsReport>;
3249
+ /** One product's views, viewers, clicks, add-to-carts and orders per hour or day, the queries it was
3250
+ * clicked from, and its clicks in recommendations. Fast, for a product page in an admin: views and
3251
+ * clicks are estimates when `sampled`, and an add-to-cart of several products counts toward the first. */
3252
+ product: (objectID: string, options?: AnalyticsOptions & {
3253
+ interval?: "hour" | "day";
3254
+ }) => Promise<ProductReport>;
3255
+ /** Revenue from search: orders and add-to-carts of products found through search, per query and per
3256
+ * product (0.20.0). */
3257
+ revenue: (options?: Omit<AnalyticsOptions, "source">) => Promise<RevenueReport>;
3258
+ /** Sales by filter value: each facet value's clicks, add-to-carts, orders and revenue (0.26.0). */
3259
+ filterSales: (options?: Omit<AnalyticsOptions, "source">) => Promise<FilterSalesReport>;
3260
+ /** Each banner's shown (shoppers' searches that showed it, cache answers included) and clicks, by its rule,
3261
+ * over the last 7, 30 (by default) or 90 days (0.23.0). */
3262
+ banners: (options?: {
3263
+ range?: "7d" | "30d" | "90d";
3264
+ signal?: AbortSignal;
3265
+ }) => Promise<BannerStatsReport>;
3266
+ };
3267
+ upsert: (records: S_8[], signal?: AbortSignal) => Promise<WriteReceipt>;
3268
+ getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_8>>;
3269
+ upsertOne: (record: S_8, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
3270
+ deleteOne: (objectID: string, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
3271
+ replaceAll: (records: S_8[], signal?: AbortSignal) => Promise<WriteReceipt>;
3272
+ beginReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
3273
+ uploadReplacementBatch: (stageId: string, batchId: string, records: S_8[], signal?: AbortSignal) => Promise<ReplacementStage>;
3274
+ commitReplacement: (stageId: string, expectedBatches: number, expectedRecords: number, signal?: AbortSignal) => Promise<WriteReceipt>;
3275
+ abortReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
3276
+ replaceAllStaged: (records: Iterable<S_8> | AsyncIterable<S_8>, options?: StagedReplaceOptions) => Promise<WriteReceipt>;
3277
+ delete: (objectID: string, signal?: AbortSignal) => Promise<WriteReceipt>;
3278
+ getSettings: (signal?: AbortSignal) => Promise<CurrentSettings>;
3279
+ replaceSettings: (settings: IndexSettings, signal?: AbortSignal) => Promise<SavedSettings>;
3280
+ /** Compares settings with the index's own without saving them: its search tests, `queries`, and its 100
3281
+ * most searched queries of the last 30 days, each searched with both, for up to 20 seconds. Takes the
3282
+ * settings `replaceSettings` does, or only those that change; `{}` runs the tests with the current
3283
+ * settings. A change to what the index stores (new searchable, facet, filter, sort or location fields,
3284
+ * or normalization) throws a 409: save it first. Not counted as searches. */
3285
+ compareSettings: (settings: Partial<IndexSettings>, options?: CompareOptions) => Promise<SettingsComparison>;
3286
+ /** The index's search tests. */
3287
+ getSearchTests: (signal?: AbortSignal) => Promise<SearchTest[]>;
3288
+ /** Replaces the index's search tests, up to 200; `[]` deletes them. */
3289
+ setSearchTests: (tests: SearchTest[], signal?: AbortSignal) => Promise<SearchTest[]>;
3290
+ /** Waits until no settings rebuild is running; throws if it failed. */
3291
+ waitForSettings: (options?: {
3292
+ timeoutMs?: number;
3293
+ intervalMs?: number;
3294
+ signal?: AbortSignal;
3295
+ }) => Promise<CurrentSettings>;
3296
+ subindex: <S_9 extends {
3297
+ objectID: string;
3298
+ } = JsonRecord>(subindex: string) => {
3299
+ /** Searches the index; the API key needs the `search` scope. Pass `{ visitor }` when searching for
3300
+ * someone, such as a shopper loading a server-rendered page (see Visitor). */
3301
+ search: <R = S_9>(query?: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<SearchResponse<R>>;
3302
+ /** Did you mean: for a search that found nothing, a query that finds something, or null. Takes the
3303
+ * same request (its q, filters, and fields matter). Needs the `didYouMean` setting; not counted as
3304
+ * a search. */
3305
+ suggest: (query: SearchRequest, options?: AbortSignal | RequestOptions) => Promise<DidYouMean | null>;
3306
+ /** Query suggestions: whole searches to offer as a shopper types `q`, the best first; with `q` empty, the
3307
+ * index's popular searches. The API key needs the `search` scope; not counted as searches. `limit`: 1 to
3308
+ * 10, 5 by default. */
3309
+ querySuggestions: (query: {
3310
+ q: string;
3311
+ limit?: number;
3312
+ }, options?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
3313
+ /** The index's popular searches, for an empty search box, with the owner's pinned searches first;
3314
+ * empty until the index has enough searches. The list changes daily. */
3315
+ popularSearches: (options?: {
3316
+ limit?: number;
3317
+ }, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<QuerySuggestion[]>;
3318
+ /** A product's recommendations (the recommendations add-on): products that go with it, and similar products.
3319
+ * The API key needs the `search` scope; not counted as a search. */
3320
+ recommendations: <R = S_9>(objectID: string, options?: RecommendationsRequest, requestOptionsOrSignal?: AbortSignal | RequestOptions) => Promise<RecommendationsResponse<R>>;
3321
+ /** The index's lists: rows of products, such as Popular, and facet fields' values for menus, built ahead
3322
+ * and served from a cache, so reading them isn't counted as searches. Reading needs the `search` scope;
3323
+ * setting them up needs `write`. */
3324
+ /** Merchandising (0.23.0): category pages and searches arranged as the dashboard's Merchandising page does:
3325
+ * the products placed first, hidden products, a banner, and when. Saved as the page's rule within seconds,
3326
+ * keeping anything else the rule does. Reading needs the `search` or `write` scope; changing, `write`. */
3327
+ merchandising: {
3328
+ /** Every arranged category page and search. */
3329
+ list: (signal?: AbortSignal) => Promise<Arrangement[]>;
3330
+ /** One page's or search's arrangement; status "none" when nothing is arranged. */
3331
+ get: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
3332
+ /** Changes one: `order` up to 20 objectIDs placed first, `hidden` up to 100, `banner` ({ image, link?, title?,
3333
+ * position? } or null), `active` ({ from?, until? } or null), `enabled`. Fields left out stay as they are. */
3334
+ set: (target: MerchandisingTarget, change: ArrangementChange, signal?: AbortSignal) => Promise<Arrangement>;
3335
+ /** Stops arranging one: its order, hidden products and banner go; the rule's other actions stay. */
3336
+ remove: (target: MerchandisingTarget, signal?: AbortSignal) => Promise<Arrangement>;
3337
+ };
3338
+ /** Images for the index's banners, hosted by Findlane at https://images.findlane.dev (0.23.0): JPEG, PNG,
3339
+ * WebP or AVIF, up to 2 MB each, 50 images and 100 MB an index. An image no rule shows is deleted a week
3340
+ * later. Uploading and deleting need the `write` scope. */
3341
+ images: {
3342
+ list: (signal?: AbortSignal) => Promise<ImageLibrary>;
3343
+ /** Uploads an image's bytes; the same image again gives the same URL. */
3344
+ upload: (image: Blob | ArrayBuffer | Uint8Array, options?: {
3345
+ contentType?: string;
3346
+ signal?: AbortSignal;
3347
+ }) => Promise<UploadedImage & {
3348
+ error?: string;
3349
+ }>;
3350
+ /** Uploads the image at an https address, which Findlane fetches. */
3351
+ uploadFromUrl: (url: string, signal?: AbortSignal) => Promise<UploadedImage>;
3352
+ /** Deletes an image by its key; refused (409) while a rule's banner shows it. */
3353
+ delete: (key: string, signal?: AbortSignal) => Promise<{
3354
+ deleted: true;
3355
+ }>;
3356
+ };
3357
+ /** The index's product feed (0.24.0): a store's Google or Meta product feed, or a JSON file of records, read on
3358
+ * a schedule (hourly, every 6 hours, or daily), replacing the index's records with only what changed. Reading
3359
+ * needs the `search` or `write` scope; the rest, `write`. */
3360
+ feed: {
3361
+ /** The feed and its last run, or null. */
3362
+ get: (signal?: AbortSignal) => Promise<ProductFeed | null>;
3363
+ /** Connects a feed or changes its setup; a new address, sign-in or variants setting reads it now. */
3364
+ set: (setup: FeedSetup, signal?: AbortSignal) => Promise<ProductFeed>;
3365
+ /** Disconnects it; the index keeps its records. */
3366
+ remove: (signal?: AbortSignal) => Promise<void>;
3367
+ /** Reads a feed's first 2,000 items without saving anything; without a url, the connected feed's. */
3368
+ check: (setup?: Pick<FeedSetup, "url" | "username" | "password" | "variants">, signal?: AbortSignal) => Promise<FeedCheck>;
3369
+ /** Reads it now, in full, in the background; `runs` shows how it went. */
3370
+ run: (signal?: AbortSignal) => Promise<FeedRun>;
3371
+ /** The last 20 runs, newest first. */
3372
+ runs: (signal?: AbortSignal) => Promise<FeedRun[]>;
3373
+ /** Imports a held run's copy of the feed as it is, without the checks that held it. */
3374
+ importHeld: (runId: string, signal?: AbortSignal) => Promise<FeedRun>;
3375
+ };
3376
+ lists: {
3377
+ /** One list by its ID; throws a FindlaneError with status 404 when there's none. `limit` shows fewer. */
3378
+ get: <R = S_9>(id: string, options?: {
3379
+ limit?: number;
3380
+ signal?: AbortSignal;
3381
+ }) => Promise<List<R>>;
3382
+ /** Several lists (up to 10) in the order asked, leaving out IDs without a list; without IDs, all of them. */
3383
+ getMany: <R = S_9>(ids?: string[], options?: {
3384
+ limit?: number;
3385
+ signal?: AbortSignal;
3386
+ }) => Promise<List<R>[]>;
3387
+ /** How the index's lists are set up, and their last build. */
3388
+ settings: (signal?: AbortSignal) => Promise<ListSettings>;
3389
+ /** Creates or changes a list and builds it; one whose filters, sort or field don't work on the index is
3390
+ * refused with why (400), and a new list past the plan's lists per index too (402). */
3391
+ save: (id: string, list: ListDefinition, signal?: AbortSignal) => Promise<ListSettings>;
3392
+ delete: (id: string, signal?: AbortSignal) => Promise<ListSettings>;
3393
+ /** Puts the lists in this order: every list's ID once. */
3394
+ order: (ids: string[], signal?: AbortSignal) => Promise<ListSettings>;
3395
+ /** Builds the lists again now, rather than within the minute they take to follow the index; once a minute. */
3396
+ refresh: (signal?: AbortSignal) => Promise<ListSettings>;
3397
+ /** What a list would hold, built without saving it. */
3398
+ preview: <R = S_9>(list: ListDefinition, signal?: AbortSignal) => Promise<{
3399
+ list: List<R>;
3400
+ tookMs: number;
3401
+ }>;
3402
+ };
3403
+ /** Events for the index's Events page and Bought together; the API key needs the `events` or `write`
3404
+ * scope. Orders count once each, however often they're sent. */
3405
+ events: {
3406
+ /** Sends events, 200 a request. One bad event doesn't refuse the rest: they're in `rejected`. Pass
3407
+ * `{ visitorId, visitId }` to link a shopper's events (see EventOptions). */
3408
+ send: (events: ServerEvent[], options?: AbortSignal | EventOptions) => Promise<EventsResult>;
3409
+ /** Sends past orders, up to 400 days old, from a list or an async iterable (such as a database
3410
+ * cursor), 200 a request. */
3411
+ importOrders: (orders: Iterable<Order> | AsyncIterable<Order>, signal?: AbortSignal) => Promise<EventsResult>;
3412
+ /** Takes a cancelled or refunded order out of Bought together. */
3413
+ cancelOrder: (orderID: string, signal?: AbortSignal) => Promise<EventsResult>;
3414
+ /** Deletes the events sent with these visitor or visit IDs, for shoppers who asked: Findlane does it
3415
+ * within a week. 1,000 IDs a request. */
3416
+ forget: (ids: string[], signal?: AbortSignal) => Promise<{
3417
+ forgotten: number;
3418
+ }>;
3419
+ /** A route on your own domain for the browser SDK's events (its `eventsUrl` option): ad blockers
3420
+ * block beacons to other sites, not to the page's own. Give it the browser's POST request (Next.js
3421
+ * route handlers, Workers, Hono, Bun, Deno); it finds the visitor's address in the headers
3422
+ * Cloudflare, Vercel and most proxies set. Where a visitor reaches your server directly, they can
3423
+ * set those too, so pass `{ ip }`. The API key needs the `events` or `write` scope. */
3424
+ proxy: (request: Request, visitor?: Partial<RelayedVisitor>) => Promise<Response>;
3425
+ /** `proxy` for servers without Fetch API requests, such as Express: the request's body as text,
3426
+ * and its visitor. Answers with the API's response. */
3427
+ relay: (body: string, visitor: RelayedVisitor, signal?: AbortSignal) => Promise<Response>;
3428
+ };
3429
+ /** The index's search analytics. The API key needs the `analytics` scope, and works only from a server:
3430
+ * requests from web pages are refused. */
3431
+ analytics: {
3432
+ /** Searches, searches without results and response times, beside the same span before, and a series per
3433
+ * hour (up to 7 days, by default) or day. */
3434
+ searches: (options?: AnalyticsOptions & {
3435
+ interval?: "hour" | "day";
3436
+ }) => Promise<SearchesReport>;
3437
+ /** Queries, the most searched first: `top` (by default) with their clicks, `noResults`, or `noClicks`, which
3438
+ * found something nobody clicked. `limit` is 1 to 1,000, 100 by default. */
3439
+ queries: <L extends keyof QueryLists = "top">(options?: AnalyticsOptions & {
3440
+ list?: L | undefined;
3441
+ limit?: number;
3442
+ }) => Promise<QueriesReport<L>>;
3443
+ /** The filter fields and sorts searches used. */
3444
+ filters: (options?: AnalyticsOptions) => Promise<FiltersReport>;
3445
+ /** Events of each type over time and by source, orders stored, and refused and bot events. */
3446
+ events: (options?: AnalyticsOptions & {
3447
+ interval?: "hour" | "day";
3448
+ }) => Promise<EventsReport>;
3449
+ /** The most viewed, most added to carts and most ordered products, with titles and images, and those
3450
+ * viewed but rarely bought. Exact, from every event kept (13 months, from 9 October 2026). */
3451
+ products: (options?: AnalyticsOptions) => Promise<ProductListsReport>;
3452
+ /** Every product with events or orders in the window, the most viewed first, up to 50,000: views,
3453
+ * viewers, clicks, add-to-carts and orders. Exact, like `products`. */
3454
+ productCounts: (options?: AnalyticsOptions) => Promise<ProductCountsReport>;
3455
+ /** One product's views, viewers, clicks, add-to-carts and orders per hour or day, the queries it was
3456
+ * clicked from, and its clicks in recommendations. Fast, for a product page in an admin: views and
3457
+ * clicks are estimates when `sampled`, and an add-to-cart of several products counts toward the first. */
3458
+ product: (objectID: string, options?: AnalyticsOptions & {
3459
+ interval?: "hour" | "day";
3460
+ }) => Promise<ProductReport>;
3461
+ /** Revenue from search: orders and add-to-carts of products found through search, per query and per
3462
+ * product (0.20.0). */
3463
+ revenue: (options?: Omit<AnalyticsOptions, "source">) => Promise<RevenueReport>;
3464
+ /** Sales by filter value: each facet value's clicks, add-to-carts, orders and revenue (0.26.0). */
3465
+ filterSales: (options?: Omit<AnalyticsOptions, "source">) => Promise<FilterSalesReport>;
3466
+ /** Each banner's shown (shoppers' searches that showed it, cache answers included) and clicks, by its rule,
3467
+ * over the last 7, 30 (by default) or 90 days (0.23.0). */
3468
+ banners: (options?: {
3469
+ range?: "7d" | "30d" | "90d";
3470
+ signal?: AbortSignal;
3471
+ }) => Promise<BannerStatsReport>;
3472
+ };
3473
+ upsert: (records: S_9[], signal?: AbortSignal) => Promise<WriteReceipt>;
3474
+ getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_9>>;
3475
+ upsertOne: (record: S_9, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
3476
+ deleteOne: (objectID: string, options: ConditionalWriteOptions) => Promise<WriteReceipt>;
3477
+ replaceAll: (records: S_9[], signal?: AbortSignal) => Promise<WriteReceipt>;
3478
+ beginReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
3479
+ uploadReplacementBatch: (stageId: string, batchId: string, records: S_9[], signal?: AbortSignal) => Promise<ReplacementStage>;
3480
+ commitReplacement: (stageId: string, expectedBatches: number, expectedRecords: number, signal?: AbortSignal) => Promise<WriteReceipt>;
3481
+ abortReplacement: (stageId: string, signal?: AbortSignal) => Promise<ReplacementStage>;
3482
+ replaceAllStaged: (records: Iterable<S_9> | AsyncIterable<S_9>, options?: StagedReplaceOptions) => Promise<WriteReceipt>;
3483
+ delete: (objectID: string, signal?: AbortSignal) => Promise<WriteReceipt>;
3484
+ getSettings: (signal?: AbortSignal) => Promise<CurrentSettings>;
3485
+ replaceSettings: (settings: IndexSettings, signal?: AbortSignal) => Promise<SavedSettings>;
3486
+ /** Compares settings with the index's own without saving them: its search tests, `queries`, and its 100
3487
+ * most searched queries of the last 30 days, each searched with both, for up to 20 seconds. Takes the
3488
+ * settings `replaceSettings` does, or only those that change; `{}` runs the tests with the current
3489
+ * settings. A change to what the index stores (new searchable, facet, filter, sort or location fields,
3490
+ * or normalization) throws a 409: save it first. Not counted as searches. */
3491
+ compareSettings: (settings: Partial<IndexSettings>, options?: CompareOptions) => Promise<SettingsComparison>;
3492
+ /** The index's search tests. */
3493
+ getSearchTests: (signal?: AbortSignal) => Promise<SearchTest[]>;
3494
+ /** Replaces the index's search tests, up to 200; `[]` deletes them. */
3495
+ setSearchTests: (tests: SearchTest[], signal?: AbortSignal) => Promise<SearchTest[]>;
3496
+ /** Waits until no settings rebuild is running; throws if it failed. */
3497
+ waitForSettings: (options?: {
3498
+ timeoutMs?: number;
3499
+ intervalMs?: number;
3500
+ signal?: AbortSignal;
3501
+ }) => Promise<CurrentSettings>;
3502
+ subindex: <S_10 extends {
3503
+ objectID: string;
3504
+ } = JsonRecord>(subindex: string) => /*elided*/ any;
3505
+ /** The index's subindexes, with their records (0.25.0). Owners make them in the dashboard. */
3506
+ listSubindexes: (signal?: AbortSignal) => Promise<Subindex[]>;
3507
+ getPublicSearchAccess: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3508
+ setPublicSearchPolicy: (policy: PublicSearchPolicy, signal?: AbortSignal) => Promise<PublicSearchAccess>;
3509
+ usePublicIndexDefaults: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3510
+ getIndexingStatus: (signal?: AbortSignal) => Promise<IndexingStatus>;
3511
+ waitUntilIndexed: (revision: number, options?: {
3512
+ timeoutMs?: number;
3513
+ intervalMs?: number;
3514
+ signal?: AbortSignal;
3515
+ }) => Promise<IndexingStatus>;
3516
+ };
3517
+ /** The index's subindexes, with their records (0.25.0). Owners make them in the dashboard. */
3518
+ listSubindexes: (signal?: AbortSignal) => Promise<Subindex[]>;
3519
+ getPublicSearchAccess: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3520
+ setPublicSearchPolicy: (policy: PublicSearchPolicy, signal?: AbortSignal) => Promise<PublicSearchAccess>;
3521
+ usePublicIndexDefaults: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3522
+ getIndexingStatus: (signal?: AbortSignal) => Promise<IndexingStatus>;
3523
+ waitUntilIndexed: (revision: number, options?: {
3524
+ timeoutMs?: number;
3525
+ intervalMs?: number;
3526
+ signal?: AbortSignal;
3527
+ }) => Promise<IndexingStatus>;
3528
+ };
3529
+ /** The index's subindexes, with their records (0.25.0). Owners make them in the dashboard. */
3530
+ listSubindexes: (signal?: AbortSignal) => Promise<Subindex[]>;
3531
+ getPublicSearchAccess: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3532
+ setPublicSearchPolicy: (policy: PublicSearchPolicy, signal?: AbortSignal) => Promise<PublicSearchAccess>;
3533
+ usePublicIndexDefaults: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3534
+ getIndexingStatus: (signal?: AbortSignal) => Promise<IndexingStatus>;
3535
+ waitUntilIndexed: (revision: number, options?: {
3536
+ timeoutMs?: number;
3537
+ intervalMs?: number;
3538
+ signal?: AbortSignal;
3539
+ }) => Promise<IndexingStatus>;
3540
+ };
3541
+ /** The index's subindexes, with their records (0.25.0). Owners make them in the dashboard. */
3542
+ listSubindexes: (signal?: AbortSignal) => Promise<Subindex[]>;
3543
+ getPublicSearchAccess: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3544
+ setPublicSearchPolicy: (policy: PublicSearchPolicy, signal?: AbortSignal) => Promise<PublicSearchAccess>;
3545
+ usePublicIndexDefaults: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3546
+ getIndexingStatus: (signal?: AbortSignal) => Promise<IndexingStatus>;
3547
+ waitUntilIndexed: (revision: number, options?: {
3548
+ timeoutMs?: number;
3549
+ intervalMs?: number;
3550
+ signal?: AbortSignal;
3551
+ }) => Promise<IndexingStatus>;
3552
+ };
3553
+ /** The index's subindexes, with their records (0.25.0). Owners make them in the dashboard. */
3554
+ listSubindexes: (signal?: AbortSignal) => Promise<Subindex[]>;
3555
+ getPublicSearchAccess: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3556
+ setPublicSearchPolicy: (policy: PublicSearchPolicy, signal?: AbortSignal) => Promise<PublicSearchAccess>;
3557
+ usePublicIndexDefaults: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3558
+ getIndexingStatus: (signal?: AbortSignal) => Promise<IndexingStatus>;
3559
+ waitUntilIndexed: (revision: number, options?: {
3560
+ timeoutMs?: number;
3561
+ intervalMs?: number;
3562
+ signal?: AbortSignal;
3563
+ }) => Promise<IndexingStatus>;
3564
+ };
3565
+ /** The index's subindexes, with their records (0.25.0). Owners make them in the dashboard. */
3566
+ listSubindexes: (signal?: AbortSignal) => Promise<Subindex[]>;
3567
+ getPublicSearchAccess: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3568
+ setPublicSearchPolicy: (policy: PublicSearchPolicy, signal?: AbortSignal) => Promise<PublicSearchAccess>;
3569
+ usePublicIndexDefaults: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3570
+ getIndexingStatus: (signal?: AbortSignal) => Promise<IndexingStatus>;
3571
+ waitUntilIndexed: (revision: number, options?: {
3572
+ timeoutMs?: number;
3573
+ intervalMs?: number;
3574
+ signal?: AbortSignal;
3575
+ }) => Promise<IndexingStatus>;
3576
+ };
3577
+ /** The index's subindexes, with their records (0.25.0). Owners make them in the dashboard. */
3578
+ listSubindexes: (signal?: AbortSignal) => Promise<Subindex[]>;
3579
+ getPublicSearchAccess: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3580
+ setPublicSearchPolicy: (policy: PublicSearchPolicy, signal?: AbortSignal) => Promise<PublicSearchAccess>;
3581
+ usePublicIndexDefaults: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3582
+ getIndexingStatus: (signal?: AbortSignal) => Promise<IndexingStatus>;
3583
+ waitUntilIndexed: (revision: number, options?: {
3584
+ timeoutMs?: number;
3585
+ intervalMs?: number;
3586
+ signal?: AbortSignal;
3587
+ }) => Promise<IndexingStatus>;
3588
+ };
3589
+ /** The index's subindexes, with their records (0.25.0). Owners make them in the dashboard. */
3590
+ listSubindexes: (signal?: AbortSignal) => Promise<Subindex[]>;
3591
+ getPublicSearchAccess: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3592
+ setPublicSearchPolicy: (policy: PublicSearchPolicy, signal?: AbortSignal) => Promise<PublicSearchAccess>;
3593
+ usePublicIndexDefaults: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3594
+ getIndexingStatus: (signal?: AbortSignal) => Promise<IndexingStatus>;
3595
+ waitUntilIndexed: (revision: number, options?: {
3596
+ timeoutMs?: number;
3597
+ intervalMs?: number;
3598
+ signal?: AbortSignal;
3599
+ }) => Promise<IndexingStatus>;
3600
+ };
3601
+ /** The index's subindexes, with their records (0.25.0). Owners make them in the dashboard. */
3602
+ listSubindexes: (signal?: AbortSignal) => Promise<Subindex[]>;
3603
+ getPublicSearchAccess: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3604
+ setPublicSearchPolicy: (policy: PublicSearchPolicy, signal?: AbortSignal) => Promise<PublicSearchAccess>;
3605
+ usePublicIndexDefaults: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3606
+ getIndexingStatus: (signal?: AbortSignal) => Promise<IndexingStatus>;
3607
+ waitUntilIndexed: (revision: number, options?: {
3608
+ timeoutMs?: number;
3609
+ intervalMs?: number;
3610
+ signal?: AbortSignal;
3611
+ }) => Promise<IndexingStatus>;
3612
+ };
3613
+ /** The index's subindexes, with their records (0.25.0). Owners make them in the dashboard. */
3614
+ listSubindexes: (signal?: AbortSignal) => Promise<Subindex[]>;
3615
+ getPublicSearchAccess: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3616
+ setPublicSearchPolicy: (policy: PublicSearchPolicy, signal?: AbortSignal) => Promise<PublicSearchAccess>;
3617
+ usePublicIndexDefaults: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
3618
+ getIndexingStatus: (signal?: AbortSignal) => Promise<IndexingStatus>;
3619
+ waitUntilIndexed: (revision: number, options?: {
3620
+ timeoutMs?: number;
3621
+ intervalMs?: number;
3622
+ signal?: AbortSignal;
3623
+ }) => Promise<IndexingStatus>;
3624
+ };
3625
+ /** The index's subindexes, with their records (0.25.0). Owners make them in the dashboard. */
3626
+ listSubindexes: (signal?: AbortSignal) => Promise<Subindex[]>;
1369
3627
  getPublicSearchAccess: (signal?: AbortSignal) => Promise<PublicSearchAccess>;
1370
3628
  setPublicSearchPolicy: (policy: PublicSearchPolicy, signal?: AbortSignal) => Promise<PublicSearchAccess>;
1371
3629
  usePublicIndexDefaults: (signal?: AbortSignal) => Promise<PublicSearchAccess>;