libsql-search 0.2.0 → 0.2.1

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 CHANGED
@@ -74,8 +74,13 @@ function getOpenAIModel(dimensions) {
74
74
  function hasOwnProperty(value, property) {
75
75
  return Object.prototype.hasOwnProperty.call(value, property);
76
76
  }
77
- function redactErrorText(value) {
78
- const raw = value instanceof Error ? value.message : String(value);
77
+ function redactErrorText(value, exactSecrets = []) {
78
+ let raw = value instanceof Error ? value.message : String(value);
79
+ for (const secret of exactSecrets) {
80
+ if (secret.length > 0) {
81
+ raw = raw.split(secret).join("[redacted]");
82
+ }
83
+ }
79
84
  return raw.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [redacted]").replace(/([?&](?:api[_-]?key|key|token)=)[^&\s]+/gi, "$1[redacted]").replace(/(authorization\s*[:=]\s*)[^\s,}]+/gi, "$1[redacted]").replace(/https?:\/\/[^\s)]+/gi, (match) => {
80
85
  try {
81
86
  const url = new URL(match);
@@ -85,14 +90,14 @@ function redactErrorText(value) {
85
90
  }
86
91
  }).slice(0, 300);
87
92
  }
88
- function providerError(provider, message, cause) {
89
- const safeCause = cause === void 0 ? "" : `: ${redactErrorText(cause).trim()}`;
93
+ function providerError(provider, message, cause, exactSecrets = []) {
94
+ const safeCause = cause === void 0 ? "" : `: ${redactErrorText(cause, exactSecrets).trim()}`;
90
95
  return new Error(`${provider} embedding error: ${message}${safeCause}`);
91
96
  }
92
97
  function getResponseHeader(response, name) {
93
98
  return response.headers.get(name) ?? void 0;
94
99
  }
95
- async function withTimeout(provider, operation, timeoutMs, run, parentSignal) {
100
+ async function withTimeout(provider, operation, timeoutMs, run, parentSignal, exactSecrets = []) {
96
101
  if (parentSignal?.aborted) {
97
102
  throw providerError(provider, `${operation} was aborted`);
98
103
  }
@@ -124,7 +129,7 @@ async function withTimeout(provider, operation, timeoutMs, run, parentSignal) {
124
129
  if (error === abortError) {
125
130
  throw error;
126
131
  }
127
- throw providerError(provider, `${operation} failed`, error);
132
+ throw providerError(provider, `${operation} failed`, error, exactSecrets);
128
133
  } finally {
129
134
  clearTimeout(timeout);
130
135
  parentSignal?.removeEventListener("abort", onParentAbort);
@@ -182,6 +187,21 @@ function validateEmbeddingVector(embedding, expectedDimensions, provider, itemIn
182
187
  }
183
188
  return embedding;
184
189
  }
190
+ function throwIfAborted(provider, operation, signal) {
191
+ if (signal.aborted) {
192
+ throw providerError(provider, `${operation} was aborted`);
193
+ }
194
+ }
195
+ async function embedSequentially(provider, operation, texts, signal, embedOne) {
196
+ const results = [];
197
+ for (const text of texts) {
198
+ throwIfAborted(provider, operation, signal);
199
+ const embedding = await embedOne(text, signal);
200
+ throwIfAborted(provider, operation, signal);
201
+ results.push(embedding);
202
+ }
203
+ return results;
204
+ }
185
205
  function createProviderMetadata(provider, dimensions) {
186
206
  switch (provider) {
187
207
  case "local":
@@ -247,18 +267,16 @@ class LocalEmbeddingProvider {
247
267
  "local",
248
268
  "model inference",
249
269
  this.#timeoutMs,
250
- async () => {
270
+ async (signal) => {
251
271
  const model = await getLocalEmbeddingModel(this.metadata.model);
252
- const results = [];
253
- for (const text of texts) {
272
+ return embedSequentially("local", "model inference", texts, signal, async (text) => {
254
273
  const output = await model(text, {
255
274
  pooling: "mean",
256
275
  normalize: true
257
276
  });
258
277
  const embedding = Array.from(output.data);
259
- results.push(padEmbedding(embedding, this.metadata.dimensions));
260
- }
261
- return results;
278
+ return padEmbedding(embedding, this.metadata.dimensions);
279
+ });
262
280
  },
263
281
  options.signal
264
282
  );
@@ -288,22 +306,21 @@ class GeminiEmbeddingProvider {
288
306
  "gemini",
289
307
  "API request",
290
308
  this.#timeoutMs,
291
- async () => {
309
+ async (signal) => {
292
310
  const { GoogleGenerativeAI } = await import('@google/generative-ai');
293
311
  const genAI = new GoogleGenerativeAI(this.#apiKey);
294
312
  const model = genAI.getGenerativeModel({ model: this.metadata.model });
295
- const results = [];
296
- for (const text of texts) {
297
- const result = await model.embedContent(text);
313
+ return embedSequentially("gemini", "API request", texts, signal, async (text, itemSignal) => {
314
+ const result = await model.embedContent(text, { signal: itemSignal });
298
315
  const values = result.embedding?.values;
299
316
  if (!Array.isArray(values)) {
300
317
  throw new Error("Gemini response did not include embedding values");
301
318
  }
302
- results.push(values);
303
- }
304
- return results;
319
+ return values;
320
+ });
305
321
  },
306
- options.signal
322
+ options.signal,
323
+ [this.#apiKey]
307
324
  );
308
325
  return createEmbeddingBatchResult(
309
326
  this.metadata,
@@ -367,7 +384,8 @@ class OpenAIEmbeddingProvider {
367
384
  return parsed;
368
385
  });
369
386
  },
370
- options.signal
387
+ options.signal,
388
+ [this.#apiKey]
371
389
  );
372
390
  return createEmbeddingBatchResult(
373
391
  this.metadata,
package/dist/index.esm.js CHANGED
@@ -72,8 +72,13 @@ function getOpenAIModel(dimensions) {
72
72
  function hasOwnProperty(value, property) {
73
73
  return Object.prototype.hasOwnProperty.call(value, property);
74
74
  }
75
- function redactErrorText(value) {
76
- const raw = value instanceof Error ? value.message : String(value);
75
+ function redactErrorText(value, exactSecrets = []) {
76
+ let raw = value instanceof Error ? value.message : String(value);
77
+ for (const secret of exactSecrets) {
78
+ if (secret.length > 0) {
79
+ raw = raw.split(secret).join("[redacted]");
80
+ }
81
+ }
77
82
  return raw.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [redacted]").replace(/([?&](?:api[_-]?key|key|token)=)[^&\s]+/gi, "$1[redacted]").replace(/(authorization\s*[:=]\s*)[^\s,}]+/gi, "$1[redacted]").replace(/https?:\/\/[^\s)]+/gi, (match) => {
78
83
  try {
79
84
  const url = new URL(match);
@@ -83,14 +88,14 @@ function redactErrorText(value) {
83
88
  }
84
89
  }).slice(0, 300);
85
90
  }
86
- function providerError(provider, message, cause) {
87
- const safeCause = cause === void 0 ? "" : `: ${redactErrorText(cause).trim()}`;
91
+ function providerError(provider, message, cause, exactSecrets = []) {
92
+ const safeCause = cause === void 0 ? "" : `: ${redactErrorText(cause, exactSecrets).trim()}`;
88
93
  return new Error(`${provider} embedding error: ${message}${safeCause}`);
89
94
  }
90
95
  function getResponseHeader(response, name) {
91
96
  return response.headers.get(name) ?? void 0;
92
97
  }
93
- async function withTimeout(provider, operation, timeoutMs, run, parentSignal) {
98
+ async function withTimeout(provider, operation, timeoutMs, run, parentSignal, exactSecrets = []) {
94
99
  if (parentSignal?.aborted) {
95
100
  throw providerError(provider, `${operation} was aborted`);
96
101
  }
@@ -122,7 +127,7 @@ async function withTimeout(provider, operation, timeoutMs, run, parentSignal) {
122
127
  if (error === abortError) {
123
128
  throw error;
124
129
  }
125
- throw providerError(provider, `${operation} failed`, error);
130
+ throw providerError(provider, `${operation} failed`, error, exactSecrets);
126
131
  } finally {
127
132
  clearTimeout(timeout);
128
133
  parentSignal?.removeEventListener("abort", onParentAbort);
@@ -180,6 +185,21 @@ function validateEmbeddingVector(embedding, expectedDimensions, provider, itemIn
180
185
  }
181
186
  return embedding;
182
187
  }
188
+ function throwIfAborted(provider, operation, signal) {
189
+ if (signal.aborted) {
190
+ throw providerError(provider, `${operation} was aborted`);
191
+ }
192
+ }
193
+ async function embedSequentially(provider, operation, texts, signal, embedOne) {
194
+ const results = [];
195
+ for (const text of texts) {
196
+ throwIfAborted(provider, operation, signal);
197
+ const embedding = await embedOne(text, signal);
198
+ throwIfAborted(provider, operation, signal);
199
+ results.push(embedding);
200
+ }
201
+ return results;
202
+ }
183
203
  function createProviderMetadata(provider, dimensions) {
184
204
  switch (provider) {
185
205
  case "local":
@@ -245,18 +265,16 @@ class LocalEmbeddingProvider {
245
265
  "local",
246
266
  "model inference",
247
267
  this.#timeoutMs,
248
- async () => {
268
+ async (signal) => {
249
269
  const model = await getLocalEmbeddingModel(this.metadata.model);
250
- const results = [];
251
- for (const text of texts) {
270
+ return embedSequentially("local", "model inference", texts, signal, async (text) => {
252
271
  const output = await model(text, {
253
272
  pooling: "mean",
254
273
  normalize: true
255
274
  });
256
275
  const embedding = Array.from(output.data);
257
- results.push(padEmbedding(embedding, this.metadata.dimensions));
258
- }
259
- return results;
276
+ return padEmbedding(embedding, this.metadata.dimensions);
277
+ });
260
278
  },
261
279
  options.signal
262
280
  );
@@ -286,22 +304,21 @@ class GeminiEmbeddingProvider {
286
304
  "gemini",
287
305
  "API request",
288
306
  this.#timeoutMs,
289
- async () => {
307
+ async (signal) => {
290
308
  const { GoogleGenerativeAI } = await import('@google/generative-ai');
291
309
  const genAI = new GoogleGenerativeAI(this.#apiKey);
292
310
  const model = genAI.getGenerativeModel({ model: this.metadata.model });
293
- const results = [];
294
- for (const text of texts) {
295
- const result = await model.embedContent(text);
311
+ return embedSequentially("gemini", "API request", texts, signal, async (text, itemSignal) => {
312
+ const result = await model.embedContent(text, { signal: itemSignal });
296
313
  const values = result.embedding?.values;
297
314
  if (!Array.isArray(values)) {
298
315
  throw new Error("Gemini response did not include embedding values");
299
316
  }
300
- results.push(values);
301
- }
302
- return results;
317
+ return values;
318
+ });
303
319
  },
304
- options.signal
320
+ options.signal,
321
+ [this.#apiKey]
305
322
  );
306
323
  return createEmbeddingBatchResult(
307
324
  this.metadata,
@@ -365,7 +382,8 @@ class OpenAIEmbeddingProvider {
365
382
  return parsed;
366
383
  });
367
384
  },
368
- options.signal
385
+ options.signal,
386
+ [this.#apiKey]
369
387
  );
370
388
  return createEmbeddingBatchResult(
371
389
  this.metadata,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libsql-search",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
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",