libsql-search 0.9.0 → 0.10.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 CHANGED
@@ -26,11 +26,23 @@ npm install libsql-search @libsql/client
26
26
  ```
27
27
 
28
28
  ```bash
29
- deno add jsr:@logan/libsql-search npm:@libsql/client
29
+ deno add jsr:@logan/libsql-search npm:@libsql/client@^0.17.0
30
30
  ```
31
31
 
32
32
  For npm usage, the package requires Node `>=22.12.0`.
33
33
 
34
+ `@tursodatabase/database` is supported as an **optional** peer, behind the separate `libsql-search/turso` entry point. It is experimental and exact-search-only, because Turso Database has no ANN vector index. Nothing is installed or resolved for it unless you opt in — see the [Turso Database backend guide](./docs/TURSO.md).
35
+
36
+ **On npm/pnpm**, the peer range is `@libsql/client ^0.15.0 || ^0.17.0`. Both lines are supported: every behavior this package depends on — `vector_top_k()`'s result shape, the vector index error wording that `search()` matches on, and transactional `batch()` rollback — is identical across them, so an existing `0.15.x` install does not have to move. There is no `0.16.x` line upstream, which is why the range is a disjunction rather than a span. The packaged build is smoke-tested against both arms on every release, at the newest release each arm admits (currently `0.15.15` and `0.17.4`).
37
+
38
+ **On JSR/Deno the range does not apply to you.** `deno.json` declares no dependency on `@libsql/client` — this package imports only its *types* — so the client you `deno add` separately is constrained by nothing on our side, and a plain `deno add npm:@libsql/client` will silently take whatever is newest, including a future major we have never tested. Deno also cannot express our range: `npm:@libsql/client@^0.15.0 || ^0.17.0` is a parse error, as is any `>=`/`<` span. Pin an arm yourself instead:
39
+
40
+ ```bash
41
+ deno add jsr:@logan/libsql-search npm:@libsql/client@^0.17.0
42
+ ```
43
+
44
+ Note for `0.17.x`: the client no longer exports `./package.json`, so `require("@libsql/client/package.json")` throws `ERR_PACKAGE_PATH_NOT_EXPORTED`. Nothing in this package reads it, but tooling of yours that inspected the client manifest by specifier needs a direct `node_modules` path instead. See [`@libsql/client` version differences](./docs/TROUBLESHOOTING.md#libsqlclient-version-differences) for the other upgrade-visible change.
45
+
34
46
  ## Quick Start
35
47
 
36
48
  This example uses the default local provider. Local embeddings run in-process after the initial model download and cache warmup; they are not automatically air-gapped.
@@ -99,7 +111,7 @@ await search({ client, query, exact: true });
99
111
 
100
112
  `exact: true` is the only way to guarantee exactness. Use it for small corpora, for correctness checks against the index path, and for tables that have no vector index.
101
113
 
102
- Requirements: `vector_top_k()` and `libsql_vector_idx()` need a libSQL build with native vector support. The peer dependency is `@libsql/client ^0.15.0`, verified against `0.15.15`; remote Turso/libSQL servers must support vector indexes as well. See the [API reference](./docs/API.md#searchoptions) for full semantics, and [Indexing and operations](./docs/INDEXING.md) for tables created before the index existed.
114
+ Requirements: `vector_top_k()` and `libsql_vector_idx()` need a libSQL build with native vector support. The peer dependency is `@libsql/client ^0.15.0 || ^0.17.0`, verified against `0.15.15` and `0.17.4`; remote Turso/libSQL servers must support vector indexes as well. See the [API reference](./docs/API.md#searchoptions) for full semantics, and [Indexing and operations](./docs/INDEXING.md) for tables created before the index existed.
103
115
 
104
116
  ## Providers
105
117
 
package/dist/index.cjs CHANGED
@@ -833,6 +833,48 @@ function normalizeVectorDimensions(dimensions) {
833
833
  return dimensions;
834
834
  }
835
835
 
836
+ function isDatabaseAdapter(client) {
837
+ return typeof client === "object" && client !== null && client.libsqlSearchAdapter === true;
838
+ }
839
+ function resolveDatabase(client) {
840
+ if (isDatabaseAdapter(client)) {
841
+ assertCompleteAdapter(client);
842
+ return client;
843
+ }
844
+ return createLibsqlAdapter(client);
845
+ }
846
+ const ADAPTER_METHODS = ["executeDdl", "executeQuery", "executeAtomicWrite"];
847
+ function assertCompleteAdapter(adapter) {
848
+ const missing = ADAPTER_METHODS.filter(
849
+ (method) => typeof adapter[method] !== "function"
850
+ );
851
+ if (missing.length > 0) {
852
+ throw new TypeError(
853
+ `This client is marked as a libsql-search database adapter but is missing ${missing.join(", ")}. The usual cause is two different versions of libsql-search resolved in one dependency tree, so the adapter was built by a different copy of the package than the one calling it. Deduplicate libsql-search, or build the adapter from the same copy you call.`
854
+ );
855
+ }
856
+ }
857
+ function createLibsqlAdapter(client) {
858
+ return {
859
+ libsqlSearchAdapter: true,
860
+ backend: "libsql",
861
+ supportsVectorIndex: true,
862
+ async executeDdl(sql) {
863
+ await client.execute(sql);
864
+ },
865
+ async executeQuery(sql, args) {
866
+ const result = args === void 0 ? await client.execute(sql) : await client.execute({ sql, args });
867
+ return result.rows;
868
+ },
869
+ async executeAtomicWrite(statements) {
870
+ const batch = statements.map(
871
+ (statement) => statement.args === void 0 ? statement.sql : statement
872
+ );
873
+ await client.batch(batch, "write");
874
+ }
875
+ };
876
+ }
877
+
836
878
  class IndexingError extends Error {
837
879
  phase;
838
880
  failures;
@@ -855,6 +897,7 @@ async function indexContent(options) {
855
897
  failurePolicy = "abort",
856
898
  allowEmptyIndex = false
857
899
  } = options;
900
+ const database = resolveDatabase(client);
858
901
  const quotedTableName = quoteSqlIdentifier(tableName, "tableName");
859
902
  let files;
860
903
  try {
@@ -928,7 +971,7 @@ async function indexContent(options) {
928
971
  );
929
972
  }
930
973
  const success = documents.length;
931
- await replaceIndex(client, quotedTableName, documents, failures);
974
+ await replaceIndex(database, quotedTableName, documents, failures);
932
975
  return {
933
976
  success,
934
977
  failed: failures.length,
@@ -1041,8 +1084,8 @@ function fallbackTitle(file) {
1041
1084
  function describeType(value) {
1042
1085
  return Array.isArray(value) ? "array" : typeof value;
1043
1086
  }
1044
- async function replaceIndex(client, quotedTableName, documents, failures) {
1045
- const statements = [`DELETE FROM ${quotedTableName}`];
1087
+ async function replaceIndex(database, quotedTableName, documents, failures) {
1088
+ const statements = [{ sql: `DELETE FROM ${quotedTableName}` }];
1046
1089
  try {
1047
1090
  for (let i = 0; i < documents.length; i++) {
1048
1091
  const document = documents[i];
@@ -1055,7 +1098,7 @@ async function replaceIndex(client, quotedTableName, documents, failures) {
1055
1098
  documents.length = 0;
1056
1099
  }
1057
1100
  try {
1058
- await client.batch(statements, "write");
1101
+ await database.executeAtomicWrite(statements);
1059
1102
  } catch (error) {
1060
1103
  throw new IndexingError(
1061
1104
  `Failed to replace the contents of ${quotedTableName}. The transaction was rolled back and the existing index was left unchanged.`,
@@ -1084,12 +1127,13 @@ function toError(error) {
1084
1127
  return error instanceof Error ? error : new Error(String(error));
1085
1128
  }
1086
1129
  async function createTable(client, tableName = "articles", dimensions = 384) {
1130
+ const database = resolveDatabase(client);
1087
1131
  const quotedTableName = quoteSqlIdentifier(tableName, "tableName");
1088
1132
  const vectorDimensions = normalizeVectorDimensions(dimensions);
1089
1133
  const quotedEmbeddingIndexName = quoteSqlIdentifier(`${tableName}_embedding_idx`, "embedding index name");
1090
1134
  const quotedFolderIndexName = quoteSqlIdentifier(`${tableName}_folder_idx`, "folder index name");
1091
1135
  const quotedSlugIndexName = quoteSqlIdentifier(`${tableName}_slug_idx`, "slug index name");
1092
- await client.execute(`
1136
+ await database.executeDdl(`
1093
1137
  CREATE TABLE IF NOT EXISTS ${quotedTableName} (
1094
1138
  id INTEGER PRIMARY KEY AUTOINCREMENT,
1095
1139
  slug TEXT UNIQUE NOT NULL,
@@ -1102,15 +1146,17 @@ async function createTable(client, tableName = "articles", dimensions = 384) {
1102
1146
  updated_at TEXT NOT NULL
1103
1147
  )
1104
1148
  `);
1105
- await client.execute(`
1106
- CREATE INDEX IF NOT EXISTS ${quotedEmbeddingIndexName}
1107
- ON ${quotedTableName}(libsql_vector_idx(embedding))
1108
- `);
1109
- await client.execute(`
1149
+ if (database.supportsVectorIndex) {
1150
+ await database.executeDdl(`
1151
+ CREATE INDEX IF NOT EXISTS ${quotedEmbeddingIndexName}
1152
+ ON ${quotedTableName}(libsql_vector_idx(embedding))
1153
+ `);
1154
+ }
1155
+ await database.executeDdl(`
1110
1156
  CREATE INDEX IF NOT EXISTS ${quotedFolderIndexName}
1111
1157
  ON ${quotedTableName}(folder)
1112
1158
  `);
1113
- await client.execute(`
1159
+ await database.executeDdl(`
1114
1160
  CREATE INDEX IF NOT EXISTS ${quotedSlugIndexName}
1115
1161
  ON ${quotedTableName}(slug)
1116
1162
  `);
@@ -1133,6 +1179,7 @@ async function search(options) {
1133
1179
  candidates,
1134
1180
  exact = false
1135
1181
  } = options;
1182
+ const database = resolveDatabase(client);
1136
1183
  const quotedTableName = quoteSqlIdentifier(tableName, "tableName");
1137
1184
  const resultLimit = normalizeSearchLimit(limit);
1138
1185
  const embeddingIndexName = validateSqlIdentifier(
@@ -1145,20 +1192,21 @@ async function search(options) {
1145
1192
  intent: embeddingOptions.intent ?? "query"
1146
1193
  });
1147
1194
  const queryVector = JSON.stringify(queryEmbedding);
1148
- const results = exact ? await executeExactSearch(client, quotedTableName, queryVector, resultLimit) : await executeIndexSearch(
1149
- client,
1195
+ const useExactSearch = exact || !database.supportsVectorIndex;
1196
+ const rows = useExactSearch ? await executeExactSearch(database, quotedTableName, queryVector, resultLimit) : await executeIndexSearch(
1197
+ database,
1150
1198
  quotedTableName,
1151
1199
  embeddingIndexName,
1152
1200
  queryVector,
1153
1201
  candidateCount,
1154
1202
  resultLimit
1155
1203
  );
1156
- return results.rows.map(toSearchResult);
1204
+ return rows.map(toSearchResult);
1157
1205
  }
1158
- async function executeIndexSearch(client, quotedTableName, embeddingIndexName, queryVector, candidateCount, resultLimit) {
1206
+ async function executeIndexSearch(database, quotedTableName, embeddingIndexName, queryVector, candidateCount, resultLimit) {
1159
1207
  try {
1160
- return await client.execute({
1161
- sql: `
1208
+ return await database.executeQuery(
1209
+ `
1162
1210
  SELECT
1163
1211
  ${RESULT_COLUMNS},
1164
1212
  vector_distance_cos(a.embedding, vector(:queryVector)) as distance
@@ -1167,20 +1215,20 @@ async function executeIndexSearch(client, quotedTableName, embeddingIndexName, q
1167
1215
  ORDER BY distance, a.id
1168
1216
  LIMIT :resultLimit
1169
1217
  `,
1170
- args: {
1218
+ {
1171
1219
  queryVector,
1172
1220
  indexName: embeddingIndexName,
1173
1221
  candidates: candidateCount,
1174
1222
  resultLimit
1175
1223
  }
1176
- });
1224
+ );
1177
1225
  } catch (error) {
1178
1226
  throw wrapIndexPathError(error, embeddingIndexName);
1179
1227
  }
1180
1228
  }
1181
- async function executeExactSearch(client, quotedTableName, queryVector, resultLimit) {
1182
- return client.execute({
1183
- sql: `
1229
+ async function executeExactSearch(database, quotedTableName, queryVector, resultLimit) {
1230
+ return database.executeQuery(
1231
+ `
1184
1232
  SELECT
1185
1233
  ${RESULT_COLUMNS},
1186
1234
  vector_distance_cos(a.embedding, vector(:queryVector)) as distance
@@ -1189,8 +1237,8 @@ async function executeExactSearch(client, quotedTableName, queryVector, resultLi
1189
1237
  ORDER BY distance, a.id
1190
1238
  LIMIT :resultLimit
1191
1239
  `,
1192
- args: { queryVector, resultLimit }
1193
- });
1240
+ { queryVector, resultLimit }
1241
+ );
1194
1242
  }
1195
1243
  function wrapIndexPathError(error, embeddingIndexName) {
1196
1244
  if (!(error instanceof Error)) {
@@ -1223,13 +1271,14 @@ function toSearchResult(row) {
1223
1271
  };
1224
1272
  }
1225
1273
  async function getAllArticles(client, tableName = "articles") {
1274
+ const database = resolveDatabase(client);
1226
1275
  const quotedTableName = quoteSqlIdentifier(tableName, "tableName");
1227
- const results = await client.execute(`
1276
+ const rows = await database.executeQuery(`
1228
1277
  SELECT id, slug, title, folder, tags, created_at, updated_at
1229
1278
  FROM ${quotedTableName}
1230
1279
  ORDER BY title
1231
1280
  `);
1232
- return results.rows.map((row) => ({
1281
+ return rows.map((row) => ({
1233
1282
  id: row.id,
1234
1283
  slug: row.slug,
1235
1284
  title: row.title,
@@ -1240,20 +1289,21 @@ async function getAllArticles(client, tableName = "articles") {
1240
1289
  }));
1241
1290
  }
1242
1291
  async function getArticleBySlug(client, slug, tableName = "articles") {
1292
+ const database = resolveDatabase(client);
1243
1293
  const quotedTableName = quoteSqlIdentifier(tableName, "tableName");
1244
- const results = await client.execute({
1245
- sql: `
1294
+ const rows = await database.executeQuery(
1295
+ `
1246
1296
  SELECT id, slug, title, content, folder, tags, created_at, updated_at
1247
1297
  FROM ${quotedTableName}
1248
1298
  WHERE slug = ?
1249
1299
  LIMIT 1
1250
1300
  `,
1251
- args: [slug]
1252
- });
1253
- if (results.rows.length === 0) {
1301
+ [slug]
1302
+ );
1303
+ if (rows.length === 0) {
1254
1304
  return null;
1255
1305
  }
1256
- const row = results.rows[0];
1306
+ const row = rows[0];
1257
1307
  return {
1258
1308
  id: row.id,
1259
1309
  slug: row.slug,
@@ -1266,17 +1316,18 @@ async function getArticleBySlug(client, slug, tableName = "articles") {
1266
1316
  };
1267
1317
  }
1268
1318
  async function getArticlesByFolder(client, folder, tableName = "articles") {
1319
+ const database = resolveDatabase(client);
1269
1320
  const quotedTableName = quoteSqlIdentifier(tableName, "tableName");
1270
- const results = await client.execute({
1271
- sql: `
1321
+ const rows = await database.executeQuery(
1322
+ `
1272
1323
  SELECT id, slug, title, folder, tags
1273
1324
  FROM ${quotedTableName}
1274
1325
  WHERE folder = ?
1275
1326
  ORDER BY title
1276
1327
  `,
1277
- args: [folder]
1278
- });
1279
- return results.rows.map((row) => ({
1328
+ [folder]
1329
+ );
1330
+ return rows.map((row) => ({
1280
1331
  id: row.id,
1281
1332
  slug: row.slug,
1282
1333
  title: row.title,
@@ -1285,13 +1336,14 @@ async function getArticlesByFolder(client, folder, tableName = "articles") {
1285
1336
  }));
1286
1337
  }
1287
1338
  async function getFolders(client, tableName = "articles") {
1339
+ const database = resolveDatabase(client);
1288
1340
  const quotedTableName = quoteSqlIdentifier(tableName, "tableName");
1289
- const results = await client.execute(`
1341
+ const rows = await database.executeQuery(`
1290
1342
  SELECT DISTINCT folder
1291
1343
  FROM ${quotedTableName}
1292
1344
  ORDER BY folder
1293
1345
  `);
1294
- return results.rows.map((row) => row.folder);
1346
+ return rows.map((row) => row.folder);
1295
1347
  }
1296
1348
 
1297
1349
  exports.DEFAULT_SEARCH_CANDIDATE_MULTIPLIER = DEFAULT_SEARCH_CANDIDATE_MULTIPLIER;
package/dist/index.d.ts CHANGED
@@ -78,6 +78,84 @@ declare function prepareTextForEmbedding(fields: {
78
78
  [key: string]: unknown;
79
79
  }): string;
80
80
 
81
+ /**
82
+ * Database backend boundary.
83
+ *
84
+ * Every SQL call this library makes goes through {@link DatabaseAdapter}. The
85
+ * `@libsql/client` adapter is built here, because that client is the declared
86
+ * peer dependency and the only backend the main entry point knows about. Other
87
+ * backends supply their own adapter from their own entry point, so the main
88
+ * bundle never imports, resolves, or references their package.
89
+ */
90
+
91
+ /**
92
+ * The narrow database contract the indexer, search, and retrieval helpers use.
93
+ *
94
+ * This interface is deliberately self-contained: it names no other type from
95
+ * this package and no type from any backend package. That keeps the declaration
96
+ * emitted into every entry point's `.d.ts` structurally identical, so an adapter
97
+ * built by one entry point is assignable to the parameter types of another
98
+ * without the two entry points sharing a nominal symbol.
99
+ *
100
+ * Do not brand this with a `unique symbol`. Each bundled `.d.ts` declares its
101
+ * own copy of the interface, and a `unique symbol` would make those copies
102
+ * nominally distinct — an adapter from the `libsql-search/turso` entry point
103
+ * would stop being assignable to `SearchOptions['client']`.
104
+ */
105
+ interface DatabaseAdapter {
106
+ /**
107
+ * Marker set by this package's adapter factories.
108
+ *
109
+ * Public functions accept either a raw `@libsql/client` `Client` or an
110
+ * adapter, and this property is how they tell the two apart. It is a plain
111
+ * property rather than structural method sniffing on purpose: guessing a
112
+ * backend from its method names would risk picking the wrong atomicity
113
+ * primitive, and the two backends disagree about which primitive is
114
+ * transactional.
115
+ */
116
+ readonly libsqlSearchAdapter: true;
117
+ /** Which backend this adapter drives. Informational; behavior keys off the capability flags. */
118
+ readonly backend: string;
119
+ /**
120
+ * Whether the backend can build a `libsql_vector_idx()` index and query it
121
+ * through `vector_top_k()`.
122
+ *
123
+ * When false, `createTable()` skips the vector index and `search()` runs the
124
+ * exact full-scan path automatically. Both are required, not optimizations:
125
+ * on a backend without the index, `CREATE INDEX ... libsql_vector_idx(...)`
126
+ * is a parse error and `vector_top_k` is not a table.
127
+ */
128
+ readonly supportsVectorIndex: boolean;
129
+ /** Run a schema statement that returns no rows. */
130
+ executeDdl(sql: string): Promise<void>;
131
+ /**
132
+ * Run one statement and return its rows as plain column-keyed objects.
133
+ *
134
+ * The bind-value union is spelled out inline rather than named, so that this
135
+ * interface stays free of any other symbol. It is narrower than `unknown` on
136
+ * purpose: it is the only compile-time check that a caller is binding
137
+ * something a SQLite driver can actually store.
138
+ */
139
+ executeQuery(sql: string, args?: Readonly<Record<string, string | number | bigint | Uint8Array | null>> | ReadonlyArray<string | number | bigint | Uint8Array | null>): Promise<Array<Record<string, unknown>>>;
140
+ /**
141
+ * Apply every statement atomically: either all of them commit, or none do.
142
+ *
143
+ * The whole "a failed rebuild leaves the previous index intact" guarantee
144
+ * rests on this method. A backend whose batch primitive is not transactional
145
+ * must implement this with an explicit transaction instead.
146
+ */
147
+ executeAtomicWrite(statements: ReadonlyArray<{
148
+ sql: string;
149
+ args?: ReadonlyArray<string | number | bigint | Uint8Array | null>;
150
+ }>): Promise<void>;
151
+ }
152
+ /**
153
+ * A client accepted by this library's public functions: either the
154
+ * `@libsql/client` client, or an adapter built by one of this package's
155
+ * adapter factories.
156
+ */
157
+ type DatabaseClient = Client | DatabaseAdapter;
158
+
81
159
  /**
82
160
  * Content indexer for markdown and other formats
83
161
  */
@@ -105,7 +183,11 @@ interface IndexFailure {
105
183
  error: Error;
106
184
  }
107
185
  interface IndexerOptions {
108
- client: Client;
186
+ /**
187
+ * A `@libsql/client` client, or an adapter from one of this package's
188
+ * backend entry points, such as `tursoAdapter()` from `libsql-search/turso`.
189
+ */
190
+ client: DatabaseClient;
109
191
  contentPath: string;
110
192
  embeddingOptions?: EmbeddingOptions;
111
193
  fileExtensions?: string[];
@@ -157,9 +239,14 @@ declare class IndexingError extends Error {
157
239
  */
158
240
  declare function indexContent(options: IndexerOptions): Promise<IndexResult>;
159
241
  /**
160
- * Create the articles table if it doesn't exist
242
+ * Create the articles table if it doesn't exist.
243
+ *
244
+ * Creates the table, the vector index, the folder index, and the slug index.
245
+ * The vector index is created only on backends that support
246
+ * `libsql_vector_idx()`; on Turso Database, which does not, everything else is
247
+ * still created and `search()` falls back to the exact full scan.
161
248
  */
162
- declare function createTable(client: Client, tableName?: string, dimensions?: number): Promise<void>;
249
+ declare function createTable(client: DatabaseClient, tableName?: string, dimensions?: number): Promise<void>;
163
250
 
164
251
  /**
165
252
  * Multiplier applied to `limit` when deriving the default candidate count.
@@ -187,7 +274,11 @@ declare const MAX_SEARCH_CANDIDATES: number;
187
274
  */
188
275
 
189
276
  interface SearchOptions {
190
- client: Client;
277
+ /**
278
+ * A `@libsql/client` client, or an adapter from one of this package's
279
+ * backend entry points, such as `tursoAdapter()` from `libsql-search/turso`.
280
+ */
281
+ client: DatabaseClient;
191
282
  query: string;
192
283
  limit?: number;
193
284
  tableName?: string;
@@ -206,6 +297,10 @@ interface SearchOptions {
206
297
  /**
207
298
  * Bypass the vector index and score every row instead. Exact but linear in
208
299
  * table size. Defaults to `false`.
300
+ *
301
+ * Backends with no vector index take this path whether or not it is set: on
302
+ * Turso Database `vector_top_k()` does not exist, so there is nothing to fall
303
+ * back from.
209
304
  */
210
305
  exact?: boolean;
211
306
  }
@@ -231,12 +326,16 @@ interface SearchResult {
231
326
  * deterministic even though the candidate set is not.
232
327
  *
233
328
  * Pass `exact: true` for a guaranteed-exact full scan.
329
+ *
330
+ * On a backend with no ANN vector index — Turso Database, reached through
331
+ * `tursoAdapter()` — the exact path is the only path, and is selected
332
+ * automatically without `exact: true`.
234
333
  */
235
334
  declare function search(options: SearchOptions): Promise<SearchResult[]>;
236
335
  /**
237
336
  * Get all articles (for building static pages, navigation, etc.)
238
337
  */
239
- declare function getAllArticles(client: Client, tableName?: string): Promise<Array<{
338
+ declare function getAllArticles(client: DatabaseClient, tableName?: string): Promise<Array<{
240
339
  id: number;
241
340
  slug: string;
242
341
  title: string;
@@ -248,7 +347,7 @@ declare function getAllArticles(client: Client, tableName?: string): Promise<Arr
248
347
  /**
249
348
  * Get a single article by slug
250
349
  */
251
- declare function getArticleBySlug(client: Client, slug: string, tableName?: string): Promise<{
350
+ declare function getArticleBySlug(client: DatabaseClient, slug: string, tableName?: string): Promise<{
252
351
  id: number;
253
352
  slug: string;
254
353
  title: string;
@@ -261,7 +360,7 @@ declare function getArticleBySlug(client: Client, slug: string, tableName?: stri
261
360
  /**
262
361
  * Get articles by folder
263
362
  */
264
- declare function getArticlesByFolder(client: Client, folder: string, tableName?: string): Promise<Array<{
363
+ declare function getArticlesByFolder(client: DatabaseClient, folder: string, tableName?: string): Promise<Array<{
265
364
  id: number;
266
365
  slug: string;
267
366
  title: string;
@@ -271,7 +370,7 @@ declare function getArticlesByFolder(client: Client, folder: string, tableName?:
271
370
  /**
272
371
  * Get all unique folders
273
372
  */
274
- declare function getFolders(client: Client, tableName?: string): Promise<string[]>;
373
+ declare function getFolders(client: DatabaseClient, tableName?: string): Promise<string[]>;
275
374
 
276
375
  export { DEFAULT_SEARCH_CANDIDATE_MULTIPLIER, IndexingError, MAX_SEARCH_CANDIDATES, MIN_SEARCH_CANDIDATES, createEmbeddingProvider, createTable, generateEmbedding, generateEmbeddings, getAllArticles, getArticleBySlug, getArticlesByFolder, getEmbeddingProviderMetadata, getFolders, indexContent, padEmbedding, prepareTextForEmbedding, search, validateEmbeddingBatch };
277
376
  export type { EmbeddingBatchBehavior, EmbeddingBatchItem, EmbeddingBatchItemResult, EmbeddingBatchMode, EmbeddingBatchResult, EmbeddingIntent, EmbeddingOptions, EmbeddingProvider, EmbeddingProviderClient, EmbeddingProviderMetadata, EmbeddingRequestOptions, IndexFailure, IndexFailurePolicy, IndexFailureStage, IndexResult, IndexedDocument, IndexerOptions, IndexingErrorPhase, SearchOptions, SearchResult };