@findlane/browser 0.1.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/LICENSE +21 -0
- package/README.md +63 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.js +38 -0
- package/package.json +25 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dagur Leo Bergsson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# @findlane/browser
|
|
2
|
+
|
|
3
|
+
The Findlane browser SDK: fast, typo-tolerant search from the browser with an index's public ID. No dependencies, about 1 KB.
|
|
4
|
+
|
|
5
|
+
Docs: https://findlane.dev/docs/browser-sdk
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @findlane/browser
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { SearchBrowserClient } from "@findlane/browser"
|
|
17
|
+
|
|
18
|
+
const client = new SearchBrowserClient({ publicId: "pub_your_public_index_id" })
|
|
19
|
+
const results = await client.search({ q: "trail shoe", limit: 10, highlight: true })
|
|
20
|
+
// results.hits[0].highlights?.title: "Trail <mark>shoe</mark>" (HTML-escaped, safe to insert as HTML)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Without a build step, load it with a script tag, which defines a global `Findlane`:
|
|
24
|
+
|
|
25
|
+
```html
|
|
26
|
+
<script src="https://cdn.findlane.dev/browser/0/findlane.min.js"></script>
|
|
27
|
+
<script>
|
|
28
|
+
const client = new Findlane.SearchBrowserClient({ publicId: "pub_your_public_id" })
|
|
29
|
+
</script>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Each index has a copyable public ID in the dashboard. An owner must save allowed origins for the index before browser search is enabled.
|
|
33
|
+
|
|
34
|
+
## Search requests
|
|
35
|
+
|
|
36
|
+
| Option | |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `q` | The query. Words match with typos and as prefixes, depending on the index's settings. |
|
|
39
|
+
| `filters` | Field values to keep: a value, `{ in: [...] }`, or a range `{ gte, lte }` for numbers and dates. |
|
|
40
|
+
| `facets` | Fields to count values for, such as `["brand.name"]`. |
|
|
41
|
+
| `sort` | A sort ID from the index settings, or `"relevance"`. |
|
|
42
|
+
| `limit`, `offset` | Paging: up to 50 hits a request, and offsets up to 1,000. |
|
|
43
|
+
| `countMode`, `facetMode` | `"page"` (the default, fastest) or `"exact"` for totals and facet counts across every match. |
|
|
44
|
+
| `highlight` | `true` to wrap matched words in `<mark>`, or `{ preTag, postTag }`. |
|
|
45
|
+
| `attributesToRetrieve` | Return only these fields. |
|
|
46
|
+
|
|
47
|
+
A response has `hits` (each with its `record` and any `highlights`), `total`, `facets`, and `tookMs`. Pass `{ signal }` as a second argument to cancel a request, as search-as-you-type should.
|
|
48
|
+
|
|
49
|
+
## Security
|
|
50
|
+
|
|
51
|
+
The public ID grants search access only to its index, and it is visible in browser source. By default the API returns every uploaded record field. `attributesToRetrieve` requests fewer fields for speed, but it does not make the others private. Origin checks constrain browsers; they do not authenticate other callers. Keep public catalog fields safe to expose. The dashboard can remove origins, add server-enforced restrictions, or rotate the ID.
|
|
52
|
+
|
|
53
|
+
## Errors
|
|
54
|
+
|
|
55
|
+
Failed requests throw a `FindlaneError` with the HTTP `status` and the API's message:
|
|
56
|
+
|
|
57
|
+
- 403: this origin isn't allowed.
|
|
58
|
+
- 429: the public search rate limit.
|
|
59
|
+
- 402: the workspace has used its monthly searches.
|
|
60
|
+
|
|
61
|
+
## License
|
|
62
|
+
|
|
63
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export type SearchRequest = {
|
|
2
|
+
q?: string;
|
|
3
|
+
/** A sort ID from the index settings, or "relevance". */
|
|
4
|
+
sort?: string;
|
|
5
|
+
/** Field values to keep: a value, `{ in: [...] }`, or a range `{ gte, lte }` for numbers and dates. */
|
|
6
|
+
filters?: Record<string, unknown>;
|
|
7
|
+
facets?: string[];
|
|
8
|
+
/** Hits per request: 1–50 (default 20). */
|
|
9
|
+
limit?: number;
|
|
10
|
+
/** Up to 1,000. */
|
|
11
|
+
offset?: number;
|
|
12
|
+
attributesToRetrieve?: string[];
|
|
13
|
+
/** "page" (default) counts only the returned page when a query matches more; "exact" counts every match. */
|
|
14
|
+
countMode?: "page" | "exact";
|
|
15
|
+
/** "page" (default) counts facet values in the returned page; "exact" counts them across every match. */
|
|
16
|
+
facetMode?: "page" | "exact";
|
|
17
|
+
/** Mark the words the query matched in each hit's searchable fields: true for <mark> tags, or custom tags.
|
|
18
|
+
* Highlighted values are HTML-escaped, so they can be inserted as HTML. */
|
|
19
|
+
highlight?: boolean | {
|
|
20
|
+
preTag?: string;
|
|
21
|
+
postTag?: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export type SearchResponse<T> = {
|
|
25
|
+
hits: {
|
|
26
|
+
id: string;
|
|
27
|
+
score: number | null;
|
|
28
|
+
record: T;
|
|
29
|
+
/** With `highlight`: matched searchable fields by path; list fields give one string per value. */
|
|
30
|
+
highlights?: Record<string, string | string[]>;
|
|
31
|
+
}[];
|
|
32
|
+
total: number;
|
|
33
|
+
/** "gte" when `total` is a lower bound (page count mode). */
|
|
34
|
+
totalRelation?: "eq" | "gte";
|
|
35
|
+
hasMore?: boolean;
|
|
36
|
+
facets: Record<string, Record<string, number>>;
|
|
37
|
+
tookMs: number;
|
|
38
|
+
sort?: string;
|
|
39
|
+
};
|
|
40
|
+
export declare class FindlaneError extends Error {
|
|
41
|
+
status: number;
|
|
42
|
+
constructor(status: number, message: string);
|
|
43
|
+
}
|
|
44
|
+
/** The hosted Findlane API, used unless `baseUrl` says otherwise. */
|
|
45
|
+
export declare const defaultBaseUrl = "https://api.findlane.dev";
|
|
46
|
+
export type BrowserClientOptions = {
|
|
47
|
+
/** The API to call; defaults to the hosted Findlane API. */
|
|
48
|
+
baseUrl?: string;
|
|
49
|
+
publicId: string;
|
|
50
|
+
fetch?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
51
|
+
};
|
|
52
|
+
export declare class SearchBrowserClient {
|
|
53
|
+
private readonly url;
|
|
54
|
+
private readonly fetcher;
|
|
55
|
+
constructor(options: BrowserClientOptions);
|
|
56
|
+
search<T = Record<string, unknown>>(request: SearchRequest, options?: {
|
|
57
|
+
signal?: AbortSignal;
|
|
58
|
+
}): Promise<SearchResponse<T>>;
|
|
59
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
class FindlaneError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
constructor(status, message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.status = status;
|
|
7
|
+
this.name = "FindlaneError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
var defaultBaseUrl = "https://api.findlane.dev";
|
|
11
|
+
|
|
12
|
+
class SearchBrowserClient {
|
|
13
|
+
url;
|
|
14
|
+
fetcher;
|
|
15
|
+
constructor(options) {
|
|
16
|
+
if (!/^pub_[a-f0-9]{32}$/.test(options.publicId))
|
|
17
|
+
throw new Error("A valid public index ID (pub_…) is required");
|
|
18
|
+
this.url = `${(options.baseUrl ?? defaultBaseUrl).replace(/\/$/, "")}/api/public/indexes/${options.publicId}/search`;
|
|
19
|
+
this.fetcher = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
20
|
+
}
|
|
21
|
+
async search(request, options = {}) {
|
|
22
|
+
const response = await this.fetcher(this.url, {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: { "content-type": "application/json" },
|
|
25
|
+
body: JSON.stringify(request),
|
|
26
|
+
signal: options.signal
|
|
27
|
+
});
|
|
28
|
+
const data = await response.json();
|
|
29
|
+
if (!response.ok)
|
|
30
|
+
throw new FindlaneError(response.status, data.error ?? `HTTP ${response.status}`);
|
|
31
|
+
return data;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
FindlaneError,
|
|
36
|
+
SearchBrowserClient,
|
|
37
|
+
defaultBaseUrl
|
|
38
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@findlane/browser",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Findlane browser SDK: fast, typo-tolerant public search from the browser with an index's public ID.",
|
|
5
|
+
"keywords": ["findlane", "search", "full-text search", "typo tolerance", "instant search", "ecommerce search", "browser"],
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://findlane.dev/docs/browser-sdk",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"files": ["dist", "README.md", "LICENSE"],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"publishConfig": { "access": "public" },
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "rm -rf dist && bun build src/index.ts --target=browser --format=esm --outdir=dist && tsc -p tsconfig.build.json",
|
|
23
|
+
"prepublishOnly": "bun run build"
|
|
24
|
+
}
|
|
25
|
+
}
|