libsql-search 0.1.5 → 0.2.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/docs/API.md CHANGED
@@ -12,12 +12,25 @@
12
12
  - `getArticlesByFolder`
13
13
  - `getFolders`
14
14
  - `generateEmbedding`
15
+ - `generateEmbeddings`
16
+ - `createEmbeddingProvider`
17
+ - `getEmbeddingProviderMetadata`
18
+ - `validateEmbeddingBatch`
15
19
  - `padEmbedding`
16
20
  - `prepareTextForEmbedding`
17
21
 
18
22
  It also exports these types:
19
23
 
20
24
  - `EmbeddingProvider`
25
+ - `EmbeddingIntent`
26
+ - `EmbeddingBatchMode`
27
+ - `EmbeddingBatchBehavior`
28
+ - `EmbeddingProviderMetadata`
29
+ - `EmbeddingRequestOptions`
30
+ - `EmbeddingProviderClient`
31
+ - `EmbeddingBatchResult`
32
+ - `EmbeddingBatchItemResult`
33
+ - `EmbeddingBatchItem`
21
34
  - `EmbeddingOptions`
22
35
  - `IndexerOptions`
23
36
  - `IndexedDocument`
@@ -37,6 +50,11 @@ Defaults:
37
50
  - `tableName`: `"articles"`
38
51
  - `dimensions`: `768`
39
52
 
53
+ `tableName` must be an ASCII SQLite identifier matching
54
+ `[A-Za-z_][A-Za-z0-9_]*`. Valid identifiers are quoted internally, so reserved
55
+ words such as `"select"` are safe to use. `dimensions` must be a positive
56
+ integer.
57
+
40
58
  The created schema includes:
41
59
 
42
60
  - `id` primary key
@@ -71,6 +89,8 @@ Defaults:
71
89
  - `exclude`: ["node_modules", ".git", "dist", "build"]
72
90
  - `tableName`: `"articles"`
73
91
 
92
+ `tableName` follows the same identifier policy as `createTable()`.
93
+
74
94
  Return shape:
75
95
 
76
96
  ```ts
@@ -86,6 +106,8 @@ Behavior notes:
86
106
  - `indexContent()` deletes existing rows in the target table before rebuilding
87
107
  - frontmatter `title`, `description`, and `tags` are folded into the embedding
88
108
  text
109
+ - embeddings default to `intent: "document"` unless `embeddingOptions.intent`
110
+ is set explicitly
89
111
  - if a file has no frontmatter title, the filename becomes the title
90
112
 
91
113
  ## `search(options)`
@@ -107,6 +129,10 @@ Defaults:
107
129
  - `limit`: `10`
108
130
  - `tableName`: `"articles"`
109
131
 
132
+ `limit` must be an integer from `1` through `100`; invalid values are rejected
133
+ before query embedding generation. `tableName` follows the same identifier
134
+ policy as `createTable()`.
135
+
110
136
  Result shape:
111
137
 
112
138
  ```ts
@@ -124,6 +150,9 @@ interface SearchResult {
124
150
 
125
151
  Lower `distance` values are better matches.
126
152
 
153
+ Search embeddings default to `intent: "query"` unless
154
+ `embeddingOptions.intent` is set explicitly.
155
+
127
156
  ## Article Retrieval Helpers
128
157
 
129
158
  ### `getAllArticles(client, tableName?)`
@@ -142,12 +171,99 @@ Returns articles in a specific folder.
142
171
 
143
172
  Returns distinct folder names from the index.
144
173
 
174
+ All article retrieval helpers validate `tableName` before executing SQL.
175
+
145
176
  ## Embedding Helpers
146
177
 
147
178
  ### `generateEmbedding(text, options?)`
148
179
 
149
180
  Generates an embedding for arbitrary text using the selected provider.
150
181
 
182
+ ### `generateEmbeddings(texts, options?)`
183
+
184
+ Generates an ordered batch of embeddings. Empty batches return `[]` without
185
+ creating a hosted provider client or making a network request.
186
+
187
+ ### `createEmbeddingProvider(options?)`
188
+
189
+ Creates a provider client with immutable metadata and an `embed(texts, options?)`
190
+ method. Provider clients return a rich `EmbeddingBatchResult`; the compatibility
191
+ helpers `generateEmbedding()` and `generateEmbeddings()` continue returning only
192
+ vectors.
193
+
194
+ ```ts
195
+ const provider = createEmbeddingProvider({
196
+ provider: "openai",
197
+ apiKey: process.env.OPENAI_API_KEY,
198
+ dimensions: 1536,
199
+ });
200
+
201
+ console.log(provider.metadata);
202
+ ```
203
+
204
+ Provider metadata includes:
205
+
206
+ - `name`
207
+ - `model`
208
+ - `dimensions`
209
+ - `batch.mode`
210
+ - `batch.maxSize`, when the provider has a hard maximum
211
+
212
+ Hosted provider clients are scoped to their options. The library does not reuse
213
+ a Gemini or OpenAI client created with a different API key or configuration.
214
+
215
+ ### `getEmbeddingProviderMetadata(options?)`
216
+
217
+ Returns the same metadata exposed by `createEmbeddingProvider(options).metadata`
218
+ without resolving hosted-provider credentials.
219
+
220
+ Provider batch metadata uses:
221
+
222
+ ```ts
223
+ type EmbeddingBatchMode = "native" | "sequential";
224
+
225
+ interface EmbeddingBatchBehavior {
226
+ mode: EmbeddingBatchMode;
227
+ maxSize?: number;
228
+ }
229
+ ```
230
+
231
+ `"native"` means the upstream provider accepts the batch in one request.
232
+ `"sequential"` means the library accepts an input batch but processes items one
233
+ at a time. If `maxSize` is present, the library enforces it before provider or
234
+ network work.
235
+
236
+ Provider clients return:
237
+
238
+ ```ts
239
+ interface EmbeddingBatchResult {
240
+ embeddings: number[][];
241
+ provider: "local" | "gemini" | "openai";
242
+ model: string;
243
+ dimensions: number;
244
+ intent: "document" | "query";
245
+ }
246
+ ```
247
+
248
+ ### `validateEmbeddingBatch(items, expectedCount, expectedDimensions, provider)`
249
+
250
+ Validates provider results before they are written to the database. It checks
251
+ cardinality, dimensions, finite numeric values, and indexed batch ordering.
252
+
253
+ `EmbeddingOptions` supports:
254
+
255
+ ```ts
256
+ interface EmbeddingOptions {
257
+ provider?: "local" | "gemini" | "openai";
258
+ apiKey?: string;
259
+ dimensions?: number;
260
+ maxLength?: number;
261
+ intent?: "document" | "query";
262
+ timeoutMs?: number;
263
+ signal?: AbortSignal;
264
+ }
265
+ ```
266
+
151
267
  ### `padEmbedding(embedding, targetDimensions)`
152
268
 
153
269
  Pads or truncates an embedding array to the requested length.
package/docs/INDEXING.md CHANGED
@@ -57,8 +57,10 @@ site build:
57
57
 
58
58
  ## Table Names
59
59
 
60
- `tableName` is interpolated into SQL. Treat it as a trusted identifier coming
61
- from your own configuration, not from user input.
60
+ `tableName` must be an ASCII SQLite identifier matching
61
+ `[A-Za-z_][A-Za-z0-9_]*`. Valid names are quoted internally for table and index
62
+ SQL, so reserved words such as `"select"` work safely. Invalid names fail before
63
+ database calls or embedding generation.
62
64
 
63
65
  ## Runtime Notes
64
66
 
package/docs/PROVIDERS.md CHANGED
@@ -18,15 +18,74 @@ interface EmbeddingOptions {
18
18
  apiKey?: string;
19
19
  dimensions?: number;
20
20
  maxLength?: number;
21
+ intent?: "document" | "query";
22
+ timeoutMs?: number;
23
+ signal?: AbortSignal;
21
24
  }
22
25
  ```
23
26
 
24
27
  - `provider` defaults to `"local"`
25
28
  - `dimensions` defaults to `768`
26
29
  - `maxLength` defaults to `8000`
30
+ - `intent` can be `"document"` or `"query"`; indexing defaults to
31
+ `"document"` and search defaults to `"query"` unless explicitly set
32
+ - `timeoutMs` defaults to `30000`
27
33
  - `apiKey` is optional in code, but required for hosted providers unless the
28
34
  matching environment variable is available
29
35
 
36
+ ## Provider Contract
37
+
38
+ Each provider exposes immutable metadata:
39
+
40
+ ```ts
41
+ interface EmbeddingProviderMetadata {
42
+ name: "local" | "gemini" | "openai";
43
+ model: string;
44
+ dimensions: number;
45
+ batch: {
46
+ mode: "native" | "sequential";
47
+ maxSize?: number;
48
+ };
49
+ }
50
+ ```
51
+
52
+ Use `getEmbeddingProviderMetadata(options)` or
53
+ `createEmbeddingProvider(options).metadata` to inspect the effective model,
54
+ dimensions, and batch behavior. Metadata inspection does not require hosted
55
+ provider credentials.
56
+
57
+ Batch modes:
58
+
59
+ - `"native"` means the upstream provider accepts the batch in one request
60
+ - `"sequential"` means the library accepts a batch and processes items one at a
61
+ time
62
+ - when `maxSize` is present, it is a hard maximum enforced before provider or
63
+ network work
64
+
65
+ `generateEmbeddings(texts, options)` returns vectors in the same order as the
66
+ input texts. Provider responses are validated before database writes:
67
+
68
+ - result count must match input count
69
+ - each vector must match the provider's effective dimensions
70
+ - every vector value must be a finite number
71
+ - indexed batch responses must contain unique contiguous indices and are
72
+ reordered before being returned
73
+
74
+ Empty batches return `[]` without loading a local model, creating hosted clients,
75
+ or making network calls.
76
+
77
+ Lower-level provider clients return an `EmbeddingBatchResult` with the validated
78
+ vectors plus provider, model, dimensions, and intent. The compatibility helpers
79
+ `generateEmbedding()` and `generateEmbeddings()` return only arrays.
80
+
81
+ Gemini and OpenAI clients are scoped to their current options. They are not
82
+ cached globally across different credentials or configurations. The local Xenova
83
+ model can be cached by model name.
84
+
85
+ Hosted provider failures are reported with bounded provider/status/request-id
86
+ context and without raw upstream bodies, credentials, Authorization headers, or
87
+ full URLs with query strings.
88
+
30
89
  ## Local
31
90
 
32
91
  Provider value: `local`
@@ -45,6 +104,8 @@ Notes:
45
104
 
46
105
  - the model emits 384 dimensions and `libsql-search` pads or truncates to your
47
106
  requested size
107
+ - metadata reports the requested output dimensions
108
+ - batch metadata is `{ mode: "sequential" }`
48
109
  - the first run downloads the model and can take longer on a fresh machine
49
110
  - no API key is required
50
111
 
@@ -65,6 +126,8 @@ Behavior:
65
126
 
66
127
  - if `apiKey` is omitted, the library reads `GEMINI_API_KEY`
67
128
  - Gemini returns 768 dimensions natively
129
+ - metadata reports `text-embedding-004` and 768 dimensions
130
+ - batch metadata is `{ mode: "sequential" }`
68
131
  - the current implementation does not expose model selection
69
132
 
70
133
  ## OpenAI
@@ -86,6 +149,9 @@ Behavior:
86
149
 
87
150
  - if `apiKey` is omitted, the library reads `OPENAI_API_KEY`
88
151
  - the request sends the `dimensions` value to the OpenAI embeddings API
152
+ - metadata reports `text-embedding-3-small` when `dimensions <= 1536` and
153
+ `text-embedding-3-large` when `dimensions > 1536`
154
+ - batch metadata is `{ mode: "native", maxSize: 2048 }`
89
155
  - use the same dimension count in `createTable()`
90
156
 
91
157
  ## Dimension Guidelines
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libsql-search",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "description": "Semantic search for static sites using libSQL/Turso with multi-provider embeddings",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.34.5",