@findlane/server 0.30.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -60,7 +60,8 @@ const results = await products.search({ q }, { visitor: { ip: req.ip, userAgent:
60
60
  | `getSearchTests()`, `setSearchTests(tests)` | Searches that must keep working, saved apart from the settings, such as a record in the top 3 or at least 100 results. `compareSettings` checks them. |
61
61
  | `getIndexingStatus()`, `waitUntilIndexed(revision)` | Writes return an accepted revision and are searchable when accepted, so `waitUntilIndexed` returns at once. |
62
62
  | `getPublicSearchAccess()`, `setPublicSearchPolicy(policy)`, `usePublicIndexDefaults()` | Restrict what browser search may read and query. |
63
- | `events.send(events, { visitorId, visitId }?)`, `events.importOrders(orders)`, `events.cancelOrder(orderID)` | Orders and other events for the index's Events page and Bought together; the key needs the `events` or `write` scope. Your own anonymous visitor IDs link a shopper's events, when the index takes them. |
63
+ | `events.send(events, { visitorId, visitId, abTest }?)`, `events.importOrders(orders)`, `events.cancelOrder(orderID)` | Orders and other events for the index's Events page and Bought together; the key needs the `events` or `write` scope. Your own anonymous visitor IDs link a shopper's events, when the index takes them. `abTest`, from the shopper's search answer, puts them in their A/B test group. |
64
+ | `abTests.get()`, `abTests.estimate({ share })`, `analytics.abTest()` | The index's A/B tests of its settings, with their results, and what a test would take. Owners start and end them in the dashboard. |
64
65
  | `events.forget(ids)` | Deletes the events sent with these visitor or visit IDs, within a week. |
65
66
  | `events.proxy(request)`, `events.relay(body, visitor)` | A route on your own site for the browser SDK's events (its `eventsUrl`), which ad blockers let through. See [Events](https://findlane.dev/docs/events#through-your-own-domain). |
66
67
  | `analytics.searches()`, `.queries({ list, limit })`, `.filters()`, `.events()`, `.products()`, `.productCounts()`, `.product(objectID)` | The index's analytics, for your own admin: searches over time, top queries with their clicks, queries without results or clicks, the filters used, events, and each product's views, add-to-carts and orders. The key needs the `analytics` scope, and works only from a server. See [Analytics](https://findlane.dev/docs/api#analytics). |
package/dist/index.cjs CHANGED
@@ -241,7 +241,8 @@ class SearchServerClient {
241
241
  return jsonResponse(await response.text(), response.status, retryAfter ? { "retry-after": retryAfter } : {});
242
242
  };
243
243
  const sendEvents = async (events, options = {}) => {
244
- const { signal, visitorId, visitId } = options;
244
+ const { signal, visitorId, visitId, abTest } = options;
245
+ const label = abTest === undefined || typeof abTest === "string" ? abTest : `${abTest.id}:${abTest.variant}`;
245
246
  const result = { accepted: 0, rejected: [] };
246
247
  let batch = [];
247
248
  let sent = 0;
@@ -251,6 +252,7 @@ class SearchServerClient {
251
252
  const answer = await postEvents({
252
253
  ...visitorId === undefined ? {} : { visitorId },
253
254
  ...visitId === undefined ? {} : { visitId },
255
+ ...label === undefined ? {} : { abTest: label },
254
256
  events: batch
255
257
  }, signal);
256
258
  result.accepted += answer.accepted ?? 0;
@@ -394,7 +396,12 @@ class SearchServerClient {
394
396
  product: (objectID, options = {}) => report(`products/${encodeURIComponent(objectID)}`, options),
395
397
  revenue: (options = {}) => report("revenue", options),
396
398
  filterSales: (options = {}) => report("filter-sales", options),
397
- banners: (options = {}) => request(`/banners?range=${options.range ?? "30d"}`, "GET", undefined, options.signal)
399
+ banners: (options = {}) => request(`/banners?range=${options.range ?? "30d"}`, "GET", undefined, options.signal),
400
+ abTest: (options = {}) => request("/analytics/ab-test", "GET", undefined, options.signal)
401
+ },
402
+ abTests: {
403
+ get: (signal) => request("/ab-tests", "GET", undefined, signal),
404
+ estimate: (options = {}) => request(`/ab-tests/estimate${options.share === undefined ? "" : `?share=${options.share}`}`, "GET", undefined, options.signal)
398
405
  },
399
406
  upsert: (records, signal) => request("/records", "POST", { records }, signal),
400
407
  getRecord: (objectID, signal) => request(`/records/${encodeURIComponent(objectID)}`, "GET", undefined, signal),
package/dist/index.d.cts CHANGED
@@ -67,6 +67,14 @@ export type IndexSettings = {
67
67
  /** Searches say which words typo tolerance corrected, and `suggest()` offers a corrected query for a
68
68
  * search that finds nothing. Off by default. */
69
69
  didYouMean?: boolean;
70
+ /** Learn from clicks (0.31.0): each search with 10+ clicks in 30 days puts its up to 5 most clicked and
71
+ * bought products first within their rank first group, after rules; learned daily. Off by default. */
72
+ learnedRanking?: boolean;
73
+ /** Searches (as typed, any case) and product IDs that learning from clicks leaves out, applied at once. */
74
+ learnedExclusions?: {
75
+ queries?: string[];
76
+ products?: string[];
77
+ };
70
78
  /** Compound words find each other written as one word or apart, in any language: a query word that the
71
79
  * index's words show is a compound also matches its parts written apart ("sjóræningjabúningur" finds
72
80
  * "Sjóræningja búningur"), and neighbouring query words the word they make ("face paint" finds "facepaint").
@@ -966,6 +974,80 @@ export type EventOptions = {
966
974
  signal?: AbortSignal;
967
975
  visitorId?: string;
968
976
  visitId?: string;
977
+ /** The shopper's group in the index's running A/B test (0.32.0): the `abTest` of the search answer their browser got,
978
+ * as `{ id, variant }` or `"<id>:<variant>"`, which the browser SDK sends with its own events. Your server's events
979
+ * count toward a group only with it, so send one shopper's events a call. A label for a test that ended is ignored. */
980
+ abTest?: AbTestLabel | string;
981
+ };
982
+ /** A shopper's group in an A/B test, as a browser search answer's `abTest` gives it: `a` searched with today's
983
+ * settings, `b` with the change (0.32.0). */
984
+ export type AbTestLabel = {
985
+ id: string;
986
+ variant: "a" | "b";
987
+ };
988
+ /** One measure in an A/B test's results: each group's value per search (a share for `noResults` and `topThree`), and
989
+ * B's change over A (0.1 is 10% more) with its 95% interval. Null where there aren't the searches or days yet. */
990
+ export type AbFigure = {
991
+ a: number | null;
992
+ b: number | null;
993
+ change: number | null;
994
+ low: number | null;
995
+ high: number | null;
996
+ };
997
+ /** An A/B test's results. `decided` once the test has run its days with 1,000 searches in each group; `verdict` is then
998
+ * `b` (the change did better), `a` (worse) or `none` (no clear difference), judged on clicks per search, then carts. */
999
+ export type AbTestResults = {
1000
+ days: number;
1001
+ decided: boolean;
1002
+ verdict: "a" | "b" | "none" | null;
1003
+ searches: {
1004
+ a: number;
1005
+ b: number;
1006
+ };
1007
+ currency: string | null;
1008
+ figures: Record<"noResults" | "clicks" | "topThree" | "carts" | "orders" | "revenue", AbFigure>;
1009
+ perDay: {
1010
+ day: string;
1011
+ searches: {
1012
+ a: number;
1013
+ b: number;
1014
+ };
1015
+ clicks: {
1016
+ a: number;
1017
+ b: number;
1018
+ };
1019
+ }[];
1020
+ computedAt: string;
1021
+ };
1022
+ /** An A/B test of an index's settings (0.32.0): group B's `share` of shoppers, the settings it `changes` and their values
1023
+ * in `patch` (null where B goes without one), an A/A test (`aa`) changes none. `outcome` once ended: `a` kept today's
1024
+ * settings, `b` applied the change, `guard` ended early because the change found nothing far more often. */
1025
+ export type AbTest = {
1026
+ id: string;
1027
+ name: string;
1028
+ share: number;
1029
+ changes: string[];
1030
+ aa: boolean;
1031
+ patch: Record<string, unknown>;
1032
+ startedAt: string;
1033
+ endsAt: string;
1034
+ endedAt: string | null;
1035
+ outcome: "a" | "b" | "guard" | null;
1036
+ results: AbTestResults | null;
1037
+ };
1038
+ /** An index's A/B tests: the running one with its results so far, or null, and up to 10 that ended, newest first. */
1039
+ export type AbTests = {
1040
+ running: AbTest | null;
1041
+ ended: AbTest[];
1042
+ };
1043
+ /** What a test at a share would take: the days to find a 10% change in clicks per search (null with too few
1044
+ * searches), from the index's searches and clicks per search over the last 14 days, and the share of searches more
1045
+ * that would miss the cache. */
1046
+ export type AbTestEstimate = {
1047
+ searchesPerDay: number;
1048
+ clicksPerSearch: number;
1049
+ days: number | null;
1050
+ extraMisses: number;
969
1051
  };
970
1052
  /** An analytics window, in UTC: `range` (7d by default), or `from` and `to`. A date as `from` is the start of
971
1053
  * that day, and as `to` includes the whole day; `to` is now by default. Analytics go back 90 days: a window
@@ -1456,6 +1538,29 @@ export declare class SearchServerClient {
1456
1538
  range?: "7d" | "30d" | "90d";
1457
1539
  signal?: AbortSignal;
1458
1540
  }) => Promise<BannerStatsReport>;
1541
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
1542
+ abTest: (options?: {
1543
+ signal?: AbortSignal;
1544
+ }) => Promise<AbTests & {
1545
+ index: string;
1546
+ }>;
1547
+ };
1548
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
1549
+ abTests: {
1550
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
1551
+ get: (signal?: AbortSignal) => Promise<AbTests & {
1552
+ shares: number[];
1553
+ days: {
1554
+ min: number;
1555
+ default: number;
1556
+ max: number;
1557
+ };
1558
+ }>;
1559
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
1560
+ estimate: (options?: {
1561
+ share?: number;
1562
+ signal?: AbortSignal;
1563
+ }) => Promise<AbTestEstimate>;
1459
1564
  };
1460
1565
  upsert: (records: T[], signal?: AbortSignal) => Promise<WriteReceipt>;
1461
1566
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<T>>;
@@ -1664,6 +1769,29 @@ export declare class SearchServerClient {
1664
1769
  range?: "7d" | "30d" | "90d";
1665
1770
  signal?: AbortSignal;
1666
1771
  }) => Promise<BannerStatsReport>;
1772
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
1773
+ abTest: (options?: {
1774
+ signal?: AbortSignal;
1775
+ }) => Promise<AbTests & {
1776
+ index: string;
1777
+ }>;
1778
+ };
1779
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
1780
+ abTests: {
1781
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
1782
+ get: (signal?: AbortSignal) => Promise<AbTests & {
1783
+ shares: number[];
1784
+ days: {
1785
+ min: number;
1786
+ default: number;
1787
+ max: number;
1788
+ };
1789
+ }>;
1790
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
1791
+ estimate: (options?: {
1792
+ share?: number;
1793
+ signal?: AbortSignal;
1794
+ }) => Promise<AbTestEstimate>;
1667
1795
  };
1668
1796
  upsert: (records: S[], signal?: AbortSignal) => Promise<WriteReceipt>;
1669
1797
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S>>;
@@ -1870,6 +1998,29 @@ export declare class SearchServerClient {
1870
1998
  range?: "7d" | "30d" | "90d";
1871
1999
  signal?: AbortSignal;
1872
2000
  }) => Promise<BannerStatsReport>;
2001
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
2002
+ abTest: (options?: {
2003
+ signal?: AbortSignal;
2004
+ }) => Promise<AbTests & {
2005
+ index: string;
2006
+ }>;
2007
+ };
2008
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
2009
+ abTests: {
2010
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
2011
+ get: (signal?: AbortSignal) => Promise<AbTests & {
2012
+ shares: number[];
2013
+ days: {
2014
+ min: number;
2015
+ default: number;
2016
+ max: number;
2017
+ };
2018
+ }>;
2019
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
2020
+ estimate: (options?: {
2021
+ share?: number;
2022
+ signal?: AbortSignal;
2023
+ }) => Promise<AbTestEstimate>;
1873
2024
  };
1874
2025
  upsert: (records: S_1[], signal?: AbortSignal) => Promise<WriteReceipt>;
1875
2026
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_1>>;
@@ -2076,6 +2227,29 @@ export declare class SearchServerClient {
2076
2227
  range?: "7d" | "30d" | "90d";
2077
2228
  signal?: AbortSignal;
2078
2229
  }) => Promise<BannerStatsReport>;
2230
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
2231
+ abTest: (options?: {
2232
+ signal?: AbortSignal;
2233
+ }) => Promise<AbTests & {
2234
+ index: string;
2235
+ }>;
2236
+ };
2237
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
2238
+ abTests: {
2239
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
2240
+ get: (signal?: AbortSignal) => Promise<AbTests & {
2241
+ shares: number[];
2242
+ days: {
2243
+ min: number;
2244
+ default: number;
2245
+ max: number;
2246
+ };
2247
+ }>;
2248
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
2249
+ estimate: (options?: {
2250
+ share?: number;
2251
+ signal?: AbortSignal;
2252
+ }) => Promise<AbTestEstimate>;
2079
2253
  };
2080
2254
  upsert: (records: S_2[], signal?: AbortSignal) => Promise<WriteReceipt>;
2081
2255
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_2>>;
@@ -2282,6 +2456,29 @@ export declare class SearchServerClient {
2282
2456
  range?: "7d" | "30d" | "90d";
2283
2457
  signal?: AbortSignal;
2284
2458
  }) => Promise<BannerStatsReport>;
2459
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
2460
+ abTest: (options?: {
2461
+ signal?: AbortSignal;
2462
+ }) => Promise<AbTests & {
2463
+ index: string;
2464
+ }>;
2465
+ };
2466
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
2467
+ abTests: {
2468
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
2469
+ get: (signal?: AbortSignal) => Promise<AbTests & {
2470
+ shares: number[];
2471
+ days: {
2472
+ min: number;
2473
+ default: number;
2474
+ max: number;
2475
+ };
2476
+ }>;
2477
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
2478
+ estimate: (options?: {
2479
+ share?: number;
2480
+ signal?: AbortSignal;
2481
+ }) => Promise<AbTestEstimate>;
2285
2482
  };
2286
2483
  upsert: (records: S_3[], signal?: AbortSignal) => Promise<WriteReceipt>;
2287
2484
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_3>>;
@@ -2488,6 +2685,29 @@ export declare class SearchServerClient {
2488
2685
  range?: "7d" | "30d" | "90d";
2489
2686
  signal?: AbortSignal;
2490
2687
  }) => Promise<BannerStatsReport>;
2688
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
2689
+ abTest: (options?: {
2690
+ signal?: AbortSignal;
2691
+ }) => Promise<AbTests & {
2692
+ index: string;
2693
+ }>;
2694
+ };
2695
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
2696
+ abTests: {
2697
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
2698
+ get: (signal?: AbortSignal) => Promise<AbTests & {
2699
+ shares: number[];
2700
+ days: {
2701
+ min: number;
2702
+ default: number;
2703
+ max: number;
2704
+ };
2705
+ }>;
2706
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
2707
+ estimate: (options?: {
2708
+ share?: number;
2709
+ signal?: AbortSignal;
2710
+ }) => Promise<AbTestEstimate>;
2491
2711
  };
2492
2712
  upsert: (records: S_4[], signal?: AbortSignal) => Promise<WriteReceipt>;
2493
2713
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_4>>;
@@ -2694,6 +2914,29 @@ export declare class SearchServerClient {
2694
2914
  range?: "7d" | "30d" | "90d";
2695
2915
  signal?: AbortSignal;
2696
2916
  }) => Promise<BannerStatsReport>;
2917
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
2918
+ abTest: (options?: {
2919
+ signal?: AbortSignal;
2920
+ }) => Promise<AbTests & {
2921
+ index: string;
2922
+ }>;
2923
+ };
2924
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
2925
+ abTests: {
2926
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
2927
+ get: (signal?: AbortSignal) => Promise<AbTests & {
2928
+ shares: number[];
2929
+ days: {
2930
+ min: number;
2931
+ default: number;
2932
+ max: number;
2933
+ };
2934
+ }>;
2935
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
2936
+ estimate: (options?: {
2937
+ share?: number;
2938
+ signal?: AbortSignal;
2939
+ }) => Promise<AbTestEstimate>;
2697
2940
  };
2698
2941
  upsert: (records: S_5[], signal?: AbortSignal) => Promise<WriteReceipt>;
2699
2942
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_5>>;
@@ -2900,6 +3143,29 @@ export declare class SearchServerClient {
2900
3143
  range?: "7d" | "30d" | "90d";
2901
3144
  signal?: AbortSignal;
2902
3145
  }) => Promise<BannerStatsReport>;
3146
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
3147
+ abTest: (options?: {
3148
+ signal?: AbortSignal;
3149
+ }) => Promise<AbTests & {
3150
+ index: string;
3151
+ }>;
3152
+ };
3153
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
3154
+ abTests: {
3155
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
3156
+ get: (signal?: AbortSignal) => Promise<AbTests & {
3157
+ shares: number[];
3158
+ days: {
3159
+ min: number;
3160
+ default: number;
3161
+ max: number;
3162
+ };
3163
+ }>;
3164
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
3165
+ estimate: (options?: {
3166
+ share?: number;
3167
+ signal?: AbortSignal;
3168
+ }) => Promise<AbTestEstimate>;
2903
3169
  };
2904
3170
  upsert: (records: S_6[], signal?: AbortSignal) => Promise<WriteReceipt>;
2905
3171
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_6>>;
@@ -3106,6 +3372,29 @@ export declare class SearchServerClient {
3106
3372
  range?: "7d" | "30d" | "90d";
3107
3373
  signal?: AbortSignal;
3108
3374
  }) => Promise<BannerStatsReport>;
3375
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
3376
+ abTest: (options?: {
3377
+ signal?: AbortSignal;
3378
+ }) => Promise<AbTests & {
3379
+ index: string;
3380
+ }>;
3381
+ };
3382
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
3383
+ abTests: {
3384
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
3385
+ get: (signal?: AbortSignal) => Promise<AbTests & {
3386
+ shares: number[];
3387
+ days: {
3388
+ min: number;
3389
+ default: number;
3390
+ max: number;
3391
+ };
3392
+ }>;
3393
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
3394
+ estimate: (options?: {
3395
+ share?: number;
3396
+ signal?: AbortSignal;
3397
+ }) => Promise<AbTestEstimate>;
3109
3398
  };
3110
3399
  upsert: (records: S_7[], signal?: AbortSignal) => Promise<WriteReceipt>;
3111
3400
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_7>>;
@@ -3312,6 +3601,29 @@ export declare class SearchServerClient {
3312
3601
  range?: "7d" | "30d" | "90d";
3313
3602
  signal?: AbortSignal;
3314
3603
  }) => Promise<BannerStatsReport>;
3604
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
3605
+ abTest: (options?: {
3606
+ signal?: AbortSignal;
3607
+ }) => Promise<AbTests & {
3608
+ index: string;
3609
+ }>;
3610
+ };
3611
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
3612
+ abTests: {
3613
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
3614
+ get: (signal?: AbortSignal) => Promise<AbTests & {
3615
+ shares: number[];
3616
+ days: {
3617
+ min: number;
3618
+ default: number;
3619
+ max: number;
3620
+ };
3621
+ }>;
3622
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
3623
+ estimate: (options?: {
3624
+ share?: number;
3625
+ signal?: AbortSignal;
3626
+ }) => Promise<AbTestEstimate>;
3315
3627
  };
3316
3628
  upsert: (records: S_8[], signal?: AbortSignal) => Promise<WriteReceipt>;
3317
3629
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_8>>;
@@ -3518,6 +3830,29 @@ export declare class SearchServerClient {
3518
3830
  range?: "7d" | "30d" | "90d";
3519
3831
  signal?: AbortSignal;
3520
3832
  }) => Promise<BannerStatsReport>;
3833
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
3834
+ abTest: (options?: {
3835
+ signal?: AbortSignal;
3836
+ }) => Promise<AbTests & {
3837
+ index: string;
3838
+ }>;
3839
+ };
3840
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
3841
+ abTests: {
3842
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
3843
+ get: (signal?: AbortSignal) => Promise<AbTests & {
3844
+ shares: number[];
3845
+ days: {
3846
+ min: number;
3847
+ default: number;
3848
+ max: number;
3849
+ };
3850
+ }>;
3851
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
3852
+ estimate: (options?: {
3853
+ share?: number;
3854
+ signal?: AbortSignal;
3855
+ }) => Promise<AbTestEstimate>;
3521
3856
  };
3522
3857
  upsert: (records: S_9[], signal?: AbortSignal) => Promise<WriteReceipt>;
3523
3858
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_9>>;
package/dist/index.d.ts CHANGED
@@ -67,6 +67,14 @@ export type IndexSettings = {
67
67
  /** Searches say which words typo tolerance corrected, and `suggest()` offers a corrected query for a
68
68
  * search that finds nothing. Off by default. */
69
69
  didYouMean?: boolean;
70
+ /** Learn from clicks (0.31.0): each search with 10+ clicks in 30 days puts its up to 5 most clicked and
71
+ * bought products first within their rank first group, after rules; learned daily. Off by default. */
72
+ learnedRanking?: boolean;
73
+ /** Searches (as typed, any case) and product IDs that learning from clicks leaves out, applied at once. */
74
+ learnedExclusions?: {
75
+ queries?: string[];
76
+ products?: string[];
77
+ };
70
78
  /** Compound words find each other written as one word or apart, in any language: a query word that the
71
79
  * index's words show is a compound also matches its parts written apart ("sjóræningjabúningur" finds
72
80
  * "Sjóræningja búningur"), and neighbouring query words the word they make ("face paint" finds "facepaint").
@@ -966,6 +974,80 @@ export type EventOptions = {
966
974
  signal?: AbortSignal;
967
975
  visitorId?: string;
968
976
  visitId?: string;
977
+ /** The shopper's group in the index's running A/B test (0.32.0): the `abTest` of the search answer their browser got,
978
+ * as `{ id, variant }` or `"<id>:<variant>"`, which the browser SDK sends with its own events. Your server's events
979
+ * count toward a group only with it, so send one shopper's events a call. A label for a test that ended is ignored. */
980
+ abTest?: AbTestLabel | string;
981
+ };
982
+ /** A shopper's group in an A/B test, as a browser search answer's `abTest` gives it: `a` searched with today's
983
+ * settings, `b` with the change (0.32.0). */
984
+ export type AbTestLabel = {
985
+ id: string;
986
+ variant: "a" | "b";
987
+ };
988
+ /** One measure in an A/B test's results: each group's value per search (a share for `noResults` and `topThree`), and
989
+ * B's change over A (0.1 is 10% more) with its 95% interval. Null where there aren't the searches or days yet. */
990
+ export type AbFigure = {
991
+ a: number | null;
992
+ b: number | null;
993
+ change: number | null;
994
+ low: number | null;
995
+ high: number | null;
996
+ };
997
+ /** An A/B test's results. `decided` once the test has run its days with 1,000 searches in each group; `verdict` is then
998
+ * `b` (the change did better), `a` (worse) or `none` (no clear difference), judged on clicks per search, then carts. */
999
+ export type AbTestResults = {
1000
+ days: number;
1001
+ decided: boolean;
1002
+ verdict: "a" | "b" | "none" | null;
1003
+ searches: {
1004
+ a: number;
1005
+ b: number;
1006
+ };
1007
+ currency: string | null;
1008
+ figures: Record<"noResults" | "clicks" | "topThree" | "carts" | "orders" | "revenue", AbFigure>;
1009
+ perDay: {
1010
+ day: string;
1011
+ searches: {
1012
+ a: number;
1013
+ b: number;
1014
+ };
1015
+ clicks: {
1016
+ a: number;
1017
+ b: number;
1018
+ };
1019
+ }[];
1020
+ computedAt: string;
1021
+ };
1022
+ /** An A/B test of an index's settings (0.32.0): group B's `share` of shoppers, the settings it `changes` and their values
1023
+ * in `patch` (null where B goes without one), an A/A test (`aa`) changes none. `outcome` once ended: `a` kept today's
1024
+ * settings, `b` applied the change, `guard` ended early because the change found nothing far more often. */
1025
+ export type AbTest = {
1026
+ id: string;
1027
+ name: string;
1028
+ share: number;
1029
+ changes: string[];
1030
+ aa: boolean;
1031
+ patch: Record<string, unknown>;
1032
+ startedAt: string;
1033
+ endsAt: string;
1034
+ endedAt: string | null;
1035
+ outcome: "a" | "b" | "guard" | null;
1036
+ results: AbTestResults | null;
1037
+ };
1038
+ /** An index's A/B tests: the running one with its results so far, or null, and up to 10 that ended, newest first. */
1039
+ export type AbTests = {
1040
+ running: AbTest | null;
1041
+ ended: AbTest[];
1042
+ };
1043
+ /** What a test at a share would take: the days to find a 10% change in clicks per search (null with too few
1044
+ * searches), from the index's searches and clicks per search over the last 14 days, and the share of searches more
1045
+ * that would miss the cache. */
1046
+ export type AbTestEstimate = {
1047
+ searchesPerDay: number;
1048
+ clicksPerSearch: number;
1049
+ days: number | null;
1050
+ extraMisses: number;
969
1051
  };
970
1052
  /** An analytics window, in UTC: `range` (7d by default), or `from` and `to`. A date as `from` is the start of
971
1053
  * that day, and as `to` includes the whole day; `to` is now by default. Analytics go back 90 days: a window
@@ -1456,6 +1538,29 @@ export declare class SearchServerClient {
1456
1538
  range?: "7d" | "30d" | "90d";
1457
1539
  signal?: AbortSignal;
1458
1540
  }) => Promise<BannerStatsReport>;
1541
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
1542
+ abTest: (options?: {
1543
+ signal?: AbortSignal;
1544
+ }) => Promise<AbTests & {
1545
+ index: string;
1546
+ }>;
1547
+ };
1548
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
1549
+ abTests: {
1550
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
1551
+ get: (signal?: AbortSignal) => Promise<AbTests & {
1552
+ shares: number[];
1553
+ days: {
1554
+ min: number;
1555
+ default: number;
1556
+ max: number;
1557
+ };
1558
+ }>;
1559
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
1560
+ estimate: (options?: {
1561
+ share?: number;
1562
+ signal?: AbortSignal;
1563
+ }) => Promise<AbTestEstimate>;
1459
1564
  };
1460
1565
  upsert: (records: T[], signal?: AbortSignal) => Promise<WriteReceipt>;
1461
1566
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<T>>;
@@ -1664,6 +1769,29 @@ export declare class SearchServerClient {
1664
1769
  range?: "7d" | "30d" | "90d";
1665
1770
  signal?: AbortSignal;
1666
1771
  }) => Promise<BannerStatsReport>;
1772
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
1773
+ abTest: (options?: {
1774
+ signal?: AbortSignal;
1775
+ }) => Promise<AbTests & {
1776
+ index: string;
1777
+ }>;
1778
+ };
1779
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
1780
+ abTests: {
1781
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
1782
+ get: (signal?: AbortSignal) => Promise<AbTests & {
1783
+ shares: number[];
1784
+ days: {
1785
+ min: number;
1786
+ default: number;
1787
+ max: number;
1788
+ };
1789
+ }>;
1790
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
1791
+ estimate: (options?: {
1792
+ share?: number;
1793
+ signal?: AbortSignal;
1794
+ }) => Promise<AbTestEstimate>;
1667
1795
  };
1668
1796
  upsert: (records: S[], signal?: AbortSignal) => Promise<WriteReceipt>;
1669
1797
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S>>;
@@ -1870,6 +1998,29 @@ export declare class SearchServerClient {
1870
1998
  range?: "7d" | "30d" | "90d";
1871
1999
  signal?: AbortSignal;
1872
2000
  }) => Promise<BannerStatsReport>;
2001
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
2002
+ abTest: (options?: {
2003
+ signal?: AbortSignal;
2004
+ }) => Promise<AbTests & {
2005
+ index: string;
2006
+ }>;
2007
+ };
2008
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
2009
+ abTests: {
2010
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
2011
+ get: (signal?: AbortSignal) => Promise<AbTests & {
2012
+ shares: number[];
2013
+ days: {
2014
+ min: number;
2015
+ default: number;
2016
+ max: number;
2017
+ };
2018
+ }>;
2019
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
2020
+ estimate: (options?: {
2021
+ share?: number;
2022
+ signal?: AbortSignal;
2023
+ }) => Promise<AbTestEstimate>;
1873
2024
  };
1874
2025
  upsert: (records: S_1[], signal?: AbortSignal) => Promise<WriteReceipt>;
1875
2026
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_1>>;
@@ -2076,6 +2227,29 @@ export declare class SearchServerClient {
2076
2227
  range?: "7d" | "30d" | "90d";
2077
2228
  signal?: AbortSignal;
2078
2229
  }) => Promise<BannerStatsReport>;
2230
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
2231
+ abTest: (options?: {
2232
+ signal?: AbortSignal;
2233
+ }) => Promise<AbTests & {
2234
+ index: string;
2235
+ }>;
2236
+ };
2237
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
2238
+ abTests: {
2239
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
2240
+ get: (signal?: AbortSignal) => Promise<AbTests & {
2241
+ shares: number[];
2242
+ days: {
2243
+ min: number;
2244
+ default: number;
2245
+ max: number;
2246
+ };
2247
+ }>;
2248
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
2249
+ estimate: (options?: {
2250
+ share?: number;
2251
+ signal?: AbortSignal;
2252
+ }) => Promise<AbTestEstimate>;
2079
2253
  };
2080
2254
  upsert: (records: S_2[], signal?: AbortSignal) => Promise<WriteReceipt>;
2081
2255
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_2>>;
@@ -2282,6 +2456,29 @@ export declare class SearchServerClient {
2282
2456
  range?: "7d" | "30d" | "90d";
2283
2457
  signal?: AbortSignal;
2284
2458
  }) => Promise<BannerStatsReport>;
2459
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
2460
+ abTest: (options?: {
2461
+ signal?: AbortSignal;
2462
+ }) => Promise<AbTests & {
2463
+ index: string;
2464
+ }>;
2465
+ };
2466
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
2467
+ abTests: {
2468
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
2469
+ get: (signal?: AbortSignal) => Promise<AbTests & {
2470
+ shares: number[];
2471
+ days: {
2472
+ min: number;
2473
+ default: number;
2474
+ max: number;
2475
+ };
2476
+ }>;
2477
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
2478
+ estimate: (options?: {
2479
+ share?: number;
2480
+ signal?: AbortSignal;
2481
+ }) => Promise<AbTestEstimate>;
2285
2482
  };
2286
2483
  upsert: (records: S_3[], signal?: AbortSignal) => Promise<WriteReceipt>;
2287
2484
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_3>>;
@@ -2488,6 +2685,29 @@ export declare class SearchServerClient {
2488
2685
  range?: "7d" | "30d" | "90d";
2489
2686
  signal?: AbortSignal;
2490
2687
  }) => Promise<BannerStatsReport>;
2688
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
2689
+ abTest: (options?: {
2690
+ signal?: AbortSignal;
2691
+ }) => Promise<AbTests & {
2692
+ index: string;
2693
+ }>;
2694
+ };
2695
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
2696
+ abTests: {
2697
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
2698
+ get: (signal?: AbortSignal) => Promise<AbTests & {
2699
+ shares: number[];
2700
+ days: {
2701
+ min: number;
2702
+ default: number;
2703
+ max: number;
2704
+ };
2705
+ }>;
2706
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
2707
+ estimate: (options?: {
2708
+ share?: number;
2709
+ signal?: AbortSignal;
2710
+ }) => Promise<AbTestEstimate>;
2491
2711
  };
2492
2712
  upsert: (records: S_4[], signal?: AbortSignal) => Promise<WriteReceipt>;
2493
2713
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_4>>;
@@ -2694,6 +2914,29 @@ export declare class SearchServerClient {
2694
2914
  range?: "7d" | "30d" | "90d";
2695
2915
  signal?: AbortSignal;
2696
2916
  }) => Promise<BannerStatsReport>;
2917
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
2918
+ abTest: (options?: {
2919
+ signal?: AbortSignal;
2920
+ }) => Promise<AbTests & {
2921
+ index: string;
2922
+ }>;
2923
+ };
2924
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
2925
+ abTests: {
2926
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
2927
+ get: (signal?: AbortSignal) => Promise<AbTests & {
2928
+ shares: number[];
2929
+ days: {
2930
+ min: number;
2931
+ default: number;
2932
+ max: number;
2933
+ };
2934
+ }>;
2935
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
2936
+ estimate: (options?: {
2937
+ share?: number;
2938
+ signal?: AbortSignal;
2939
+ }) => Promise<AbTestEstimate>;
2697
2940
  };
2698
2941
  upsert: (records: S_5[], signal?: AbortSignal) => Promise<WriteReceipt>;
2699
2942
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_5>>;
@@ -2900,6 +3143,29 @@ export declare class SearchServerClient {
2900
3143
  range?: "7d" | "30d" | "90d";
2901
3144
  signal?: AbortSignal;
2902
3145
  }) => Promise<BannerStatsReport>;
3146
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
3147
+ abTest: (options?: {
3148
+ signal?: AbortSignal;
3149
+ }) => Promise<AbTests & {
3150
+ index: string;
3151
+ }>;
3152
+ };
3153
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
3154
+ abTests: {
3155
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
3156
+ get: (signal?: AbortSignal) => Promise<AbTests & {
3157
+ shares: number[];
3158
+ days: {
3159
+ min: number;
3160
+ default: number;
3161
+ max: number;
3162
+ };
3163
+ }>;
3164
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
3165
+ estimate: (options?: {
3166
+ share?: number;
3167
+ signal?: AbortSignal;
3168
+ }) => Promise<AbTestEstimate>;
2903
3169
  };
2904
3170
  upsert: (records: S_6[], signal?: AbortSignal) => Promise<WriteReceipt>;
2905
3171
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_6>>;
@@ -3106,6 +3372,29 @@ export declare class SearchServerClient {
3106
3372
  range?: "7d" | "30d" | "90d";
3107
3373
  signal?: AbortSignal;
3108
3374
  }) => Promise<BannerStatsReport>;
3375
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
3376
+ abTest: (options?: {
3377
+ signal?: AbortSignal;
3378
+ }) => Promise<AbTests & {
3379
+ index: string;
3380
+ }>;
3381
+ };
3382
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
3383
+ abTests: {
3384
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
3385
+ get: (signal?: AbortSignal) => Promise<AbTests & {
3386
+ shares: number[];
3387
+ days: {
3388
+ min: number;
3389
+ default: number;
3390
+ max: number;
3391
+ };
3392
+ }>;
3393
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
3394
+ estimate: (options?: {
3395
+ share?: number;
3396
+ signal?: AbortSignal;
3397
+ }) => Promise<AbTestEstimate>;
3109
3398
  };
3110
3399
  upsert: (records: S_7[], signal?: AbortSignal) => Promise<WriteReceipt>;
3111
3400
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_7>>;
@@ -3312,6 +3601,29 @@ export declare class SearchServerClient {
3312
3601
  range?: "7d" | "30d" | "90d";
3313
3602
  signal?: AbortSignal;
3314
3603
  }) => Promise<BannerStatsReport>;
3604
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
3605
+ abTest: (options?: {
3606
+ signal?: AbortSignal;
3607
+ }) => Promise<AbTests & {
3608
+ index: string;
3609
+ }>;
3610
+ };
3611
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
3612
+ abTests: {
3613
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
3614
+ get: (signal?: AbortSignal) => Promise<AbTests & {
3615
+ shares: number[];
3616
+ days: {
3617
+ min: number;
3618
+ default: number;
3619
+ max: number;
3620
+ };
3621
+ }>;
3622
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
3623
+ estimate: (options?: {
3624
+ share?: number;
3625
+ signal?: AbortSignal;
3626
+ }) => Promise<AbTestEstimate>;
3315
3627
  };
3316
3628
  upsert: (records: S_8[], signal?: AbortSignal) => Promise<WriteReceipt>;
3317
3629
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_8>>;
@@ -3518,6 +3830,29 @@ export declare class SearchServerClient {
3518
3830
  range?: "7d" | "30d" | "90d";
3519
3831
  signal?: AbortSignal;
3520
3832
  }) => Promise<BannerStatsReport>;
3833
+ /** The index's A/B tests, as `abTests.get()` reads them with a search or write key (0.32.0). */
3834
+ abTest: (options?: {
3835
+ signal?: AbortSignal;
3836
+ }) => Promise<AbTests & {
3837
+ index: string;
3838
+ }>;
3839
+ };
3840
+ /** The index's A/B tests of its settings (0.32.0); owners start and end them in the dashboard, or through an agent. */
3841
+ abTests: {
3842
+ /** The running test with its results so far, and those that ended; with the shares and days a test may take. */
3843
+ get: (signal?: AbortSignal) => Promise<AbTests & {
3844
+ shares: number[];
3845
+ days: {
3846
+ min: number;
3847
+ default: number;
3848
+ max: number;
3849
+ };
3850
+ }>;
3851
+ /** What a test would take at a `share` of shoppers in group B: 0.1 to 0.5, 0.5 by default. */
3852
+ estimate: (options?: {
3853
+ share?: number;
3854
+ signal?: AbortSignal;
3855
+ }) => Promise<AbTestEstimate>;
3521
3856
  };
3522
3857
  upsert: (records: S_9[], signal?: AbortSignal) => Promise<WriteReceipt>;
3523
3858
  getRecord: (objectID: string, signal?: AbortSignal) => Promise<RecordSnapshot<S_9>>;
package/dist/index.js CHANGED
@@ -194,7 +194,8 @@ class SearchServerClient {
194
194
  return jsonResponse(await response.text(), response.status, retryAfter ? { "retry-after": retryAfter } : {});
195
195
  };
196
196
  const sendEvents = async (events, options = {}) => {
197
- const { signal, visitorId, visitId } = options;
197
+ const { signal, visitorId, visitId, abTest } = options;
198
+ const label = abTest === undefined || typeof abTest === "string" ? abTest : `${abTest.id}:${abTest.variant}`;
198
199
  const result = { accepted: 0, rejected: [] };
199
200
  let batch = [];
200
201
  let sent = 0;
@@ -204,6 +205,7 @@ class SearchServerClient {
204
205
  const answer = await postEvents({
205
206
  ...visitorId === undefined ? {} : { visitorId },
206
207
  ...visitId === undefined ? {} : { visitId },
208
+ ...label === undefined ? {} : { abTest: label },
207
209
  events: batch
208
210
  }, signal);
209
211
  result.accepted += answer.accepted ?? 0;
@@ -347,7 +349,12 @@ class SearchServerClient {
347
349
  product: (objectID, options = {}) => report(`products/${encodeURIComponent(objectID)}`, options),
348
350
  revenue: (options = {}) => report("revenue", options),
349
351
  filterSales: (options = {}) => report("filter-sales", options),
350
- banners: (options = {}) => request(`/banners?range=${options.range ?? "30d"}`, "GET", undefined, options.signal)
352
+ banners: (options = {}) => request(`/banners?range=${options.range ?? "30d"}`, "GET", undefined, options.signal),
353
+ abTest: (options = {}) => request("/analytics/ab-test", "GET", undefined, options.signal)
354
+ },
355
+ abTests: {
356
+ get: (signal) => request("/ab-tests", "GET", undefined, signal),
357
+ estimate: (options = {}) => request(`/ab-tests/estimate${options.share === undefined ? "" : `?share=${options.share}`}`, "GET", undefined, options.signal)
351
358
  },
352
359
  upsert: (records, signal) => request("/records", "POST", { records }, signal),
353
360
  getRecord: (objectID, signal) => request(`/records/${encodeURIComponent(objectID)}`, "GET", undefined, signal),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@findlane/server",
3
- "version": "0.30.0",
3
+ "version": "0.32.0",
4
4
  "description": "Findlane server SDK: upload catalogs, manage index settings, and search with a secret workspace API key.",
5
5
  "keywords": ["findlane", "search", "full-text search", "typo tolerance", "ecommerce search", "search api", "sdk"],
6
6
  "license": "MIT",