@skawr/search 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/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # @skawr/search
2
+
3
+ Official SKAWR browser search SDK — lightweight, search-only client safe for frontend use.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @skawr/search
9
+ ```
10
+
11
+ ESM only. ~1.7 KB minified. Zero runtime dependencies.
12
+
13
+ ## Quick Start
14
+
15
+ ```typescript
16
+ import { SkawrSearch } from '@skawr/search';
17
+
18
+ const search = new SkawrSearch({
19
+ publicKey: 'your-public-key',
20
+ baseUrl: 'https://api.skawr.com', // optional
21
+ });
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ### Search
27
+
28
+ ```typescript
29
+ const results = await search.search('laptop', {
30
+ filters: { category: 'electronics', min_price: 100 },
31
+ page: 1,
32
+ per_page: 20,
33
+ sort_by: 'relevance',
34
+ });
35
+
36
+ console.log(results.total_results);
37
+ results.results.forEach((item) => {
38
+ console.log(item.title, item.price);
39
+ });
40
+ ```
41
+
42
+ ### Suggestions
43
+
44
+ ```typescript
45
+ const suggestions = await search.suggest('lap', {
46
+ include_trending: true,
47
+ limit: 10,
48
+ });
49
+
50
+ console.log(suggestions.query_completions); // ['laptop', 'laptop bag', ...]
51
+ console.log(suggestions.trending_queries); // ['phone', 'tablet', ...]
52
+ ```
53
+
54
+ ### Autocomplete
55
+
56
+ ```typescript
57
+ const { suggestions } = await search.autocomplete('lap', { limit: 5 });
58
+ console.log(suggestions); // ['laptop', 'laptop case', 'laptop stand']
59
+ ```
60
+
61
+ ## Configuration
62
+
63
+ | Option | Type | Default | Description |
64
+ |---|---|---|---|
65
+ | `publicKey` | `string` | *required* | Your SKAWR public/search key |
66
+ | `baseUrl` | `string` | `https://api.skawr.com` | API base URL |
67
+ | `timeout` | `number` | `10000` | Request timeout in ms |
68
+
69
+ ## Error Handling
70
+
71
+ ```typescript
72
+ import { SearchError } from '@skawr/search';
73
+
74
+ try {
75
+ await search.search('test');
76
+ } catch (error) {
77
+ if (error instanceof SearchError) {
78
+ console.log(error.status); // HTTP status code
79
+ console.log(error.detail); // Error message from API
80
+ }
81
+ }
82
+ ```
83
+
84
+ ## Browser Support
85
+
86
+ Works in all modern browsers with native `fetch` support (Chrome 42+, Firefox 39+, Safari 10.1+, Edge 14+).
87
+
88
+ ## License
89
+
90
+ MIT
@@ -0,0 +1,95 @@
1
+ interface SkawrSearchConfig {
2
+ publicKey: string;
3
+ baseUrl?: string;
4
+ timeout?: number;
5
+ }
6
+ interface SearchFilters {
7
+ min_price?: number;
8
+ max_price?: number;
9
+ source?: string[];
10
+ category?: string;
11
+ custom_attributes?: Record<string, unknown>;
12
+ boost_fields?: Record<string, number>;
13
+ }
14
+ type SortBy = 'relevance' | 'price_asc' | 'price_desc' | 'date_desc';
15
+ interface SearchOptions {
16
+ index?: string;
17
+ filters?: SearchFilters;
18
+ page?: number;
19
+ per_page?: number;
20
+ sort_by?: SortBy;
21
+ highlight_matches?: boolean;
22
+ result_format?: 'standard' | 'minimal' | 'detailed';
23
+ }
24
+ interface SearchResult {
25
+ id: string;
26
+ title: string;
27
+ description?: string;
28
+ price?: number;
29
+ currency?: string;
30
+ image_url?: string;
31
+ product_url?: string;
32
+ source?: string;
33
+ store_name?: string;
34
+ category?: string;
35
+ score?: number;
36
+ highlighted_title?: string;
37
+ highlighted_description?: string;
38
+ [key: string]: unknown;
39
+ }
40
+ interface FacetCount {
41
+ value: string;
42
+ count: number;
43
+ }
44
+ interface Facet {
45
+ field_name: string;
46
+ counts: FacetCount[];
47
+ }
48
+ interface SearchResponse {
49
+ results: SearchResult[];
50
+ total_results: number;
51
+ page: number;
52
+ per_page: number;
53
+ total_pages: number;
54
+ took_ms: number;
55
+ facets?: Facet[];
56
+ suggestions?: string[];
57
+ search_id: string;
58
+ }
59
+ interface SuggestOptions {
60
+ index?: string;
61
+ limit?: number;
62
+ include_trending?: boolean;
63
+ }
64
+ interface SuggestionsResponse {
65
+ query_completions: string[];
66
+ trending_queries?: string[];
67
+ category_suggestions?: string[];
68
+ }
69
+ interface AutocompleteOptions {
70
+ limit?: number;
71
+ }
72
+ interface AutocompleteResponse {
73
+ suggestions: string[];
74
+ }
75
+
76
+ declare class SkawrSearch {
77
+ private readonly baseUrl;
78
+ private readonly publicKey;
79
+ private readonly timeout;
80
+ constructor(config: SkawrSearchConfig);
81
+ search(query: string, options?: SearchOptions): Promise<SearchResponse>;
82
+ suggest(query: string, options?: SuggestOptions): Promise<SuggestionsResponse>;
83
+ autocomplete(query: string, options?: AutocompleteOptions): Promise<AutocompleteResponse>;
84
+ private get;
85
+ private post;
86
+ private request;
87
+ }
88
+
89
+ declare class SearchError extends Error {
90
+ readonly status: number;
91
+ readonly detail: string;
92
+ constructor(message: string, status: number, detail?: string);
93
+ }
94
+
95
+ export { type AutocompleteOptions, type AutocompleteResponse, type Facet, type FacetCount, SearchError, type SearchFilters, type SearchOptions, type SearchResponse, type SearchResult, SkawrSearch, type SkawrSearchConfig, type SortBy, type SuggestOptions, type SuggestionsResponse };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ var n=class extends Error{status;detail;constructor(t,e,r){super(t),this.name="SearchError",this.status=e,this.detail=r??t;}};var u="https://api.skawr.com",g=1e4,a=class{baseUrl;publicKey;timeout;constructor(t){if(!t.publicKey)throw new Error("publicKey is required");this.baseUrl=(t.baseUrl??u).replace(/\/+$/,""),this.publicKey=t.publicKey,this.timeout=t.timeout??g;}async search(t,e){return this.post("/api/v1/search",{query:t,filters:e?.filters,page:e?.page,per_page:e?.per_page,sort_by:e?.sort_by,highlight_matches:e?.highlight_matches??true,result_format:e?.result_format})}async suggest(t,e){let r={q:t};return e?.limit!==void 0&&(r.limit=String(e.limit)),e?.include_trending!==void 0&&(r.include_trending=String(e.include_trending)),this.get("/api/v1/search/suggestions",r)}async autocomplete(t,e){let r={q:t};return e?.limit!==void 0&&(r.limit=String(e.limit)),this.get("/api/v1/autocomplete",r)}async get(t,e){let r=`${this.baseUrl}${t}`;if(e){let s=new URLSearchParams(e).toString();s&&(r+=`?${s}`);}return this.request(r,{method:"GET"})}async post(t,e){return this.request(`${this.baseUrl}${t}`,{method:"POST",body:JSON.stringify(e)})}async request(t,e){let r={"X-API-Key":this.publicKey,Accept:"application/json"};e.body&&(r["Content-Type"]="application/json");let s;try{s=await fetch(t,{...e,headers:r,signal:AbortSignal.timeout(this.timeout)});}catch(i){throw i instanceof DOMException&&i.name==="TimeoutError"?new n("Request timed out",0,"Request timed out"):i}if(!s.ok){let i=await s.text(),o;try{let c=JSON.parse(i);o=typeof c.detail=="string"?c.detail:i;}catch{o=i||s.statusText;}throw new n(o,s.status,o)}return await s.json()}};
2
+ export{n as SearchError,a as SkawrSearch};//# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":["SearchError","message","status","detail","DEFAULT_BASE_URL","DEFAULT_TIMEOUT","SkawrSearch","config","query","options","params","path","url","qs","body","init","headers","response","error","text","parsed"],"mappings":"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","file":"index.js","sourcesContent":["export class SearchError extends Error {\n readonly status: number;\n readonly detail: string;\n\n constructor(message: string, status: number, detail?: string) {\n super(message);\n this.name = 'SearchError';\n this.status = status;\n this.detail = detail ?? message;\n }\n}\n","import { SearchError } from './errors.js';\nimport type {\n SkawrSearchConfig,\n SearchOptions,\n SearchResponse,\n SuggestOptions,\n SuggestionsResponse,\n AutocompleteOptions,\n AutocompleteResponse,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.skawr.com';\nconst DEFAULT_TIMEOUT = 10_000;\n\nexport class SkawrSearch {\n private readonly baseUrl: string;\n private readonly publicKey: string;\n private readonly timeout: number;\n\n constructor(config: SkawrSearchConfig) {\n if (!config.publicKey) {\n throw new Error('publicKey is required');\n }\n\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n this.publicKey = config.publicKey;\n this.timeout = config.timeout ?? DEFAULT_TIMEOUT;\n }\n\n async search(query: string, options?: SearchOptions): Promise<SearchResponse> {\n return this.post<SearchResponse>('/api/v1/search', {\n query,\n filters: options?.filters,\n page: options?.page,\n per_page: options?.per_page,\n sort_by: options?.sort_by,\n highlight_matches: options?.highlight_matches ?? true,\n result_format: options?.result_format,\n });\n }\n\n async suggest(query: string, options?: SuggestOptions): Promise<SuggestionsResponse> {\n const params: Record<string, string> = { q: query };\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.include_trending !== undefined) params.include_trending = String(options.include_trending);\n\n return this.get<SuggestionsResponse>('/api/v1/search/suggestions', params);\n }\n\n async autocomplete(query: string, options?: AutocompleteOptions): Promise<AutocompleteResponse> {\n const params: Record<string, string> = { q: query };\n if (options?.limit !== undefined) params.limit = String(options.limit);\n\n return this.get<AutocompleteResponse>('/api/v1/autocomplete', params);\n }\n\n private async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n let url = `${this.baseUrl}${path}`;\n if (params) {\n const qs = new URLSearchParams(params).toString();\n if (qs) url += `?${qs}`;\n }\n\n return this.request<T>(url, { method: 'GET' });\n }\n\n private async post<T>(path: string, body: unknown): Promise<T> {\n return this.request<T>(`${this.baseUrl}${path}`, {\n method: 'POST',\n body: JSON.stringify(body),\n });\n }\n\n private async request<T>(url: string, init: RequestInit): Promise<T> {\n const headers: Record<string, string> = {\n 'X-API-Key': this.publicKey,\n 'Accept': 'application/json',\n };\n\n if (init.body) {\n headers['Content-Type'] = 'application/json';\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n ...init,\n headers,\n signal: AbortSignal.timeout(this.timeout),\n });\n } catch (error) {\n if (error instanceof DOMException && error.name === 'TimeoutError') {\n throw new SearchError('Request timed out', 0, 'Request timed out');\n }\n throw error;\n }\n\n if (!response.ok) {\n const text = await response.text();\n let detail: string;\n try {\n const parsed = JSON.parse(text);\n detail = typeof parsed.detail === 'string' ? parsed.detail : text;\n } catch {\n detail = text || response.statusText;\n }\n throw new SearchError(detail, response.status, detail);\n }\n\n return (await response.json()) as T;\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@skawr/search",
3
+ "version": "0.1.0",
4
+ "description": "Official SKAWR browser search SDK — lightweight, search-only client",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ }
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "sideEffects": false,
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "dev": "tsup --watch",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest",
26
+ "typecheck": "tsc --noEmit",
27
+ "prepublishOnly": "npm run build"
28
+ },
29
+ "devDependencies": {
30
+ "tsup": "^8.0.0",
31
+ "typescript": "^5.4.0",
32
+ "vitest": "^2.0.0"
33
+ },
34
+ "engines": {
35
+ "node": ">=18.0.0"
36
+ },
37
+ "keywords": [
38
+ "skawr",
39
+ "search",
40
+ "frontend",
41
+ "browser",
42
+ "autocomplete"
43
+ ],
44
+ "license": "MIT",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/skawr/skawr-sdk-search"
48
+ }
49
+ }