libsql-search 0.1.4 → 0.1.6

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.
@@ -0,0 +1,143 @@
1
+ # Integration Examples
2
+
3
+ These examples show the current exported API wired into typical server-side
4
+ routes. They are intentionally small so you can adapt them to your app.
5
+
6
+ ## Astro Search Endpoint
7
+
8
+ ```ts
9
+ import type { APIRoute } from "astro";
10
+ import { createClient } from "@libsql/client";
11
+ import { search } from "libsql-search";
12
+
13
+ export const prerender = false;
14
+
15
+ const client = createClient({
16
+ url: import.meta.env.TURSO_DB_URL,
17
+ authToken: import.meta.env.TURSO_AUTH_TOKEN,
18
+ });
19
+
20
+ export const POST: APIRoute = async ({ request }) => {
21
+ const { query, limit = 10 } = await request.json();
22
+
23
+ const results = await search({
24
+ client,
25
+ query,
26
+ limit,
27
+ embeddingOptions: {
28
+ provider: "local",
29
+ dimensions: 768,
30
+ },
31
+ });
32
+
33
+ return new Response(JSON.stringify({ results }), {
34
+ headers: { "Content-Type": "application/json" },
35
+ });
36
+ };
37
+ ```
38
+
39
+ ## Astro Static Paths
40
+
41
+ ```ts
42
+ import { createClient } from "@libsql/client";
43
+ import { getAllArticles, getArticleBySlug } from "libsql-search";
44
+
45
+ const client = createClient({
46
+ url: import.meta.env.TURSO_DB_URL,
47
+ authToken: import.meta.env.TURSO_AUTH_TOKEN,
48
+ });
49
+
50
+ export async function getStaticPaths() {
51
+ const articles = await getAllArticles(client);
52
+
53
+ return articles.map((article) => ({
54
+ params: { slug: article.slug },
55
+ }));
56
+ }
57
+
58
+ const article = await getArticleBySlug(client, "guides/getting-started");
59
+ ```
60
+
61
+ ## Next.js Route Handler
62
+
63
+ ```ts
64
+ import { createClient } from "@libsql/client";
65
+ import { search } from "libsql-search";
66
+ import { NextRequest } from "next/server";
67
+
68
+ const client = createClient({
69
+ url: process.env.TURSO_DB_URL!,
70
+ authToken: process.env.TURSO_AUTH_TOKEN!,
71
+ });
72
+
73
+ export async function POST(request: NextRequest) {
74
+ const { query, limit = 10 } = await request.json();
75
+
76
+ const results = await search({
77
+ client,
78
+ query,
79
+ limit,
80
+ embeddingOptions: {
81
+ provider: "local",
82
+ dimensions: 768,
83
+ },
84
+ });
85
+
86
+ return Response.json({ results });
87
+ }
88
+ ```
89
+
90
+ ## Next.js Static Params
91
+
92
+ ```tsx
93
+ import { createClient } from "@libsql/client";
94
+ import { getAllArticles, getArticleBySlug } from "libsql-search";
95
+
96
+ const client = createClient({
97
+ url: process.env.TURSO_DB_URL!,
98
+ authToken: process.env.TURSO_AUTH_TOKEN!,
99
+ });
100
+
101
+ export async function generateStaticParams() {
102
+ const articles = await getAllArticles(client);
103
+
104
+ return articles.map((article) => ({
105
+ slug: article.slug,
106
+ }));
107
+ }
108
+
109
+ export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
110
+ const { slug } = await params;
111
+ const article = await getArticleBySlug(client, slug);
112
+
113
+ return <article>{article?.title}</article>;
114
+ }
115
+ ```
116
+
117
+ ## Build-Time Index Script
118
+
119
+ A small script is usually enough to rebuild the index before a site build.
120
+
121
+ ```ts
122
+ import { createClient } from "@libsql/client";
123
+ import { createTable, indexContent } from "libsql-search";
124
+
125
+ const client = createClient({
126
+ url: process.env.TURSO_DB_URL!,
127
+ authToken: process.env.TURSO_AUTH_TOKEN!,
128
+ });
129
+
130
+ await createTable(client, "articles", 768);
131
+
132
+ await indexContent({
133
+ client,
134
+ contentPath: "./content",
135
+ embeddingOptions: {
136
+ provider: process.env.EMBEDDING_PROVIDER as "local" | "gemini" | "openai" | undefined,
137
+ dimensions: 768,
138
+ },
139
+ });
140
+ ```
141
+
142
+ Pair this with your framework build command so indexed content and deployed code
143
+ stay in sync.
@@ -0,0 +1,100 @@
1
+ # Embedding Providers
2
+
3
+ `libsql-search` currently supports three embedding providers:
4
+
5
+ - `local`
6
+ - `gemini`
7
+ - `openai`
8
+
9
+ Use the same provider and dimensions for both indexing and querying. A mismatch
10
+ between stored vectors and query vectors will break search quality or fail at
11
+ query time.
12
+
13
+ ## Shared Options
14
+
15
+ ```ts
16
+ interface EmbeddingOptions {
17
+ provider?: "local" | "gemini" | "openai";
18
+ apiKey?: string;
19
+ dimensions?: number;
20
+ maxLength?: number;
21
+ }
22
+ ```
23
+
24
+ - `provider` defaults to `"local"`
25
+ - `dimensions` defaults to `768`
26
+ - `maxLength` defaults to `8000`
27
+ - `apiKey` is optional in code, but required for hosted providers unless the
28
+ matching environment variable is available
29
+
30
+ ## Local
31
+
32
+ Provider value: `local`
33
+
34
+ The local provider loads `Xenova/all-MiniLM-L6-v2` through
35
+ `@xenova/transformers`.
36
+
37
+ ```ts
38
+ embeddingOptions: {
39
+ provider: "local",
40
+ dimensions: 768,
41
+ }
42
+ ```
43
+
44
+ Notes:
45
+
46
+ - the model emits 384 dimensions and `libsql-search` pads or truncates to your
47
+ requested size
48
+ - the first run downloads the model and can take longer on a fresh machine
49
+ - no API key is required
50
+
51
+ ## Gemini
52
+
53
+ Provider value: `gemini`
54
+
55
+ Gemini uses Google `text-embedding-004`.
56
+
57
+ ```ts
58
+ embeddingOptions: {
59
+ provider: "gemini",
60
+ apiKey: process.env.GEMINI_API_KEY,
61
+ }
62
+ ```
63
+
64
+ Behavior:
65
+
66
+ - if `apiKey` is omitted, the library reads `GEMINI_API_KEY`
67
+ - Gemini returns 768 dimensions natively
68
+ - the current implementation does not expose model selection
69
+
70
+ ## OpenAI
71
+
72
+ Provider value: `openai`
73
+
74
+ OpenAI uses `text-embedding-3-small` when `dimensions <= 1536` and
75
+ `text-embedding-3-large` when `dimensions > 1536`.
76
+
77
+ ```ts
78
+ embeddingOptions: {
79
+ provider: "openai",
80
+ apiKey: process.env.OPENAI_API_KEY,
81
+ dimensions: 1536,
82
+ }
83
+ ```
84
+
85
+ Behavior:
86
+
87
+ - if `apiKey` is omitted, the library reads `OPENAI_API_KEY`
88
+ - the request sends the `dimensions` value to the OpenAI embeddings API
89
+ - use the same dimension count in `createTable()`
90
+
91
+ ## Dimension Guidelines
92
+
93
+ - `768` is the easiest cross-provider target in the current implementation
94
+ - local embeddings are padded from 384 to your target size
95
+ - Gemini stays at 768
96
+ - OpenAI can be used at 1536 or 3072, or another supported OpenAI dimension
97
+ value you explicitly set
98
+
99
+ If you switch provider or dimensions for an existing table, recreate the table
100
+ or rebuild the index into a separate table so stored vectors stay consistent.
package/docs/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # Documentation
2
+
3
+ This directory holds the longer-form reference material for `libsql-search`.
4
+ Start with the page that matches the job you are doing:
5
+
6
+ - [Provider guide](./PROVIDERS.md): local, Gemini, and OpenAI embedding options,
7
+ dimensions, and API key behavior
8
+ - [API reference](./API.md): exported functions, option shapes, and result data
9
+ - [Integration examples](./INTEGRATIONS.md): Astro and Next.js server-side usage
10
+ - [Indexing and operations](./INDEXING.md): content layout, rebuild scripts,
11
+ search quality tips, and indexing gotchas
12
+ - [Troubleshooting](./TROUBLESHOOTING.md): known install/runtime issues
13
+ - [Releasing](./RELEASING.md): maintainer release workflow
14
+
15
+ For the shortest first-use path, go back to the repository
16
+ [README](../README.md).
@@ -0,0 +1,91 @@
1
+ # Releasing
2
+
3
+ Normal releases are automatic. Merge a reviewed PR to `main`; the `Publish
4
+ Package` workflow decides the next stable SemVer version, creates any required
5
+ manifest-only release commit, creates an annotated `vX.Y.Z` tag, publishes npm
6
+ and JSR, then creates GitHub Release notes after both registries succeed.
7
+
8
+ ## Automatic release flow
9
+
10
+ 1. Every push to `main` starts `.github/workflows/publish.yml`.
11
+ 2. The workflow ignores self-generated `chore(release): ...` commits.
12
+ 3. A serialized release-writer job fetches the current `origin/main` after it
13
+ has the release slot. If `origin/main` moved beyond the triggering commit,
14
+ that older run exits and the newer run handles the accumulated changes.
15
+ 4. The release planner compares commits since the highest stable `vX.Y.Z` tag
16
+ merged into the release commit. Higher tags that are not reachable from
17
+ `main` are ignored so a stray or divergent tag cannot make the default
18
+ release line jump. Commits whose changed files are confined to `docs/**` or
19
+ `.github/**` do not count as release-eligible and do not affect the bump. If
20
+ the newest `main` commit is docs-only but an earlier untagged code or README
21
+ commit is still pending, that newest run releases the accumulated eligible
22
+ changes. Breaking changes bump major, `feat:` bumps minor, and all other
23
+ eligible commits bump patch.
24
+ 5. `package.json`, `jsr.json`, and `deno.json` are synchronized to the chosen
25
+ version. If they already match the chosen version, no release commit is
26
+ created.
27
+ 6. The workflow validates the candidate, creates an annotated tag, and atomically
28
+ pushes the release commit plus tag.
29
+ 7. npm publishes `libsql-search` through trusted publishing OIDC with the GitHub
30
+ environment named `npm`.
31
+ 8. JSR publishes `@logan/libsql-search` through a separate OIDC job.
32
+ 9. GitHub Release notes are generated only after both registry jobs complete.
33
+
34
+ The current bootstrap case is supported: if the latest tag is `v0.1.3` and the
35
+ manifests already say `0.1.4`, the first qualifying `main` release tags and
36
+ publishes `v0.1.4` without creating an empty release commit.
37
+
38
+ ## Manual overrides
39
+
40
+ Manual version and tag commands are overrides, not the default path. Use them
41
+ only when you intentionally need to publish a specific already-reviewed `main`
42
+ commit.
43
+
44
+ 1. Synchronize `package.json`, `jsr.json`, and `deno.json` to the target
45
+ `X.Y.Z` version.
46
+ 2. Merge that manifest change to `main`.
47
+ 3. Create annotated tag `vX.Y.Z` on the merged `main` commit.
48
+ 4. Push the tag.
49
+
50
+ The same `Publish Package` workflow validates manual tags before publishing. It
51
+ checks that the tag target is on `origin/main`, that the tag and manifests agree,
52
+ and that the remote tag still resolves to the checked-out commit immediately
53
+ before each registry publish.
54
+
55
+ ## Recovery dispatch
56
+
57
+ Use the guarded workflow dispatch path when an existing `vX.Y.Z` tag needs a
58
+ registry or GitHub Release recovery without creating a new version. Example:
59
+
60
+ ```bash
61
+ gh workflow run publish.yml --ref main -f release_tag=v0.1.4
62
+ ```
63
+
64
+ Dispatch validates that `release_tag` is strict `vX.Y.Z`, fetches the remote tag,
65
+ peels it to a commit, checks that commit is on `origin/main`, checks manifests
66
+ against the tag, and then publishes from the tag target SHA. Unlike a tag-push
67
+ run, dispatch does not require the tag target to equal the workflow dispatch
68
+ SHA; this allows a newer `main` workflow fix to recover an older release tag.
69
+
70
+ npm and GitHub Release recovery steps remain idempotent and skip when the
71
+ version or release already exists. JSR recovery always invokes
72
+ `pnpm dlx jsr@0.14.3 publish`; do not use `deno info jsr:...` as an existence
73
+ gate, because it can resolve successfully even when the public JSR package
74
+ version metadata is not actually published.
75
+
76
+ ## GitHub and registry settings
77
+
78
+ - npm trusted publishing must point at workflow filename `publish.yml` and use
79
+ the GitHub Actions environment named `npm`.
80
+ - The workflow does not use `NPM_TOKEN`.
81
+ - JSR publishing uses its own OIDC job and does not depend on the npm
82
+ environment.
83
+ - The repository settings must allow GitHub Actions to push the generated
84
+ `chore(release): ...` commit to `main`; otherwise the automatic release job
85
+ will validate successfully and then fail at the atomic push step.
86
+ - Configure a repository ruleset or tag protection rule for `v*` tags.
87
+ - Restrict the `npm` environment to the `main` deployment branch for automatic
88
+ releases and `v*` tags for intentional manual overrides.
89
+
90
+ GitHub Releases are an after-publish record. They are not a prerequisite for npm
91
+ or JSR publishing.
@@ -0,0 +1,64 @@
1
+ # Troubleshooting: Transitive `sharp` Install Errors
2
+
3
+ `libsql-search` does not directly depend on `sharp`. If you see an install error
4
+ mentioning `sharp`, it is coming from another dependency in your application or
5
+ toolchain.
6
+
7
+ This page exists because the error can show up in environments that also use
8
+ `libsql-search`, and it is easy to misattribute the failure to this package.
9
+
10
+ ## Typical Error
11
+
12
+ ```text
13
+ Cannot find module '../build/Release/sharp-*.node'
14
+ ```
15
+
16
+ Or:
17
+
18
+ ```text
19
+ Error: Something went wrong installing the "sharp" module
20
+ ```
21
+
22
+ ## Why It Happens
23
+
24
+ With pnpm, native packages may need explicit build-script approval. If the
25
+ relevant install script is blocked, the native binary is never downloaded or
26
+ built.
27
+
28
+ ## What To Do
29
+
30
+ First inspect which build scripts pnpm blocked:
31
+
32
+ ```bash
33
+ pnpm ignored-builds
34
+ ```
35
+
36
+ Then approve the package that is actually failing and reinstall:
37
+
38
+ ```bash
39
+ pnpm approve-builds
40
+ pnpm install
41
+ ```
42
+
43
+ In the interactive `pnpm approve-builds` prompt, select `sharp` if that is the
44
+ package reporting the native-module failure.
45
+
46
+ For a committed repository-level fix, you can also allow the package explicitly
47
+ in `pnpm-workspace.yaml` with `onlyBuiltDependencies`.
48
+
49
+ ## Relation To `libsql-search`
50
+
51
+ - local embeddings use `@xenova/transformers`
52
+ - the first local embedding run may download a model at runtime
53
+ - that runtime model download is separate from a pnpm native-module install
54
+ failure
55
+
56
+ ## Verification
57
+
58
+ After reinstalling, rerun the command that originally failed. If your app uses
59
+ `sharp` directly, verify that import in your own project context.
60
+
61
+ ## Additional Resources
62
+
63
+ - [pnpm approve-builds](https://pnpm.io/10.x/cli/approve-builds)
64
+ - [Sharp installation docs](https://sharp.pixelplumbing.com/install)
@@ -0,0 +1,12 @@
1
+ # Troubleshooting
2
+
3
+ Use the page that matches the failure mode:
4
+
5
+ - [Sharp native module issues](./TROUBLESHOOTING-SHARP.md)
6
+
7
+ Common operational checks:
8
+
9
+ - verify you called `createTable()` before indexing or searching
10
+ - verify the table dimension matches the embedding dimension in your code
11
+ - verify the same provider is used for indexing and querying
12
+ - verify hosted providers have `GEMINI_API_KEY` or `OPENAI_API_KEY` available
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libsql-search",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
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",
@@ -15,7 +15,8 @@
15
15
  },
16
16
  "files": [
17
17
  "dist",
18
- "README.md"
18
+ "README.md",
19
+ "docs"
19
20
  ],
20
21
  "scripts": {
21
22
  "build": "tsc --noEmit && rollup -c && rollup -c rollup.dts.config.js",