@findlane/server 0.18.0 → 0.19.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.cjs +6 -6
- package/dist/index.d.cts +30 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +6 -6
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -232,7 +232,7 @@ class SearchServerClient {
|
|
|
232
232
|
await flush();
|
|
233
233
|
return result;
|
|
234
234
|
};
|
|
235
|
-
const report = (
|
|
235
|
+
const report = (name, options) => retry(() => request(`/analytics/${name}${analyticsQuery(options)}`, "GET", undefined, options.signal), options.signal);
|
|
236
236
|
const stagePath = (stageId) => `/staged-replacements/${encodeURIComponent(stageId)}`;
|
|
237
237
|
const beginReplacement = (stageId, signal) => retry(() => request(stagePath(stageId), "POST", undefined, signal), signal);
|
|
238
238
|
const uploadReplacementBatch = (stageId, batchId, records, signal) => retry(() => request(`${stagePath(stageId)}/batches/${encodeURIComponent(batchId)}`, "POST", { records }, signal), signal);
|
|
@@ -295,16 +295,16 @@ class SearchServerClient {
|
|
|
295
295
|
forgotten += (await postEvents({ forget: ids.slice(start, start + 1000) }, signal)).forgotten ?? 0;
|
|
296
296
|
return { forgotten };
|
|
297
297
|
},
|
|
298
|
-
proxy: async (
|
|
299
|
-
if (
|
|
298
|
+
proxy: async (request, visitor = {}) => {
|
|
299
|
+
if (request.method !== "POST")
|
|
300
300
|
return jsonResponse(JSON.stringify({ error: "Only POST is allowed" }), 405, { allow: "POST" });
|
|
301
301
|
const tooLarge = () => jsonResponse(JSON.stringify({ error: "The request is too large" }), 413);
|
|
302
|
-
if (Number(
|
|
302
|
+
if (Number(request.headers.get("content-length") ?? 0) > relayedBytes)
|
|
303
303
|
return tooLarge();
|
|
304
|
-
const body = await
|
|
304
|
+
const body = await request.text();
|
|
305
305
|
if (new TextEncoder().encode(body).length > relayedBytes)
|
|
306
306
|
return tooLarge();
|
|
307
|
-
const found = { ...requestVisitor(
|
|
307
|
+
const found = { ...requestVisitor(request), ...visitor };
|
|
308
308
|
if (!found.ip)
|
|
309
309
|
throw new Error("No visitor IP address in the request's headers; pass it: events.proxy(request, { ip })");
|
|
310
310
|
return relayEvents(body, { ...found, ip: found.ip });
|
package/dist/index.d.cts
CHANGED
|
@@ -77,6 +77,18 @@ export type IndexSettings = {
|
|
|
77
77
|
normalizationProfile?: "default-v2" | "default-v1" | "icelandic-ascii-v1";
|
|
78
78
|
/** An object field of lat and lng numbers, such as `_geoloc`, that `near` and `within` search; null for none. */
|
|
79
79
|
locationField?: string | null;
|
|
80
|
+
/** Shows each value of a field once, such as a product whose colours or sizes are records sharing its ID:
|
|
81
|
+
* the record (or up to `limit`, 1 to 4) that best matches the search. A text or number field with one value;
|
|
82
|
+
* `total` then counts groups. Null for none. */
|
|
83
|
+
distinct?: {
|
|
84
|
+
field: string;
|
|
85
|
+
limit?: number;
|
|
86
|
+
} | null;
|
|
87
|
+
/** Variants listed inside each record, such as a product's flavours: a list of objects at `field`. Each hit
|
|
88
|
+
* then says which one the search matched (`variant`). Null for none. */
|
|
89
|
+
variants?: {
|
|
90
|
+
field: string;
|
|
91
|
+
} | null;
|
|
80
92
|
/** When saving: types for fields no record has yet, so settings can come before the records. Records'
|
|
81
93
|
* types win once they have the field. Not returned when reading settings. */
|
|
82
94
|
fieldTypes?: Record<string, "text" | "number" | "boolean" | "text[]" | "number[]" | "boolean[]" | "location">;
|
|
@@ -345,6 +357,9 @@ export type SearchRequest = {
|
|
|
345
357
|
within?: GeoBox;
|
|
346
358
|
/** With the index's `relatedResults` on: false asks for no related results (0.18.0). */
|
|
347
359
|
related?: boolean;
|
|
360
|
+
/** With the index's `distinct` setting: false shows every record, a number 1 to 4 how many of each group's
|
|
361
|
+
* records. */
|
|
362
|
+
distinct?: boolean | number;
|
|
348
363
|
};
|
|
349
364
|
/** A point in degrees: lat from -90 to 90, lng from -180 to 180. */
|
|
350
365
|
export type GeoPoint = {
|
|
@@ -425,8 +440,23 @@ export type SearchResponse<T> = {
|
|
|
425
440
|
highlights?: Record<string, string | string[]>;
|
|
426
441
|
/** With `explain`: why the hit matched and what ordered it. */
|
|
427
442
|
explain?: HitExplanation;
|
|
443
|
+
/** With the index's `distinct` setting: the hit's group (its value of the group field, null for a record
|
|
444
|
+
* without one) and how many of the group's records matched. */
|
|
445
|
+
group?: {
|
|
446
|
+
value: string | number | null;
|
|
447
|
+
matched: number;
|
|
448
|
+
};
|
|
449
|
+
/** With the index's `variants` setting: which item of the record's variants list the search matched, by
|
|
450
|
+
* its words or by filters on the variants' fields, such as the flavour a shopper typed. Absent when none
|
|
451
|
+
* stands out. */
|
|
452
|
+
variant?: {
|
|
453
|
+
index: number;
|
|
454
|
+
};
|
|
428
455
|
}[];
|
|
456
|
+
/** The matches; with the index's `distinct` setting, the groups. */
|
|
429
457
|
total: number;
|
|
458
|
+
/** With `distinct`: the matching records, which `total` counts as groups. */
|
|
459
|
+
totalRecords?: number;
|
|
430
460
|
/** "gte" when `total` is a lower bound (page count mode). */
|
|
431
461
|
totalRelation?: "eq" | "gte";
|
|
432
462
|
hasMore?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -77,6 +77,18 @@ export type IndexSettings = {
|
|
|
77
77
|
normalizationProfile?: "default-v2" | "default-v1" | "icelandic-ascii-v1";
|
|
78
78
|
/** An object field of lat and lng numbers, such as `_geoloc`, that `near` and `within` search; null for none. */
|
|
79
79
|
locationField?: string | null;
|
|
80
|
+
/** Shows each value of a field once, such as a product whose colours or sizes are records sharing its ID:
|
|
81
|
+
* the record (or up to `limit`, 1 to 4) that best matches the search. A text or number field with one value;
|
|
82
|
+
* `total` then counts groups. Null for none. */
|
|
83
|
+
distinct?: {
|
|
84
|
+
field: string;
|
|
85
|
+
limit?: number;
|
|
86
|
+
} | null;
|
|
87
|
+
/** Variants listed inside each record, such as a product's flavours: a list of objects at `field`. Each hit
|
|
88
|
+
* then says which one the search matched (`variant`). Null for none. */
|
|
89
|
+
variants?: {
|
|
90
|
+
field: string;
|
|
91
|
+
} | null;
|
|
80
92
|
/** When saving: types for fields no record has yet, so settings can come before the records. Records'
|
|
81
93
|
* types win once they have the field. Not returned when reading settings. */
|
|
82
94
|
fieldTypes?: Record<string, "text" | "number" | "boolean" | "text[]" | "number[]" | "boolean[]" | "location">;
|
|
@@ -345,6 +357,9 @@ export type SearchRequest = {
|
|
|
345
357
|
within?: GeoBox;
|
|
346
358
|
/** With the index's `relatedResults` on: false asks for no related results (0.18.0). */
|
|
347
359
|
related?: boolean;
|
|
360
|
+
/** With the index's `distinct` setting: false shows every record, a number 1 to 4 how many of each group's
|
|
361
|
+
* records. */
|
|
362
|
+
distinct?: boolean | number;
|
|
348
363
|
};
|
|
349
364
|
/** A point in degrees: lat from -90 to 90, lng from -180 to 180. */
|
|
350
365
|
export type GeoPoint = {
|
|
@@ -425,8 +440,23 @@ export type SearchResponse<T> = {
|
|
|
425
440
|
highlights?: Record<string, string | string[]>;
|
|
426
441
|
/** With `explain`: why the hit matched and what ordered it. */
|
|
427
442
|
explain?: HitExplanation;
|
|
443
|
+
/** With the index's `distinct` setting: the hit's group (its value of the group field, null for a record
|
|
444
|
+
* without one) and how many of the group's records matched. */
|
|
445
|
+
group?: {
|
|
446
|
+
value: string | number | null;
|
|
447
|
+
matched: number;
|
|
448
|
+
};
|
|
449
|
+
/** With the index's `variants` setting: which item of the record's variants list the search matched, by
|
|
450
|
+
* its words or by filters on the variants' fields, such as the flavour a shopper typed. Absent when none
|
|
451
|
+
* stands out. */
|
|
452
|
+
variant?: {
|
|
453
|
+
index: number;
|
|
454
|
+
};
|
|
428
455
|
}[];
|
|
456
|
+
/** The matches; with the index's `distinct` setting, the groups. */
|
|
429
457
|
total: number;
|
|
458
|
+
/** With `distinct`: the matching records, which `total` counts as groups. */
|
|
459
|
+
totalRecords?: number;
|
|
430
460
|
/** "gte" when `total` is a lower bound (page count mode). */
|
|
431
461
|
totalRelation?: "eq" | "gte";
|
|
432
462
|
hasMore?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -186,7 +186,7 @@ class SearchServerClient {
|
|
|
186
186
|
await flush();
|
|
187
187
|
return result;
|
|
188
188
|
};
|
|
189
|
-
const report = (
|
|
189
|
+
const report = (name, options) => retry(() => request(`/analytics/${name}${analyticsQuery(options)}`, "GET", undefined, options.signal), options.signal);
|
|
190
190
|
const stagePath = (stageId) => `/staged-replacements/${encodeURIComponent(stageId)}`;
|
|
191
191
|
const beginReplacement = (stageId, signal) => retry(() => request(stagePath(stageId), "POST", undefined, signal), signal);
|
|
192
192
|
const uploadReplacementBatch = (stageId, batchId, records, signal) => retry(() => request(`${stagePath(stageId)}/batches/${encodeURIComponent(batchId)}`, "POST", { records }, signal), signal);
|
|
@@ -249,16 +249,16 @@ class SearchServerClient {
|
|
|
249
249
|
forgotten += (await postEvents({ forget: ids.slice(start, start + 1000) }, signal)).forgotten ?? 0;
|
|
250
250
|
return { forgotten };
|
|
251
251
|
},
|
|
252
|
-
proxy: async (
|
|
253
|
-
if (
|
|
252
|
+
proxy: async (request, visitor = {}) => {
|
|
253
|
+
if (request.method !== "POST")
|
|
254
254
|
return jsonResponse(JSON.stringify({ error: "Only POST is allowed" }), 405, { allow: "POST" });
|
|
255
255
|
const tooLarge = () => jsonResponse(JSON.stringify({ error: "The request is too large" }), 413);
|
|
256
|
-
if (Number(
|
|
256
|
+
if (Number(request.headers.get("content-length") ?? 0) > relayedBytes)
|
|
257
257
|
return tooLarge();
|
|
258
|
-
const body = await
|
|
258
|
+
const body = await request.text();
|
|
259
259
|
if (new TextEncoder().encode(body).length > relayedBytes)
|
|
260
260
|
return tooLarge();
|
|
261
|
-
const found = { ...requestVisitor(
|
|
261
|
+
const found = { ...requestVisitor(request), ...visitor };
|
|
262
262
|
if (!found.ip)
|
|
263
263
|
throw new Error("No visitor IP address in the request's headers; pass it: events.proxy(request, { ip })");
|
|
264
264
|
return relayEvents(body, { ...found, ip: found.ip });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@findlane/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.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",
|