Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: tursodatabase/libsql-client-ts
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.14.0
Choose a base ref
...
head repository: tursodatabase/libsql-client-ts
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.15.0
Choose a head ref

Commits on Aug 28, 2024

  1. use simpler batch input

    notrab committed Aug 28, 2024
    Copy the full SHA
    bc49824 View commit details
  2. update sqlite3 to use simpler batch api

    notrab committed Aug 28, 2024
    Copy the full SHA
    d2f637d View commit details
  3. update tests

    notrab committed Aug 28, 2024
    Copy the full SHA
    5c6da67 View commit details
  4. Delete packages/libsql-client/examples/package-lock.json

    notrab authored Aug 28, 2024
    Copy the full SHA
    79094ae View commit details
  5. remove age for now

    notrab committed Aug 28, 2024
    Copy the full SHA
    0fffe73 View commit details
  6. revert async execute change

    notrab committed Aug 28, 2024
    Copy the full SHA
    0cfe870 View commit details

Commits on Sep 8, 2024

  1. chore: bump husky and clean up scripts

    alcpereira committed Sep 8, 2024
    Copy the full SHA
    4df9ee4 View commit details
  2. Copy the full SHA
    6e9614e View commit details
  3. ci: bump github actions to v4

    alcpereira committed Sep 8, 2024
    Copy the full SHA
    a677695 View commit details

Commits on Sep 11, 2024

  1. Copy the full SHA
    6de91a2 View commit details
  2. Copy the full SHA
    b40f7ea View commit details
  3. Copy the full SHA
    af2d811 View commit details
  4. add CONTRIBUTING.md

    DaBigBlob committed Sep 11, 2024
    Copy the full SHA
    48b25f6 View commit details

Commits on Sep 13, 2024

  1. fix: spelling mistake

    DaBigBlob committed Sep 13, 2024
    Copy the full SHA
    12e3086 View commit details
  2. fix: linting: npx prettier --write .

    DaBigBlob committed Sep 13, 2024
    Copy the full SHA
    3473a53 View commit details

Commits on Sep 14, 2024

  1. Copy the full SHA
    743838c View commit details
  2. ci: check formatting and types

    alcpereira committed Sep 14, 2024
    Copy the full SHA
    1df6199 View commit details

Commits on Sep 25, 2024

  1. update CONTRIBUTING.md

    Co-authored-by: alcpereira <48070464+alcpereira@users.noreply.github.com>
    DaBigBlob and alcpereira authored Sep 25, 2024
    Copy the full SHA
    e0560a4 View commit details
  2. Copy the full SHA
    92ea842 View commit details
  3. better instructions for contribution

    DaBigBlob committed Sep 25, 2024
    Copy the full SHA
    d8d16b4 View commit details
  4. prettier's antics

    DaBigBlob committed Sep 25, 2024
    Copy the full SHA
    5e77593 View commit details
  5. better instructions for contribution

    DaBigBlob committed Sep 25, 2024
    Copy the full SHA
    1bebef6 View commit details
  6. Merge pull request #261 from DaBigBlob/main

    move overloads of execute to @libsql/core/api (because its part of the public API) && add CONTRIBUTING.md
    penberg authored Sep 25, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    alexfauquette Alexandre Fauquette
    Copy the full SHA
    d84a4a4 View commit details

Commits on Sep 26, 2024

  1. Merge pull request #255 from tursodatabase/simpler-batch-api

    use simpler batch input
    penberg authored Sep 26, 2024
    Copy the full SHA
    80c2767 View commit details
  2. Merge pull request #259 from alcpereira/ci/bump-actions

    ci: bump github actions to v4
    penberg authored Sep 26, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    oliviertassinari Olivier Tassinari
    Copy the full SHA
    e9db106 View commit details

Commits on Oct 9, 2024

  1. Copy the full SHA
    75f3a05 View commit details
  2. add cover

    notrab committed Oct 9, 2024
    Copy the full SHA
    6b4868b View commit details
  3. note encryption at rest

    notrab committed Oct 9, 2024
    Copy the full SHA
    23b0bf3 View commit details

Commits on Oct 16, 2024

  1. Add examples

    giovannibenussi committed Oct 16, 2024
    Copy the full SHA
    d3f4d86 View commit details
  2. Add vector example

    giovannibenussi committed Oct 16, 2024
    Copy the full SHA
    77aca8a View commit details
  3. update readme

    notrab committed Oct 16, 2024
    Copy the full SHA
    adf1daa View commit details
  4. update readme to include examples list

    notrab committed Oct 16, 2024
    Copy the full SHA
    8264a0c View commit details
  5. remove android note

    notrab committed Oct 16, 2024
    Copy the full SHA
    7b41745 View commit details
  6. Add transaction example

    giovannibenussi committed Oct 16, 2024
    Copy the full SHA
    5a314e7 View commit details
  7. Delete unneeded database file

    giovannibenussi committed Oct 16, 2024
    Copy the full SHA
    b121779 View commit details

Commits on Oct 17, 2024

  1. Merge pull request #275 from tursodatabase/examples

    Add examples
    notrab authored Oct 17, 2024
    Copy the full SHA
    5008acd View commit details
  2. Merge pull request #273 from tursodatabase/readme

    docs(libsql-client): update readme
    notrab authored Oct 17, 2024
    Copy the full SHA
    7ad7acd View commit details

Commits on Oct 25, 2024

  1. docs: update weekly downloads shield in readme

    alcpereira committed Oct 25, 2024
    Copy the full SHA
    3ecb0dc View commit details

Commits on Oct 28, 2024

  1. Fixed sample code in README

    HAYASAKA-Ryosuke committed Oct 28, 2024
    Copy the full SHA
    445b8e7 View commit details

Commits on Oct 29, 2024

  1. Update transaction example

    giovannibenussi committed Oct 29, 2024
    Copy the full SHA
    0ce0806 View commit details
  2. Merge pull request #279 from alcpereira/chore/fix-npm-downloads

    docs: update weekly downloads shield in readme
    notrab authored Oct 29, 2024
    Copy the full SHA
    d722d3c View commit details
  3. Merge pull request #281 from HAYASAKA-Ryosuke/change_readme_sample_code

    Fixed sample code in README
    notrab authored Oct 29, 2024
    Copy the full SHA
    e1825ab View commit details
  4. Merge pull request #283 from tursodatabase/update-transaction-example

    Update transaction example
    giovannibenussi authored Oct 29, 2024
    Copy the full SHA
    1608674 View commit details

Commits on Nov 1, 2024

  1. Merge pull request #258 from alcpereira/chore/lint-staged

    chore: format other file types in lint-staged
    notrab authored Nov 1, 2024
    Copy the full SHA
    0ca281d View commit details
  2. chore: add git+ prefix to repo url and directory in package.json

    alcpereira committed Nov 1, 2024
    Copy the full SHA
    cea871e View commit details
  3. Merge pull request #265 from alcpereira/chore/update-git-urls

    chore: add git+ prefix to repo url in package.json
    notrab authored Nov 1, 2024
    Copy the full SHA
    1e77794 View commit details
  4. Copy the full SHA
    672114a View commit details
  5. fix(examples): move read-your-writes examples

    levydsa committed Nov 1, 2024
    Copy the full SHA
    4073452 View commit details
  6. Merge pull request #282 from levydsa/read_your_writes

    feat: add readYourWrites to options
    levydsa authored Nov 1, 2024
    Copy the full SHA
    2f62c71 View commit details
  7. docs: fix full reference link in README

    dector authored Nov 1, 2024
    Copy the full SHA
    aeba950 View commit details
Showing with 4,620 additions and 162 deletions.
  1. BIN .github/cover.png
  2. +45 −13 .github/workflows/ci.yaml
  3. +5 −4 .github/workflows/pages.yaml
  4. +1 −0 .husky/install.mjs
  5. +1 −1 .husky/pre-commit
  6. +1 −1 .lintstagedrc.json
  7. +16 −0 CHANGELOG.md
  8. +13 −0 CONTRIBUTING.md
  9. +1 −0 examples/batch/.gitignore
  10. +19 −0 examples/batch/README.md
  11. +28 −0 examples/batch/index.mjs
  12. +351 −0 examples/batch/package-lock.json
  13. +10 −0 examples/batch/package.json
  14. +1 −0 examples/encryption/.gitignore
  15. +19 −0 examples/encryption/README.md
  16. +24 −0 examples/encryption/index.mjs
  17. +351 −0 examples/encryption/package-lock.json
  18. +10 −0 examples/encryption/package.json
  19. +1 −0 examples/local/.gitignore
  20. +19 −0 examples/local/README.md
  21. +19 −0 examples/local/index.mjs
  22. +351 −0 examples/local/package-lock.json
  23. +10 −0 examples/local/package.json
  24. +1 −0 examples/memory/.gitignore
  25. +19 −0 examples/memory/README.md
  26. +19 −0 examples/memory/index.mjs
  27. +351 −0 examples/memory/package-lock.json
  28. +10 −0 examples/memory/package.json
  29. +1 −0 examples/ollama/.gitignore
  30. +29 −0 examples/ollama/README.md
  31. +110 −0 examples/ollama/index.mjs
  32. +365 −0 examples/ollama/package-lock.json
  33. +9 −0 examples/ollama/package.json
  34. +351 −0 examples/read-your-writes/package-lock.json
  35. +10 −0 examples/read-your-writes/package.json
  36. +32 −0 examples/read-your-writes/read_your_writes.js
  37. +1 −0 examples/remote/.gitignore
  38. +19 −0 examples/remote/README.md
  39. +20 −0 examples/remote/index.mjs
  40. +351 −0 examples/remote/package-lock.json
  41. +10 −0 examples/remote/package.json
  42. +2 −0 examples/sync/.gitignore
  43. +19 −0 examples/sync/README.md
  44. +21 −0 examples/sync/index.mjs
  45. +351 −0 examples/sync/package-lock.json
  46. +10 −0 examples/sync/package.json
  47. +1 −0 examples/transactions/.gitignore
  48. +27 −0 examples/transactions/README.md
  49. +48 −0 examples/transactions/index.mjs
  50. +351 −0 examples/transactions/package-lock.json
  51. +10 −0 examples/transactions/package.json
  52. +1 −0 examples/vector/.gitignore
  53. +19 −0 examples/vector/README.md
  54. +21 −0 examples/vector/index.mjs
  55. +351 −0 examples/vector/package-lock.json
  56. +10 −0 examples/vector/package.json
  57. +116 −50 package-lock.json
  58. +8 −4 package.json
  59. +5 −3 packages/libsql-client-wasm/package.json
  60. +1 −6 packages/libsql-client-wasm/src/wasm.ts
  61. +102 −27 packages/libsql-client/README.md
  62. +16 −0 packages/libsql-client/examples/example.js
  63. +34 −0 packages/libsql-client/examples/sync_offline.js
  64. +6 −6 packages/libsql-client/package.json
  65. +3 −3 packages/libsql-client/src/__tests__/client.test.ts
  66. +22 −11 packages/libsql-client/src/hrana.ts
  67. +13 −8 packages/libsql-client/src/http.ts
  68. +15 −10 packages/libsql-client/src/sqlite3.ts
  69. +13 −8 packages/libsql-client/src/ws.ts
  70. +4 −2 packages/libsql-core/package.json
  71. +10 −5 packages/libsql-core/src/api.ts
  72. +6 −0 packages/libsql-core/src/config.ts
Binary file added .github/cover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 45 additions & 13 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -5,6 +5,38 @@ on:
pull_request:

jobs:
"typecheck":
name: "Typecheck"
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- name: "Checkout this repo"
uses: actions/checkout@v4
- name: "Setup Node.js"
uses: actions/setup-node@v4
with:
node-version: "18.x"
- name: "Install node dependencies and build"
run: "npm ci && npm run build"
- name: "Typecheck"
run: "npm run typecheck"

"format-check":
name: "Check formatting"
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- name: "Checkout this repo"
uses: actions/checkout@v4
- name: "Setup Node.js"
uses: actions/setup-node@v4
with:
node-version: "18.x"
- name: "Install node dependencies"
run: "npm ci"
- name: "Check formatting"
run: "npm run format:check"

"test-against-sqld":
name: "Tests against sqld"
runs-on: ubuntu-latest
@@ -15,9 +47,9 @@ jobs:
env: { "NODE_OPTIONS": "--trace-warnings" }
steps:
- name: "Checkout this repo"
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: "Setup Node.js"
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: "18.x"
- name: "Build core"
@@ -45,9 +77,9 @@ jobs:
env: { "NODE_OPTIONS": "--trace-warnings" }
steps:
- name: "Checkout this repo"
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: "Setup Node.js"
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: "18.x"
cache-dependency-path: "packages/libsql-client-wasm"
@@ -72,9 +104,9 @@ jobs:
env: { "NODE_OPTIONS": "--trace-warnings" }
steps:
- name: "Checkout this repo"
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: "Setup Node.js"
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: "18.x"
- name: "Build core"
@@ -83,7 +115,7 @@ jobs:
- name: "Install npm dependencies"
run: "npm ci"
- name: "Checkout hrana-test-server"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: "libsql/hrana-test-server"
path: "packages/libsql-client/hrana-test-server"
@@ -133,9 +165,9 @@ jobs:
"CLOUDFLARE_ACCOUNT_ID": "${{ secrets.CLOUDFLARE_ACCOUNT_ID }}"
steps:
- name: "Checkout this repo"
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: "Setup Node.js"
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: "lts/Hydrogen"
- name: "Build core"
@@ -145,7 +177,7 @@ jobs:
run: "npm ci"

- name: "Checkout hrana-test-server"
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: "libsql/hrana-test-server"
path: "packages/libsql-client/hrana-test-server"
@@ -201,17 +233,17 @@ jobs:
# VERCEL_PROJECT_NAME: "smoke-test"
# steps:
# - name: "Checkout this repo"
# uses: actions/checkout@v3
# uses: actions/checkout@v4
# - name: "Setup Node.js"
# uses: actions/setup-node@v3
# uses: actions/setup-node@v4
# with:
# node-version: "lts/Hydrogen"
# cache: "npm"
# - name: "Install npm dependencies"
# run: "npm ci"

# - name: "Checkout hrana-test-server"
# uses: actions/checkout@v3
# uses: actions/checkout@v4
# with:
# repository: "libsql/hrana-test-server"
# path: "hrana-test-server"
9 changes: 5 additions & 4 deletions .github/workflows/pages.yaml
Original file line number Diff line number Diff line change
@@ -12,9 +12,9 @@ jobs:
working-directory: ./packages/libsql-client
steps:
- name: "Checkout this repo"
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: "Setup Node.js"
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: "${{ matrix.node-version }}"
cache: "npm"
@@ -26,7 +26,8 @@ jobs:
- name: "Build"
run: "npm run typedoc"
- name: "Upload GitHub Pages artifact"
uses: actions/upload-pages-artifact@v1
uses: actions/upload-pages-artifact@v3
id: deployment
with:
path: "./packages/libsql-client/docs"

@@ -45,4 +46,4 @@ jobs:
steps:
- name: "Deploy to GitHub Pages"
id: deployment
uses: actions/deploy-pages@v1
uses: actions/deploy-pages@v4
1 change: 1 addition & 0 deletions .husky/install.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// See https://typicode.github.io/husky/how-to.html#ci-server-and-docker
// Skip Husky install in production and CI
if (process.env.NODE_ENV === "production" || process.env.CI === "true") {
process.exit(0);
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
npm run lint-staged
lint-staged
2 changes: 1 addition & 1 deletion .lintstagedrc.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{ "*.{js,ts}": "prettier --write" }
{ "*.{js,ts,json,md,yaml,yml}": "prettier --write" }
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## 0.15.0 -- 2025-03-17

- Bump to latest `libsql` package.

## 0.15.0-pre.3 -- 2025-03-11

- Fix Bun complaint about duplicate "prepare" key in `package.json`

## 0.15.0-pre.2 -- 2024-02-11

- Bump to latest `libsql` package.

## 0.15.0-pre.1 -- 2024-11-15

- Initial support for offline writes.

## 0.12.0 -- 2024-09-16

- Upgrade `hrana-client-ts` to latest 0.7.0 version which has stable `isomorphic-fetch` implementation (see https://github.com/libsql/hrana-client-ts/pull/19)
13 changes: 13 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Prerequisites

- Have `npm` installed and in PATH
- Have `git` installed and in PATH

# Setting up the repository for contribution

- Clone this repository: `git clone https://github.com/tursodatabase/libsql-client-ts`
- Change the current working directory to the cloned repository: `cd libsql-client-ts`
- Install dependencies: `npm i`
- Change the current working directory to `libsql-core`'s workspace: `cd packages/libsql-core`
- Built the core package: `npm run build`
- Go back to the root directory to start making changes: `cd ../..`
1 change: 1 addition & 0 deletions examples/batch/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
local.db
19 changes: 19 additions & 0 deletions examples/batch/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Batch

This example demonstrates how to use libSQL to execute a batch of SQL statements.

## Install Dependencies

```bash
npm i
```

## Running

Execute the example:

```bash
node index.mjs
```

This will setup a SQLite database, execute a batch of SQL statements, and then query the results.
28 changes: 28 additions & 0 deletions examples/batch/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { createClient } from "@libsql/client";

const client = createClient({
url: "file:local.db",
});

await client.batch(
[
"CREATE TABLE IF NOT EXISTS users (email TEXT)",
{
sql: "INSERT INTO users VALUES (?)",
args: ["first@example.com"],
},
{
sql: "INSERT INTO users VALUES (?)",
args: ["second@example.com"],
},
{
sql: "INSERT INTO users VALUES (?)",
args: ["third@example.com"],
},
],
"write",
);

const result = await client.execute("SELECT * FROM users");

console.log("Users:", result.rows);
351 changes: 351 additions & 0 deletions examples/batch/package-lock.json
10 changes: 10 additions & 0 deletions examples/batch/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "batch",
"version": "1.0.0",
"main": "index.mjs",
"author": "Giovanni Benussi",
"license": "MIT",
"dependencies": {
"@libsql/client": "^0.14.0"
}
}
1 change: 1 addition & 0 deletions examples/encryption/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
encrypted.db
19 changes: 19 additions & 0 deletions examples/encryption/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Encryption

This example demonstrates how to create and use an encrypted SQLite database with libSQL.

## Install Dependencies

```bash
npm i
```

## Running

Execute the example:

```bash
node index.mjs
```

This will setup an encrypted SQLite database, execute a batch of SQL statements, and then query the results.
24 changes: 24 additions & 0 deletions examples/encryption/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { createClient } from "@libsql/client";

// You should set the ENCRYPTION_KEY in a environment variable
// For demo purposes, we're using a fixed key
const encryptionKey = "my-safe-encryption-key";

const client = createClient({
url: "file:encrypted.db",
encryptionKey,
});

await client.batch(
[
"CREATE TABLE IF NOT EXISTS users (email TEXT)",
"INSERT INTO users VALUES ('first@example.com')",
"INSERT INTO users VALUES ('second@example.com')",
"INSERT INTO users VALUES ('third@example.com')",
],
"write",
);

const result = await client.execute("SELECT * FROM users");

console.log("Users:", result.rows);
351 changes: 351 additions & 0 deletions examples/encryption/package-lock.json
10 changes: 10 additions & 0 deletions examples/encryption/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "batch",
"version": "1.0.0",
"main": "index.mjs",
"author": "Giovanni Benussi",
"license": "MIT",
"dependencies": {
"@libsql/client": "^0.14.0"
}
}
1 change: 1 addition & 0 deletions examples/local/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
local.db
19 changes: 19 additions & 0 deletions examples/local/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Local

This example demonstrates how to use libSQL with a local SQLite file.

## Install Dependencies

```bash
npm i
```

## Running

Execute the example:

```bash
node index.mjs
```

This will setup a local SQLite database, insert some data, and then query the results.
19 changes: 19 additions & 0 deletions examples/local/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createClient } from "@libsql/client";

const client = createClient({
url: "file:local.db",
});

await client.batch(
[
"CREATE TABLE IF NOT EXISTS users (email TEXT)",
"INSERT INTO users VALUES ('first@example.com')",
"INSERT INTO users VALUES ('second@example.com')",
"INSERT INTO users VALUES ('third@example.com')",
],
"write",
);

const result = await client.execute("SELECT * FROM users");

console.log("Users:", result.rows);
351 changes: 351 additions & 0 deletions examples/local/package-lock.json
10 changes: 10 additions & 0 deletions examples/local/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "batch",
"version": "1.0.0",
"main": "index.mjs",
"author": "Giovanni Benussi",
"license": "MIT",
"dependencies": {
"@libsql/client": "^0.14.0"
}
}
1 change: 1 addition & 0 deletions examples/memory/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
local.db
19 changes: 19 additions & 0 deletions examples/memory/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Memory

This example demonstrates how to use libsql with an in-memory SQLite database.

## Install Dependencies

```bash
npm i
```

## Running

Execute the example:

```bash
node index.mjs
```

This will create an in-memory SQLite database, insert some data, and then query the results.
19 changes: 19 additions & 0 deletions examples/memory/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createClient } from "@libsql/client";

const client = createClient({
url: ":memory:",
});

await client.batch(
[
"CREATE TABLE users (email TEXT)",
"INSERT INTO users VALUES ('first@example.com')",
"INSERT INTO users VALUES ('second@example.com')",
"INSERT INTO users VALUES ('third@example.com')",
],
"write",
);

const result = await client.execute("SELECT * FROM users");

console.log("Users:", result.rows);
351 changes: 351 additions & 0 deletions examples/memory/package-lock.json
10 changes: 10 additions & 0 deletions examples/memory/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "batch",
"version": "1.0.0",
"main": "index.mjs",
"author": "Giovanni Benussi",
"license": "MIT",
"dependencies": {
"@libsql/client": "^0.14.0"
}
}
1 change: 1 addition & 0 deletions examples/ollama/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
local.db
29 changes: 29 additions & 0 deletions examples/ollama/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Ollama + Vector Search Example

This example demonstrates how to use libSQL vector search with a local database and Ollama.

## Install Dependencies

```bash
npm i
```

## Install Ollama

[Download Ollama](https://ollama.com/download) and install it.

## Running

Make sure Ollama is running with the model `mistral`:

```bash
ollama run mistral
```

Execute the example:

```bash
node index.mjs
```

This will setup a local SQLite database, generate embeddings using Ollama, and insert the data with embeddings, and then query the results using the vector similarity search function.
110 changes: 110 additions & 0 deletions examples/ollama/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { createClient } from "@libsql/client";
import ollama from "ollama";

const client = createClient({
url: "file:local.db",
});

await client.batch(
[
"CREATE TABLE IF NOT EXISTS movies (id INTEGER PRIMARY KEY, title TEXT NOT NULL, description TEXT NOT NULL, embedding F32_BLOB(4096))",
"CREATE INDEX IF NOT EXISTS movies_embedding_idx ON movies(libsql_vector_idx(embedding))",
],
"write",
);

async function getEmbedding(prompt) {
const response = await ollama.embeddings({
model: "mistral",
prompt,
});

return response.embedding;
}

async function insertMovie(id, title, description) {
const embedding = await getEmbedding(description);

await client.execute({
sql: `INSERT OR REPLACE INTO movies (id, title, description, embedding) VALUES (?, ?, ?, vector(?))`,
args: [id, title, description, JSON.stringify(embedding)],
});
}

async function insertMovieIfNotExists(id, title, description) {
const existing = await client.execute({
sql: "SELECT id FROM movies WHERE id = ?",
args: [id],
});

if (existing.rows.length === 0) {
await insertMovie(id, title, description);
console.log(`Inserted: ${title} (ID: ${id})`);
} else {
console.log(`Movie already exists: ${title} (ID: ${id})`);
}
}

async function findSimilarMovies(description, limit = 3) {
const queryEmbedding = await getEmbedding(description);

const results = await client.execute({
sql: `
WITH vector_scores AS (
SELECT DISTINCT
id,
title,
description,
1 - vector_distance_cos(embedding, vector32(?)) AS similarity
FROM movies
ORDER BY similarity DESC
LIMIT ?
)
SELECT id, title, description, similarity FROM vector_scores
`,
args: [JSON.stringify(queryEmbedding), limit],
});

return results.rows;
}

try {
const sampleMovies = [
{
id: 1,
title: "Inception",
description:
"A thief who enters the dreams of others to steal secrets from their subconscious.",
},
{
id: 2,
title: "The Matrix",
description:
"A computer programmer discovers that reality as he knows it is a simulation created by machines.",
},
{
id: 3,
title: "Interstellar",
description:
"Astronauts travel through a wormhole in search of a new habitable planet for humanity.",
},
];

for (const movie of sampleMovies) {
await insertMovieIfNotExists(movie.id, movie.title, movie.description);
}

const query =
"A sci-fi movie about virtual reality and artificial intelligence";
console.log("\nSearching for movies similar to:", query);

const similarMovies = await findSimilarMovies(query);
console.log("\nSimilar movies found:");
similarMovies.forEach((movie) => {
console.log(`\nTitle: ${movie.title}`);
console.log(`Description: ${movie.description}`);
console.log(`Similarity: ${movie.similarity.toFixed(4)}`);
});
} catch (error) {
console.error("Error:", error);
}
365 changes: 365 additions & 0 deletions examples/ollama/package-lock.json
9 changes: 9 additions & 0 deletions examples/ollama/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "ollama",
"private": true,
"main": "index.mjs",
"dependencies": {
"@libsql/client": "^0.14.0",
"ollama": "^0.5.11"
}
}
351 changes: 351 additions & 0 deletions examples/read-your-writes/package-lock.json
10 changes: 10 additions & 0 deletions examples/read-your-writes/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "read-your-writes",
"version": "1.0.0",
"main": "index.mjs",
"author": "Levy Albuquerque",
"license": "MIT",
"dependencies": {
"@libsql/client": "^0.14.0"
}
}
32 changes: 32 additions & 0 deletions examples/read-your-writes/read_your_writes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { createClient } from "@libsql/client";

const client = createClient({
url: "file:local.db",
syncUrl: process.env.TURSO_DATABASE_URL,
authToken: process.env.TURSO_AUTH_TOKEN,
readYourWrites: false,
});

await client.execute("DROP TABLE users");
await client.execute("CREATE TABLE IF NOT EXISTS users (email TEXT)");
await client.sync();

await client.execute("INSERT INTO users VALUES ('first@example.com')");
await client.execute("INSERT INTO users VALUES ('second@example.com')");
await client.execute("INSERT INTO users VALUES ('third@example.com')");

{
// No users, sinc no sync has happend since inserts
const result = await client.execute("SELECT * FROM users");

console.log("Users:", result.rows);
}

{
await client.sync();

// No users, sinc no sync has happend since inserts
const result = await client.execute("SELECT * FROM users");

console.log("Users:", result.rows);
}
1 change: 1 addition & 0 deletions examples/remote/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
local.db
19 changes: 19 additions & 0 deletions examples/remote/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Remote

This example demonstrates how to use libSQL with a remote database.

## Install Dependencies

```bash
npm i
```

## Running

Execute the example:

```bash
TURSO_DATABASE_URL="..." TURSO_AUTH_TOKEN="..." node index.mjs
```

This will connect to a remote SQLite database, insert some data, and then query the results.
20 changes: 20 additions & 0 deletions examples/remote/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createClient } from "@libsql/client";

const client = createClient({
url: process.env.TURSO_DATABASE_URL,
authToken: process.env.TURSO_AUTH_TOKEN,
});

await client.batch(
[
"CREATE TABLE IF NOT EXISTS users (email TEXT)",
"INSERT INTO users VALUES ('first@example.com')",
"INSERT INTO users VALUES ('second@example.com')",
"INSERT INTO users VALUES ('third@example.com')",
],
"write",
);

const result = await client.execute("SELECT * FROM users");

console.log("Users:", result.rows);
351 changes: 351 additions & 0 deletions examples/remote/package-lock.json
10 changes: 10 additions & 0 deletions examples/remote/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "batch",
"version": "1.0.0",
"main": "index.mjs",
"author": "Giovanni Benussi",
"license": "MIT",
"dependencies": {
"@libsql/client": "^0.14.0"
}
}
2 changes: 2 additions & 0 deletions examples/sync/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local.db
local.db-client_wal_index
19 changes: 19 additions & 0 deletions examples/sync/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Sync

This example demonstrates how to use libSQL with a synced database (local file synced with a remote database).

## Install Dependencies

```bash
npm i
```

## Running

Execute the example:

```bash
TURSO_DATABASE_URL="..." TURSO_AUTH_TOKEN="..." node index.mjs
```

This will connect to a remote SQLite database, insert some data, and then query the results.
21 changes: 21 additions & 0 deletions examples/sync/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createClient } from "@libsql/client";

const client = createClient({
url: "file:local.db",
syncUrl: process.env.TURSO_DATABASE_URL,
authToken: process.env.TURSO_AUTH_TOKEN,
});

await client.batch(
[
"CREATE TABLE IF NOT EXISTS users (email TEXT)",
"INSERT INTO users VALUES ('first@example.com')",
"INSERT INTO users VALUES ('second@example.com')",
"INSERT INTO users VALUES ('third@example.com')",
],
"write",
);

const result = await client.execute("SELECT * FROM users");

console.log("Users:", result.rows);
351 changes: 351 additions & 0 deletions examples/sync/package-lock.json
10 changes: 10 additions & 0 deletions examples/sync/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "batch",
"version": "1.0.0",
"main": "index.mjs",
"author": "Giovanni Benussi",
"license": "MIT",
"dependencies": {
"@libsql/client": "^0.14.0"
}
}
1 change: 1 addition & 0 deletions examples/transactions/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
local.db
27 changes: 27 additions & 0 deletions examples/transactions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Local

This example demonstrates how to use transactions with libSQL.

## Install Dependencies

```bash
npm i
```

## Running

Execute the example:

```bash
node index.mjs
```

This example will:

1. Create a new table called `users`.
2. Start a transaction.
3. Insert multiple users within the transaction.
4. Demonstrate how to rollback a transaction.
5. Start another transaction.
6. Insert more users and commit the transaction.
7. Query and display the final state of the `users` table.
48 changes: 48 additions & 0 deletions examples/transactions/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { createClient } from "@libsql/client";

const client = createClient({
url: "file:local.db",
});

await client.batch(
[
"DROP TABLE IF EXISTS users",
"CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)",
"INSERT INTO users (name) VALUES ('Iku Turso')",
],
"write",
);

const names = ["John Doe", "Mary Smith", "Alice Jones", "Mark Taylor"];

let transaction, secondTransaction;
try {
transaction = await client.transaction("write");

for (const name of names) {
await transaction.execute({
sql: "INSERT INTO users (name) VALUES (?)",
args: [name],
});
}
await transaction.rollback();

secondTransaction = await client.transaction("write");

for (const name of names) {
await secondTransaction.execute({
sql: "INSERT INTO users (name) VALUES (?)",
args: [name],
});
}

await secondTransaction.commit();
} catch (e) {
console.error(e);
await transaction?.rollback();
await secondTransaction?.rollback();
}

const result = await client.execute("SELECT * FROM users");

console.log("Users:", result.rows);
351 changes: 351 additions & 0 deletions examples/transactions/package-lock.json
10 changes: 10 additions & 0 deletions examples/transactions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "batch",
"version": "1.0.0",
"main": "index.mjs",
"author": "Giovanni Benussi",
"license": "MIT",
"dependencies": {
"@libsql/client": "^0.14.0"
}
}
1 change: 1 addition & 0 deletions examples/vector/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
local.db
19 changes: 19 additions & 0 deletions examples/vector/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Local

This example demonstrates how to use libSQL vector search with a local database.

## Install Dependencies

```bash
npm i
```

## Running

Execute the example:

```bash
node index.mjs
```

This will setup a local SQLite database, insert some data, and then query the results using the vector similarity search function.
21 changes: 21 additions & 0 deletions examples/vector/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createClient } from "@libsql/client";

const client = createClient({
url: "file:local.db",
});

await client.batch(
[
"DROP TABLE IF EXISTS movies",
"CREATE TABLE IF NOT EXISTS movies (title TEXT, year INT, embedding F32_BLOB(3))",
"CREATE INDEX movies_idx ON movies (libsql_vector_idx(embedding))",
"INSERT INTO movies (title, year, embedding) VALUES ('Napoleon', 2023, vector32('[1,2,3]')), ('Black Hawk Down', 2001, vector32('[10,11,12]')), ('Gladiator', 2000, vector32('[7,8,9]')), ('Blade Runner', 1982, vector32('[4,5,6]'))",
],
"write",
);

const result = await client.execute(
"SELECT title, year FROM vector_top_k('movies_idx', '[4,5,6]', 3) JOIN movies ON movies.rowid = id",
);

console.log("Movies:", result.rows);
351 changes: 351 additions & 0 deletions examples/vector/package-lock.json
10 changes: 10 additions & 0 deletions examples/vector/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "batch",
"version": "1.0.0",
"main": "index.mjs",
"author": "Giovanni Benussi",
"license": "MIT",
"dependencies": {
"@libsql/client": "^0.14.0"
}
}
166 changes: 116 additions & 50 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -4,12 +4,16 @@
"packages/libsql-client",
"packages/libsql-client-wasm"
],
"dependencies": {
"husky": "^9.0.11",
"lint-staged": "^15.2.2"
},
"dependencies": {},
"scripts": {
"prepare": "node .husky/install.mjs",
"build": "npm run build --workspaces",
"typecheck": "npm run typecheck --workspaces",
"format:check": "npm run format:check --workspaces",
"lint-staged": "lint-staged"
},
"devDependencies": {
"lint-staged": "^15.2.2",
"husky": "^9.1.5"
}
}
8 changes: 5 additions & 3 deletions packages/libsql-client-wasm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@libsql/client-wasm",
"version": "0.14.0",
"version": "0.15.0",
"keywords": [
"libsql",
"database",
@@ -13,7 +13,8 @@
"description": "libSQL driver for TypeScript and JavaScript",
"repository": {
"type": "git",
"url": "https://github.com/libsql/libsql-client-ts"
"url": "git+https://github.com/libsql/libsql-client-ts",
"directory": "packages/libsql-client-wasm"
},
"authors": [
"Jan Špaček <honza@chiselstrike.com>",
@@ -51,12 +52,13 @@
"build": "npm run build:esm",
"build:esm": "tsc -p tsconfig.build-esm.json",
"bundle": "rm -rf node_modules && mkdir -p node_modules/@libsql/libsql-wasm-experimental && cp -R ../../node_modules/@libsql/libsql-wasm-experimental/* node_modules/@libsql/libsql-wasm-experimental",
"format:check": "prettier --check .",
"test": "jest --runInBand",
"typecheck": "tsc --noEmit",
"typedoc": "rm -rf ./docs && typedoc"
},
"dependencies": {
"@libsql/core": "^0.14.0",
"@libsql/core": "^0.15.0",
"@libsql/libsql-wasm-experimental": "^0.0.2",
"js-base64": "^3.7.5"
},
7 changes: 1 addition & 6 deletions packages/libsql-client-wasm/src/wasm.ts
Original file line number Diff line number Diff line change
@@ -123,9 +123,6 @@ export class Sqlite3Client implements Client {
this.protocol = "file";
}

async execute(stmt: InStatement): Promise<ResultSet>;
async execute(sql: string, args?: InArgs): Promise<ResultSet>;

async execute(
stmtOrSql: InStatement | string,
args?: InArgs,
@@ -171,9 +168,7 @@ export class Sqlite3Client implements Client {
}
}

async migrate(
stmts: Array<InStatement>,
): Promise<Array<ResultSet>> {
async migrate(stmts: Array<InStatement>): Promise<Array<ResultSet>> {
this.#checkNotClosed();
const db = this.#getDb();
try {
129 changes: 102 additions & 27 deletions packages/libsql-client/README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,126 @@
<p align="center">
<a href="https://docs.turso.tech/sdk/ts/quickstart">
<img alt="Turso + TypeScript" src="https://github.com/tursodatabase/libsql-client-ts/assets/950181/5d3a2693-75f9-4c56-9107-8ccaa96785fd" width="1000">
<h3 align="center">Turso + TypeScript / JS</h3>
<a href="https://tur.so/turso-ts">
<picture>
<img src="/.github/cover.png" alt="libSQL TypeScript" />
</picture>
</a>
<h1 align="center">libSQL TypeScript</h1>
</p>

<p align="center">
SQLite for Production. Powered by <a href="https://turso.tech/libsql">libSQL</a>.
Databases for all TypeScript and JS multi-tenant apps.
</p>

<p align="center">
<a href="https://turso.tech"><strong>Turso</strong></a> ·
<a href="https://docs.turso.tech/quickstart"><strong>Quickstart</strong></a> ·
<a href="/examples"><strong>Examples</strong></a> ·
<a href="https://tur.so/turso-ts"><strong>Turso</strong></a> ·
<a href="https://docs.turso.tech"><strong>Docs</strong></a> ·
<a href="https://discord.com/invite/4B5D7hYwub"><strong>Discord</strong></a> ·
<a href="https://blog.turso.tech/"><strong>Blog &amp; Tutorials</strong></a>
<a href="https://docs.turso.tech/sdk/ts/quickstart"><strong>Quickstart</strong></a> ·
<a href="https://docs.turso.tech/sdk/ts/reference"><strong>SDK Reference</strong></a> ·
<a href="https://turso.tech/blog"><strong>Blog &amp; Tutorials</strong></a>
</p>

<p align="center">
<a href="https://www.npmjs.com/@libsql/client">
<img src="https://badge.fury.io/js/@libsql%2Fclient.svg" alt="npm version" title="npm version" />
<a href="LICENSE">
<picture>
<img src="https://img.shields.io/github/license/tursodatabase/libsql-client-ts?color=0F624B" alt="MIT License" />
</picture>
</a>
<a href="https://discord.com/invite/4B5D7hYwub">
<img src="https://dcbadge.vercel.app/api/server/4B5D7hYwub?style=flat" alt="discord activity" title="join us on discord" />
<a href="https://tur.so/discord-ts">
<picture>
<img src="https://img.shields.io/discord/933071162680958986?color=0F624B" alt="Discord" />
</picture>
</a>
<a href="https://www.phorm.ai/query?projectId=3c9a471f-4a47-469f-81f6-4ea1ff9ab418"><img src="https://img.shields.io/badge/Phorm-Ask_AI-%23F2777A.svg?&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNSIgaGVpZ2h0PSI0IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxwYXRoIGQ9Ik00LjQzIDEuODgyYTEuNDQgMS40NCAwIDAgMS0uMDk4LjQyNmMtLjA1LjEyMy0uMTE1LjIzLS4xOTIuMzIyLS4wNzUuMDktLjE2LjE2NS0uMjU1LjIyNmExLjM1MyAxLjM1MyAwIDAgMS0uNTk1LjIxMmMtLjA5OS4wMTItLjE5Mi4wMTQtLjI3OS4wMDZsLTEuNTkzLS4xNHYtLjQwNmgxLjY1OGMuMDkuMDAxLjE3LS4xNjkuMjQ2LS4xOTFhLjYwMy42MDMgMCAwIDAgLjItLjEwNi41MjkuNTI5IDAgMCAwIC4xMzgtLjE3LjY1NC42NTQgMCAwIDAgLjA2NS0uMjRsLjAyOC0uMzJhLjkzLjkzIDAgMCAwLS4wMzYtLjI0OS41NjcuNTY3IDAgMCAwLS4xMDMtLjIuNTAyLjUwMiAwIDAgMC0uMTY4LS4xMzguNjA4LjYwOCAwIDAgMC0uMjQtLjA2N0wyLjQzNy43MjkgMS42MjUuNjcxYS4zMjIuMzIyIDAgMCAwLS4yMzIuMDU4LjM3NS4zNzUgMCAwIDAtLjExNi4yMzJsLS4xMTYgMS40NS0uMDU4LjY5Ny0uMDU4Ljc1NEwuNzA1IDRsLS4zNTctLjA3OUwuNjAyLjkwNkMuNjE3LjcyNi42NjMuNTc0LjczOS40NTRhLjk1OC45NTggMCAwIDEgLjI3NC0uMjg1Ljk3MS45NzEgMCAwIDEgLjMzNy0uMTRjLjExOS0uMDI2LjIyNy0uMDM0LjMyNS0uMDI2TDMuMjMyLjE2Yy4xNTkuMDE0LjMzNi4wMy40NTkuMDgyYTEuMTczIDEuMTczIDAgMCAxIC41NDUuNDQ3Yy4wNi4wOTQuMTA5LjE5Mi4xNDQuMjkzYTEuMzkyIDEuMzkyIDAgMCAxIC4wNzguNThsLS4wMjkuMzJaIiBmaWxsPSIjRjI3NzdBIi8+CiAgPHBhdGggZD0iTTQuMDgyIDIuMDA3YTEuNDU1IDEuNDU1IDAgMCAxLS4wOTguNDI3Yy0uMDUuMTI0LS4xMTQuMjMyLS4xOTIuMzI0YTEuMTMgMS4xMyAwIDAgMS0uMjU0LjIyNyAxLjM1MyAxLjM1MyAwIDAgMS0uNTk1LjIxNGMtLjEuMDEyLS4xOTMuMDE0LS4yOC4wMDZsLTEuNTYtLjEwOC4wMzQtLjQwNi4wMy0uMzQ4IDEuNTU5LjE1NGMuMDkgMCAuMTczLS4wMS4yNDgtLjAzM2EuNjAzLjYwMyAwIDAgMCAuMi0uMTA2LjUzMi41MzIgMCAwIDAgLjEzOS0uMTcyLjY2LjY2IDAgMCAwIC4wNjQtLjI0MWwuMDI5LS4zMjFhLjk0Ljk0IDAgMCAwLS4wMzYtLjI1LjU3LjU3IDAgMCAwLS4xMDMtLjIwMi41MDIuNTAyIDAgMCAwLS4xNjgtLjEzOC42MDUuNjA1IDAgMCAwLS4yNC0uMDY3TDEuMjczLjgyN2MtLjA5NC0uMDA4LS4xNjguMDEtLjIyMS4wNTUtLjA1My4wNDUtLjA4NC4xMTQtLjA5Mi4yMDZMLjcwNSA0IDAgMy45MzhsLjI1NS0yLjkxMUExLjAxIDEuMDEgMCAwIDEgLjM5My41NzIuOTYyLjk2MiAwIDAgMSAuNjY2LjI4NmEuOTcuOTcgMCAwIDEgLjMzOC0uMTRDMS4xMjIuMTIgMS4yMy4xMSAxLjMyOC4xMTlsMS41OTMuMTRjLjE2LjAxNC4zLjA0Ny40MjMuMWExLjE3IDEuMTcgMCAwIDEgLjU0NS40NDhjLjA2MS4wOTUuMTA5LjE5My4xNDQuMjk1YTEuNDA2IDEuNDA2IDAgMCAxIC4wNzcuNTgzbC0uMDI4LjMyMloiIGZpbGw9IndoaXRlIi8+CiAgPHBhdGggZD0iTTQuMDgyIDIuMDA3YTEuNDU1IDEuNDU1IDAgMCAxLS4wOTguNDI3Yy0uMDUuMTI0LS4xMTQuMjMyLS4xOTIuMzI0YTEuMTMgMS4xMyAwIDAgMS0uMjU0LjIyNyAxLjM1MyAxLjM1MyAwIDAgMS0uNTk1LjIxNGMtLjEuMDEyLS4xOTMuMDE0LS4yOC4wMDZsLTEuNTYtLjEwOC4wMzQtLjQwNi4wMy0uMzQ4IDEuNTU5LjE1NGMuMDkgMCAuMTczLS4wMS4yNDgtLjAzM2EuNjAzLjYwMyAwIDAgMCAuMi0uMTA2LjUzMi41MzIgMCAwIDAgLjEzOS0uMTcyLjY2LjY2IDAgMCAwIC4wNjQtLjI0MWwuMDI5LS4zMjFhLjk0Ljk0IDAgMCAwLS4wMzYtLjI1LjU3LjU3IDAgMCAwLS4xMDMtLjIwMi41MDIuNTAyIDAgMCAwLS4xNjgtLjEzOC42MDUuNjA1IDAgMCAwLS4yNC0uMDY3TDEuMjczLjgyN2MtLjA5NC0uMDA4LS4xNjguMDEtLjIyMS4wNTUtLjA1My4wNDUtLjA4NC4xMTQtLjA5Mi4yMDZMLjcwNSA0IDAgMy45MzhsLjI1NS0yLjkxMUExLjAxIDEuMDEgMCAwIDEgLjM5My41NzIuOTYyLjk2MiAwIDAgMSAuNjY2LjI4NmEuOTcuOTcgMCAwIDEgLjMzOC0uMTRDMS4xMjIuMTIgMS4yMy4xMSAxLjMyOC4xMTlsMS41OTMuMTRjLjE2LjAxNC4zLjA0Ny40MjMuMWExLjE3IDEuMTcgMCAwIDEgLjU0NS40NDhjLjA2MS4wOTUuMTA5LjE5My4xNDQuMjk1YTEuNDA2IDEuNDA2IDAgMCAxIC4wNzcuNTgzbC0uMDI4LjMyMloiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=" alt="phorm.ai">
<a href="#contributors">
<picture>
<img src="https://img.shields.io/github/contributors/tursodatabase/libsql-client-ts?color=0F624B" alt="Contributors" />
</picture>
</a>
<a href="https://www.npmjs.com/package/@libsql/client">
<picture>
<img src="https://img.shields.io/npm/dw/%40libsql%2Fclient?color=0F624B" alt="Weekly downloads" />
</picture>
</a>
<a href="/examples">
<picture>
<img src="https://img.shields.io/badge/browse-examples-0F624B" alt="Examples" />
</picture>
</a>
</p>

---
## Features

- 🔌 Works offline with [Embedded Replicas](https://docs.turso.tech/features/embedded-replicas/introduction)
- 🌎 Works with remote Turso databases
- ✨ Works with Turso [AI & Vector Search](https://docs.turso.tech/features/ai-and-embeddings)
- 🔐 Supports [encryption at rest](https://docs.turso.tech/libsql#encryption-at-rest)

## Install

```bash
npm install @libsql/client
```

## Quickstart

The example below uses Embedded Replicas and syncs every minute from Turso.

```ts
import { createClient } from "@libsql/client";

export const turso = createClient({
url: "file:local.db",
syncUrl: process.env.TURSO_DATABASE_URL,
authToken: process.env.TURSO_AUTH_TOKEN,
syncInterval: 60000,
});

await turso.batch(
[
"CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)",
{
sql: "INSERT INTO users(name) VALUES (?)",
args: ["Iku"],
},
],
"write",
);

await turso.execute({
sql: "SELECT * FROM users WHERE id = ?",
args: [1],
});
```

## Examples

| Example | Description |
| ------------------------------------- | --------------------------------------------------------------------------------------- |
| [local](examples/local) | Uses libsql with a local SQLite file. Creates database, inserts data, and queries. |
| [remote](examples/remote) | Connects to a remote database. Requires environment variables for URL and auth token. |
| [sync](examples/sync) | Demonstrates synchronization between local and remote databases. |
| [batch](examples/batch) | Executes multiple SQL statements in a single batch operation. |
| [transactions](examples/transactions) | Shows transaction usage: starting, performing operations, and committing/rolling back. |
| [memory](examples/memory) | Uses an in-memory SQLite database for temporary storage or fast access. |
| [vector](examples/vector) | Works with vector embeddings, storing and querying for similarity search. |
| [encryption](examples/encryption) | Creates and uses an encrypted SQLite database, demonstrating setup and data operations. |
| [ollama](examples/ollama) | Similarity search with Ollama and Mistral. |

## Documentation

1. [Turso Quickstart](https://docs.turso.tech/quickstart) &mdash; Learn how create and connect your first database.
2. [SDK Quickstart](https://docs.turso.tech/sdk/ts/quickstart) &mdash; Learn how to install and execute queries using the libSQL client.
3. [SDK Reference](https://docs.turso.tech/sdk/ts/reference) &mdash; Dive deeper with the libSQL SDK reference and examples.
Visit our [official documentation](https://docs.turso.tech/sdk/ts).

## Support

Join us [on Discord](https://tur.so/discord-ts) to get help using this SDK. Report security issues [via email](mailto:security@turso.tech).

### What is Turso?
## Contributors

[Turso](https://turso.tech) is a SQLite-compatible database built on [libSQL](https://docs.turso.tech/libsql), the Open Contribution fork of SQLite. It enables scaling to hundreds of thousands of databases per organization and supports replication to any location, including your own servers, for microsecond-latency access.
See the [contributing guide](CONTRIBUTING.md) to learn how to get involved.

Learn more about what you can do with Turso:
![Contributors](https://contrib.nn.ci/api?repo=tursodatabase/libsql-client-ts)

- [Embedded Replicas](https://docs.turso.tech/features/embedded-replicas)
- [Platform API](https://docs.turso.tech/features/platform-api)
- [Data Edge](https://docs.turso.tech/features/data-edge)
- [Branching](https://docs.turso.tech/features/branching)
- [Point-in-Time Recovery](https://docs.turso.tech/features/point-in-time-recovery)
- [Scale to Zero](https://docs.turso.tech/features/scale-to-zero)
<a href="https://github.com/tursodatabase/libsql-client-ts/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22">
<picture>
<img src="https://img.shields.io/github/issues-search/tursodatabase/libsql-client-ts?label=good%20first%20issue&query=label%3A%22good%20first%20issue%22%20&color=0F624B" alt="good first issue" />
</picture>
</a>
16 changes: 16 additions & 0 deletions packages/libsql-client/examples/example.js
Original file line number Diff line number Diff line change
@@ -14,6 +14,22 @@ async function example() {
],
"write",
);

await db.batch(
[
{
sql: "INSERT INTO users (email) VALUES (?)",
args: ["alice@example.com"],
},
["INSERT INTO users (email) VALUES (?)", ["bob@example.com"]],
{
sql: "INSERT INTO users (email) VALUES (:email)",
args: { email: "charlie@example.com" },
},
],
"write",
);

const rs = await db.execute("SELECT * FROM users");
console.log(rs);
}
34 changes: 34 additions & 0 deletions packages/libsql-client/examples/sync_offline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { createClient } from "@libsql/client";
import reader from "readline-sync";

async function example() {
const config = {
url: process.env.URL ?? "file:local.db",
syncUrl: process.env.SYNC_URL,
authToken: process.env.AUTH_TOKEN,
offline: true,
};
const db = createClient(config);
await db.execute(
"CREATE TABLE IF NOT EXISTS guest_book_entries (comment TEXT)",
);

const comment = reader.question("Enter your comment: ");

await db.execute({
sql: "INSERT INTO guest_book_entries (comment) VALUES (?)",
args: [comment],
});

const rep2 = await db.sync();

console.log("frames_synced: " + rep2.frames_synced);

console.log("Guest book entries:");
const rs = await db.execute("SELECT * FROM guest_book_entries");
for (const row of rs.rows) {
console.log(" - " + row.comment);
}
}

example();
12 changes: 6 additions & 6 deletions packages/libsql-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@libsql/client",
"version": "0.14.0",
"version": "0.15.0",
"keywords": [
"libsql",
"database",
@@ -13,7 +13,8 @@
"description": "libSQL driver for TypeScript and JavaScript",
"repository": {
"type": "git",
"url": "https://github.com/libsql/libsql-client-ts"
"url": "git+https://github.com/libsql/libsql-client-ts",
"directory": "packages/libsql-client"
},
"authors": [
"Jan Špaček <honza@chiselstrike.com>",
@@ -94,24 +95,23 @@
"build": "npm run build:cjs && npm run build:esm",
"build:cjs": "tsc -p tsconfig.build-cjs.json",
"build:esm": "tsc -p tsconfig.build-esm.json",
"format:check": "prettier --check .",
"postbuild": "cp package-cjs.json ./lib-cjs/package.json",
"test": "jest --runInBand",
"typecheck": "tsc --noEmit",
"typedoc": "rm -rf ./docs && typedoc",
"prepare": "husky install",
"lint-staged": "lint-staged"
},
"dependencies": {
"@libsql/core": "^0.14.0",
"@libsql/core": "^0.15.0",
"@libsql/hrana-client": "^0.7.0",
"js-base64": "^3.7.5",
"libsql": "^0.4.4",
"libsql": "^0.5.0",
"promise-limit": "^2.7.0"
},
"devDependencies": {
"@types/jest": "^29.2.5",
"@types/node": "^18.15.5",
"husky": "^9.0.11",
"jest": "^29.3.1",
"lint-staged": "^15.2.2",
"msw": "^2.3.0",
6 changes: 3 additions & 3 deletions packages/libsql-client/src/__tests__/client.test.ts
Original file line number Diff line number Diff line change
@@ -814,7 +814,7 @@ describe("batch()", () => {
);

const n = 100;
const promises = [];
const promises = [] as Array<any>;
for (let i = 0; i < n; ++i) {
const ii = i;
promises.push(
@@ -885,7 +885,7 @@ describe("batch()", () => {
test(
"batch with a lot of different statements",
withClient(async (c) => {
const stmts = [];
const stmts = [] as Array<any>;
for (let i = 0; i < 1000; ++i) {
stmts.push(`SELECT ${i}`);
}
@@ -902,7 +902,7 @@ describe("batch()", () => {
const n = 20;
const m = 200;

const stmts = [];
const stmts = [] as Array<any>;
for (let i = 0; i < n; ++i) {
for (let j = 0; j < m; ++j) {
stmts.push({ sql: `SELECT ?, ${j}`, args: [i] });
33 changes: 22 additions & 11 deletions packages/libsql-client/src/hrana.ts
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import type {
ResultSet,
Transaction,
TransactionMode,
InArgs,
} from "@libsql/core/api";
import { LibsqlError } from "@libsql/core/api";
import type { SqlCache } from "./sql_cache.js";
@@ -255,7 +256,7 @@ export async function executeHranaBatch(
disableForeignKeys: boolean = false,
): Promise<Array<ResultSet>> {
if (disableForeignKeys) {
batch.step().run("PRAGMA foreign_keys=off")
batch.step().run("PRAGMA foreign_keys=off");
}
const beginStep = batch.step();
const beginPromise = beginStep.run(transactionModeToBegin(mode));
@@ -287,7 +288,7 @@ export async function executeHranaBatch(
.condition(hrana.BatchCond.not(hrana.BatchCond.ok(commitStep)));
rollbackStep.run("ROLLBACK").catch((_) => undefined);
if (disableForeignKeys) {
batch.step().run("PRAGMA foreign_keys=on")
batch.step().run("PRAGMA foreign_keys=on");
}

await batch.execute();
@@ -309,17 +310,27 @@ export async function executeHranaBatch(
return resultSets;
}

export function stmtToHrana(stmt: InStatement): hrana.Stmt {
if (typeof stmt === "string") {
return new hrana.Stmt(stmt);
}
export function stmtToHrana(stmt: InStatement | [string, InArgs?]): hrana.Stmt {
let sql: string;
let args: InArgs | undefined;

const hranaStmt = new hrana.Stmt(stmt.sql);
if (Array.isArray(stmt.args)) {
hranaStmt.bindIndexes(stmt.args);
if (Array.isArray(stmt)) {
[sql, args] = stmt;
} else if (typeof stmt === "string") {
sql = stmt;
} else {
for (const [key, value] of Object.entries(stmt.args)) {
hranaStmt.bindName(key, value);
sql = stmt.sql;
args = stmt.args;
}

const hranaStmt = new hrana.Stmt(sql);
if (args) {
if (Array.isArray(args)) {
hranaStmt.bindIndexes(args);
} else {
for (const [key, value] of Object.entries(args)) {
hranaStmt.bindName(key, value);
}
}
}

21 changes: 13 additions & 8 deletions packages/libsql-client/src/http.ts
Original file line number Diff line number Diff line change
@@ -96,9 +96,6 @@ export class HttpClient implements Client {
return this.#promiseLimitFunction(fn);
}

async execute(stmt: InStatement): Promise<ResultSet>;
async execute(sql: string, args?: InArgs): Promise<ResultSet>;

async execute(
stmtOrSql: InStatement | string,
args?: InArgs,
@@ -138,12 +135,22 @@ export class HttpClient implements Client {
}

async batch(
stmts: Array<InStatement>,
stmts: Array<InStatement | [string, InArgs?]>,
mode: TransactionMode = "deferred",
): Promise<Array<ResultSet>> {
return this.limit<Array<ResultSet>>(async () => {
try {
const hranaStmts = stmts.map(stmtToHrana);
const normalizedStmts = stmts.map((stmt) => {
if (Array.isArray(stmt)) {
return {
sql: stmt[0],
args: stmt[1] || [],
};
}
return stmt;
});

const hranaStmts = normalizedStmts.map(stmtToHrana);
const version = await this.#client.getVersion();

// Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the batch and
@@ -180,9 +187,7 @@ export class HttpClient implements Client {
});
}

async migrate(
stmts: Array<InStatement>,
): Promise<Array<ResultSet>> {
async migrate(stmts: Array<InStatement>): Promise<Array<ResultSet>> {
return this.limit<Array<ResultSet>>(async () => {
try {
const hranaStmts = stmts.map(stmtToHrana);
25 changes: 15 additions & 10 deletions packages/libsql-client/src/sqlite3.ts
Original file line number Diff line number Diff line change
@@ -83,6 +83,8 @@ export function _createClient(config: ExpandedConfig): Client {
encryptionKey: config.encryptionKey,
syncUrl: config.syncUrl,
syncPeriod: config.syncInterval,
readYourWrites: config.readYourWrites,
offline: config.offline,
};

const db = new Database(path, options);
@@ -119,9 +121,6 @@ export class Sqlite3Client implements Client {
this.protocol = "file";
}

async execute(stmt: InStatement): Promise<ResultSet>;
async execute(sql: string, args?: InArgs): Promise<ResultSet>;

async execute(
stmtOrSql: InStatement | string,
args?: InArgs,
@@ -142,7 +141,7 @@ export class Sqlite3Client implements Client {
}

async batch(
stmts: Array<InStatement>,
stmts: Array<InStatement | [string, InArgs?]>,
mode: TransactionMode = "deferred",
): Promise<Array<ResultSet>> {
this.#checkNotClosed();
@@ -156,7 +155,10 @@ export class Sqlite3Client implements Client {
"TRANSACTION_CLOSED",
);
}
return executeStmt(db, stmt, this.#intMode);
const normalizedStmt: InStatement = Array.isArray(stmt)
? { sql: stmt[0], args: stmt[1] || [] }
: stmt;
return executeStmt(db, normalizedStmt, this.#intMode);
});
executeStmt(db, "COMMIT", this.#intMode);
return resultSets;
@@ -167,9 +169,7 @@ export class Sqlite3Client implements Client {
}
}

async migrate(
stmts: Array<InStatement>,
): Promise<Array<ResultSet>> {
async migrate(stmts: Array<InStatement>): Promise<Array<ResultSet>> {
this.#checkNotClosed();
const db = this.#getDb();
try {
@@ -276,10 +276,15 @@ export class Sqlite3Transaction implements Transaction {
return executeStmt(this.#database, stmt, this.#intMode);
}

async batch(stmts: Array<InStatement>): Promise<Array<ResultSet>> {
async batch(
stmts: Array<InStatement | [string, InArgs?]>,
): Promise<Array<ResultSet>> {
return stmts.map((stmt) => {
this.#checkNotClosed();
return executeStmt(this.#database, stmt, this.#intMode);
const normalizedStmt: InStatement = Array.isArray(stmt)
? { sql: stmt[0], args: stmt[1] || [] }
: stmt;
return executeStmt(this.#database, normalizedStmt, this.#intMode);
});
}

21 changes: 13 additions & 8 deletions packages/libsql-client/src/ws.ts
Original file line number Diff line number Diff line change
@@ -154,9 +154,6 @@ export class WsClient implements Client {
return this.#promiseLimitFunction(fn);
}

async execute(stmt: InStatement): Promise<ResultSet>;
async execute(sql: string, args?: InArgs): Promise<ResultSet>;

async execute(
stmtOrSql: InStatement | string,
args?: InArgs,
@@ -195,13 +192,23 @@ export class WsClient implements Client {
}

async batch(
stmts: Array<InStatement>,
stmts: Array<InStatement | [string, InArgs?]>,
mode: TransactionMode = "deferred",
): Promise<Array<ResultSet>> {
return this.limit<Array<ResultSet>>(async () => {
const streamState = await this.#openStream();
try {
const hranaStmts = stmts.map(stmtToHrana);
const normalizedStmts = stmts.map((stmt) => {
if (Array.isArray(stmt)) {
return {
sql: stmt[0],
args: stmt[1] || [],
};
}
return stmt;
});

const hranaStmts = normalizedStmts.map(stmtToHrana);
const version = await streamState.conn.client.getVersion();

// Schedule all operations synchronously, so they will be pipelined and executed in a single
@@ -226,9 +233,7 @@ export class WsClient implements Client {
});
}

async migrate(
stmts: Array<InStatement>,
): Promise<Array<ResultSet>> {
async migrate(stmts: Array<InStatement>): Promise<Array<ResultSet>> {
return this.limit<Array<ResultSet>>(async () => {
const streamState = await this.#openStream();
try {
6 changes: 4 additions & 2 deletions packages/libsql-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@libsql/core",
"version": "0.14.0",
"version": "0.15.0",
"keywords": [
"libsql",
"database",
@@ -13,7 +13,8 @@
"description": "libSQL driver for TypeScript and JavaScript",
"repository": {
"type": "git",
"url": "https://github.com/libsql/libsql-client-ts"
"url": "git+https://github.com/libsql/libsql-client-ts",
"directory": "packages/libsql-core"
},
"authors": [
"Jan Špaček <honza@chiselstrike.com>",
@@ -70,6 +71,7 @@
"build": "npm run build:cjs && npm run build:esm",
"build:cjs": "tsc -p tsconfig.build-cjs.json",
"build:esm": "tsc -p tsconfig.build-esm.json",
"format:check": "prettier --check .",
"postbuild": "cp package-cjs.json ./lib-cjs/package.json",
"test": "jest --runInBand",
"typecheck": "tsc --noEmit",
15 changes: 10 additions & 5 deletions packages/libsql-core/src/api.ts
Original file line number Diff line number Diff line change
@@ -21,6 +21,12 @@ export interface Config {
/** Sync interval in seconds. */
syncInterval?: number;

/** Read your writes */
readYourWrites?: boolean;

/** Enable offline writes */
offline?: boolean;

/** Enables or disables TLS for `libsql:` URLs.
*
* By default, `libsql:` URLs use TLS. You can set this option to `false` to disable TLS.
@@ -87,6 +93,7 @@ export interface Client {
* ```
*/
execute(stmt: InStatement): Promise<ResultSet>;
execute(sql: string, args?: InArgs): Promise<ResultSet>;

/** Execute a batch of SQL statements in a transaction.
*
@@ -122,7 +129,7 @@ export interface Client {
* ```
*/
batch(
stmts: Array<InStatement>,
stmts: Array<InStatement | [string, InArgs?]>,
mode?: TransactionMode,
): Promise<Array<ResultSet>>;

@@ -155,9 +162,7 @@ export interface Client {
* ]);
* ```
*/
migrate(
stmts: Array<InStatement>,
): Promise<Array<ResultSet>>;
migrate(stmts: Array<InStatement>): Promise<Array<ResultSet>>;

/** Start an interactive transaction.
*
@@ -470,7 +475,7 @@ export type Value = null | string | number | bigint | ArrayBuffer;

export type InValue = Value | boolean | Uint8Array | Date;

export type InStatement = { sql: string; args: InArgs } | string;
export type InStatement = { sql: string; args?: InArgs } | string;
export type InArgs = Array<InValue> | Record<string, InValue>;

/** Error thrown by the client. */
6 changes: 6 additions & 0 deletions packages/libsql-core/src/config.ts
Original file line number Diff line number Diff line change
@@ -13,6 +13,8 @@ export interface ExpandedConfig {
encryptionKey: string | undefined;
syncUrl: string | undefined;
syncInterval: number | undefined;
readYourWrites: boolean | undefined;
offline: boolean | undefined;
intMode: IntMode;
fetch: Function | undefined;
concurrency: number;
@@ -174,6 +176,8 @@ export function expandConfig(
concurrency,
syncUrl: config.syncUrl,
syncInterval: config.syncInterval,
readYourWrites: config.readYourWrites,
offline: config.offline,
fetch: config.fetch,
authToken: undefined,
encryptionKey: undefined,
@@ -192,6 +196,8 @@ export function expandConfig(
encryptionKey: config.encryptionKey,
syncUrl: config.syncUrl,
syncInterval: config.syncInterval,
readYourWrites: config.readYourWrites,
offline: config.offline,
fetch: config.fetch,
};
}