LibSQL/Turso storage and hybrid search backend for Worlds.
Standalone LibSQL package extracted from
@worlds/sdk.
# Deno (first-class JSR support)
deno add jsr:@worlds/libsql
# Bun / npm / pnpm / Yarn (via JSR npm compatibility layer)
npx jsr add @worlds/libsqlesm.sh serves JSR packages as ES modules — no install, no bundler needed.
import { createLibsqlWorldsSdk } from "https://esm.sh/jsr/@worlds/libsql@0.4.1";With an import map:
<script type="importmap">
{
"imports": {
"@worlds/libsql": "https://esm.sh/jsr/@worlds/libsql@0.4.1"
}
}
</script>Then a module script:
import { createLibsqlWorldsSdk } from "@worlds/libsql";Pin to an exact build for deterministic caching:
import { createLibsqlWorldsSdk } from "https://esm.sh/jsr/@worlds/libsql@0.4.1?pin=v1724100000";import { createClient } from "@libsql/client";
import { createLibsqlWorldsSdk } from "@worlds/libsql";
const databaseClient = createClient({ url: ":memory:" });
// The factory assembles the three strategy objects internally: a
// LibsqlConnectionDriver over the raw client, the schema builder, and the
// search-query builder. Callers just pass the LibSQL client.
const client = await createLibsqlWorldsSdk({ client: databaseClient });
await client.import({
source: {
kind: "serialized",
data:
`<http://example.com/alice> <http://example.com/knows> <http://example.com/bob> .`,
contentType: "text/turtle",
},
});
const { search, sparql } = await Promise.all([
client.search({ query: "alice" }),
client.sparql({
query:
`SELECT ?o WHERE { <http://example.com/alice> <http://example.com/knows> ?o }`,
}),
]);When you only need SPARQL over an RDF/JS store backed by LibSQL (no chunk
search, no embeddings), wire LibsqlRdfjsStore directly into
@wazoo/sparql-engine's WazooSparqlEngine:
import { createClient } from "@libsql/client";
import type * as rdfjs from "@rdfjs/types";
import { WazooSparqlEngine } from "@wazoo/sparql-engine";
import {
initializeLibsqlSchema,
LibsqlConnectionDriver,
LibsqlQuadStore,
LibsqlRdfjsStore,
LibsqlSchemaBuilder,
LibsqlSearchQueryBuilder,
} from "@worlds/libsql";
// A raw LibSQL client — in-memory here, any remote/embedded URL works.
const databaseClient = createClient({ url: ":memory:" });
// Create the quads table + covering indexes (no FTS/vector chunk schema).
const schemaBuilder = new LibsqlSchemaBuilder(32);
const connection = new LibsqlConnectionDriver(databaseClient);
await initializeLibsqlSchema(connection, schemaBuilder);
// The RDF/JS read source over LibSQL: match/countQuads via SQL index seeks.
const store = new LibsqlRdfjsStore({ connection });
// A quad store for writes (import/export/transaction); chunk projection
// is skipped by leaving searchIndexProjector unset.
const quadStore = new LibsqlQuadStore({
connection,
store,
searchQueryBuilder: new LibsqlSearchQueryBuilder(32),
});
// SPARQL engine over the same LibSQL-backed store.
const sparqlEngine = new WazooSparqlEngine({
store: store as unknown as rdfjs.Store,
createTransaction: () => quadStore.createTransaction(),
});
await quadStore.import({
source: {
kind: "serialized",
data:
`<http://example.com/alice> <http://example.com/knows> <http://example.com/bob> .`,
contentType: "text/turtle",
},
});
const result = await sparqlEngine.execute({
query:
`SELECT ?o WHERE { <http://example.com/alice> <http://example.com/knows> ?o }`,
});This package consumes the shared, driver-free SQL plan layer from
@worlds/sqlite/sql-core — the FTS5
sanitizer/stopwords, buildChunkFtsValue, buildSearchResultId, the
chunks_fts DDL/triggers, and filter-clause helpers. The LibSQL-specific
dialect (native vector32 columns, in-SQL RRF fusion over
vector_top_k('idx_chunks_vector', ...), and the column-per-position quads
table) stays local to this repo.
deno task ciDry-run a JSR publish locally:
deno task publish:dryReleases publish automatically when changes merge to main. Bump "version" in
deno.json in each release PR — JSR rejects duplicate versions.
One-time setup on jsr.io/@worlds/libsql:
- Open package settings and link
https://github.com/wazootech/worlds-libsql. - Enable GitHub Actions publishing (OIDC). The
publish workflow uses
id-token: write; no JSR token secret is required when OIDC is configured. - Confirm your GitHub account can publish to the
@worldsorg.
After setup, merging to main runs CI, a publish dry-run, and deno publish.