Code Monkey home page Code Monkey logo

denokv's Introduction

denokv

A self-hosted backend for Deno KV, the JavaScript first key-value database:

  • Seamlessly integrated JavaScript APIs
  • ACID transactions
  • Multiple consistency levels for optimal performance for every usecase

Diagram showing how a denokv setup looks Diagram showing how a denokv setup looks

Deno KV can be used with the built-in single instance database in the CLI, useful for testing and development, with a hosted and scalable backend on Deno Deploy, or with this self-hostable Deno KV backend.

To run denokv, just run:

docker run -it --init -p 4512:4512 -v ./data:/data ghcr.io/denoland/denokv --sqlite-path /data/denokv.sqlite serve --access-token <random-token>

Then run your Deno program and specify the access token in the DENO_KV_ACCESS_TOKEN environment variable:

const kv = await Deno.openKv("http://localhost:4512");

The self-hosted denokv backend is built on the same robust SQLite backend as the built-in single instance database in the CLI. It is designed to be run on a VPS or Kubernetes cluster statefully, with Deno processes connecting via the network using KV Connect.

The standalone denokv binary is designed to handle thousands of concurrent requests, from hundreds of different Deno processes. It is built on top of the robust SQLite database, and uses non-blocking IO to ensure excellent performance even in the face of hundreds of concurrent connections.

Just like the Deno CLI, denokv is MIT licensed, free and open source.

Read more in the announcement of self-hosted Deno KV.

When should I use this?

If you need more than a single Deno process to access the same KV database, and you are ok with running a server, keeping denokv updated, handling backups, and performing regular maintenance, then this is for you.

You can use a hosted KV database on Deno Deploy if you don't want to self-host and manage a denokv server.

If you are just need a backend for local development or testing, you can use the Deno KV backend built into the Deno CLI. You can open a temporary in memory KV database with Deno.openKv(":memory:") or a persistent database by specifying a path like Deno.openKv("./my-database.sqlite").

How to run

Docker on a VPS

Ensure that you are running on a service that supports persistent storage, and does not perform auto-scaling beyond a single instance. This means you can not run denokv on Google Cloud Run or AWS Lambda.

Install Docker on your VPS and create a directory for the database to store data in.

$ mkdir -p /data

Then run the denokv Docker image, mounting the /data directory as a volume and specifying a random access token.

docker run -it --init -p 4512:4512 -v ./data:/data ghcr.io/denoland/denokv --sqlite-path /data/denokv.sqlite serve --access-token <random-token>

You can now access the database from your Deno programs by specifying the access token in the DENO_KV_ACCESS_TOKEN environment variable, and the host and port of your VPS in the URL passed to Deno.openKv.

You should additionally add a HTTPS terminating proxy or loadbalancer in front of denokv to ensure that all communication happens over TLS. Not using TLS can pose a significant security risk. The HTTP protocol used by Deno KV is compatible with any HTTP proxy, such as caddy, nginx, or a loadbalancer.

Fly.io

You can easily host denokv on https://fly.io.

Note: Fly.io is a paid service. You will need to add a credit card to your account to use it.

Sign up to Fly.io and install the flyctl CLI.

Sign into the CLI with flyctl auth login.

Create a new app with flyctl apps create.

Create a fly.toml file with the following contents. Make sure to replace the <your-app-name> and <region> placeholders with your app name and the region you want to deploy to.

app = "<your-app-name>"
primary_region = "<region>"

[build]
  image = "ghcr.io/denoland/denokv:latest"

[http_service]
  internal_port = 4512
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 0

[env]
  DENO_KV_SQLITE_PATH="/data/denokv.sqlite3"
  # access token is set via `flyctl secrets set`

[mounts]
  destination = "/data"
  source = "denokv_data"

Run flyctl volumes create denokv_data to create a volume to store the database in.

Run flyctl secrets set DENO_KV_ACCESS_TOKEN=<random-token> to set the access token. Make sure to replace <random-token> with a random string. Keep this token secret, and don't share it with anyone. You will need this token to connect to your database from Deno.

Run flyctl deploy to deploy your app.

You can now access the database from your Deno programs by specifying the access token in the DENO_KV_ACCESS_TOKEN environment variable, and the URL provided by flyctl deploy in the URL passed to Deno.openKv.

Be aware that with this configuration, your database can scale to 0 instances when not in use. This means that the first request to your database after a period of inactivity will be slow, as the database needs to be started. You can avoid this by setting min_machines_running to 1, and setting auto_stop_machines = false.

Install binary

You can download a prebuilt binary from the releases page and place it in your PATH.

You can also compile from source by running cargo install denokv --locked.

How to connect

Deno

To connect to a denokv server from Deno, use the Deno.openKv API:

const kv = await Deno.openKv("http://localhost:4512");

Make sure to specify your access token in the DENO_KV_ACCESS_TOKEN environment variable.

Advanced setup

Running as a replica of a hosted KV database

denokv has a mode for running as a replica of a KV database hosted on Deno Deploy through the S3 backup feature.

To run as a replica:

docker run -it --init -p 4512:4512 -v ./data:/data \
  -e AWS_ACCESS_KEY_ID="<aws-access-key-id>" \
  -e AWS_SECRET_ACCESS_KEY="<aws-secret-access-key>" \
  -e AWS_REGION="<aws-region>" \
  ghcr.io/denoland/denokv --sqlite-path /data/denokv.sqlite serve \
  --access-token <random-token> --sync-from-s3 --s3-bucket your-bucket --s3-prefix some-prefix/6aea9765-2b1e-41c7-8904-0bdcd70b21d3/

To sync the local database from S3, without updating the snapshot:

denokv --sqlite-path /data/denokv.sqlite pitr sync --s3-bucket your-bucket --s3-prefix some-prefix/6aea9765-2b1e-41c7-8904-0bdcd70b21d3/

To list recoverable points:

denokv --sqlite-path /data/denokv.sqlite pitr list

To checkout the snapshot at a specific recoverable point:

denokv --sqlite-path /data/denokv.sqlite pitr checkout 0100000002c0f4c10000

Continuous backup using LiteFS

TODO

Other things in this repo

This repository contains two crates:

  • denokv_proto (/proto): Shared interfaces backing KV, like definitions of Key, Database, and Value.
  • denokv_sqlite (/sqlite): An implementation of Database backed by SQLite.
  • denokv_remote (/remote): An implementation of Database backed by a remote KV database, acessible via the KV Connect protocol.

These crates are used by the deno_kv crate in the Deno repository to provide a JavaScript API for interacting with Deno KV.

The Deno KV Connect protocol used for communication between Deno and a remote KV database is defined in /proto/kv-connect.md.

denokv's People

Contributors

igorzi avatar john-pope avatar johnspurlock-skymethod avatar lambtron avatar losfair avatar lucacasonato avatar mmastrac avatar nathanwhit avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

denokv's Issues

S3 backup feature

Is it possible to enter custom S3 endpoint url as docker env variable AWS_ENDPOINT? I'm using minio as my S3 provider.

Support for multiple data structures

Currently deno kv uses only key-value store system. Which is fast but I really miss hash like redis provides key field-value system.
Also incrementing values is a bit more handy than just simply using val.incrBy().

Will KV always remain just as it is right now or it will extend its wings?

`denokv serve`: `500 An internal server error occurred` when attempting to sum a non kvu64

To reproduce: run denokv serve locally, connect via Deno.openKv, then attempt a sum operation on an existing non kvu64 value.

Expected:
http 4xx response, this is a non-retryable client error

Actual:
An error is logged: [ERROR denokv] Failed to write to database: Failed to perform 'sum' mutation on a non-U64 value in the database and an http 500 is returned to the client with body An internal server error occurred. The spec encourages retrying 5xx, so it's probably important to return a 4xx here instead.

Issues No loader is configured for ".node" files: ... deno-kv-napi.win32-x64-msvc.node

I tested the code in a minimal environment using vite and get the following error.

X [ERROR] No loader is configured for ".node" files: node_modules/@deno/kv-win32-x64-msvc/deno-kv-napi.win32-x64-msvc.node

node_modules/@deno/kv/esm/_napi_index.cjs:41:36:
  41 │             nativeBinding = require('@deno/kv-win32-x64-msvc')
     ╵                                     ~~~~~~~~~~~~~~~~~~~~~~~~~

14:29:21 [vite] error while updating dependencies:
Error: Build failed with 2 errors:
node_modules/@deno/kv/esm/_napi_index.cjs:41:36: ERROR: No loader is configured for ".node" files: node_modules/@deno/kv-win32-x64-msvc/deno-kv-napi.win32-x64-msvc.node
node_modules/@deno/kv/esm/napi_based.js:34:31: ERROR: Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)
at failureErrorWithLog (D:\workspace\test\denokv-for-issue\min-vite\node_modules\esbuild\lib\main.js:1650:15)
at D:\workspace\test\denokv-for-issue\min-vite\node_modules\esbuild\lib\main.js:1058:25
at D:\workspace\test\denokv-for-issue\min-vite\node_modules\esbuild\lib\main.js:1526:9
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

We have prepared the code for testing in the following repository
This problem does not occur with min-node, but can be reproduced with min-vite.
https://github.com/rinjugatla/denokv-for-issue

Problem with the npm package and vite/esbuild

I can't get @deno/kv to work with vite nor esbuild.

With vite/rollup I get:

[commonjs--resolver] Unexpected character '' (Note that you need plugins to import files that are not JavaScript)
file: /home/murphy/.../obsidian-memorize/node_modules/@deno/kv/esm/_napi_index.cjs:1:0
1: ELF>��@ �/@8 @����...
   ^
2: ���_:��|`�EoS>...
3: l�...

Which appears to be related to: vitejs/vite#3304 and vitejs/vite#12246. I don't know much else though. I am not very familiar with bundlers and all the cjs vs esm details. After all I tried I do think it's a thing about this package though.

With esbuild I get some other errors. I am mostly interested in getting it with vite to work though
✘ [ERROR] Top-level await is currently not supported with the "cjs" output format

    node_modules/@deno/kv/esm/napi_based.js:34:31:
      34 │ const DEFAULT_NAPI_INTERFACE = await import('./_napi_index.cjs');
         ╵                                ~~~~~

✘ [ERROR] No loader is configured for ".node" files: node_modules/@deno/kv-linux-x64-gnu/deno-kv-napi.linux-x64-gnu.node

    node_modules/@deno/kv/esm/_napi_index.cjs:92:38:
      92 │               nativeBinding = require('@deno/kv-linux-x64-gnu')
         ╵                                       ~~~~~~~~~~~~~~~~~~~~~~~~

A bit of context: I am writing an obsidian.md plugin. So all code gets bundled into a single main.js which then gets run by obsidian (an electron app).

Error: Unsupported architecture on Linux: arm64

Problem

Environment:

On installing the @deno/kv package I get this runtime error

functions-1  | /opt/project/functions/node_modules/@deno/kv/script/_napi_index.cjs:100
functions-1  |         throw new Error(`Unsupported architecture on Linux: ${arch}`)
functions-1  |               ^
functions-1  |
functions-1  | Error: Unsupported architecture on Linux: arm64
functions-1  |     at Object.<anonymous> (/opt/project/functions/node_modules/@deno/kv/script/_napi_index.cjs:100:15)
functions-1  |     at Module._compile (node:internal/modules/cjs/loader:1256:14)

Looking into /opt/project/functions/node_modules/@deno/kv/script/_napi_index.cjs:100 then yes there is no matching package (linux/arm64)

This is the environment you can get in docker in macos.

Solution

Maybe add an automated build for linux/arm64

This architecture is also on e.g. raspberry pi devices.

NPM: Wrap the Deno KV API if available

The NPM package should just re-export the values of Deno if Deno's native KV API is available, so that Node projects using @deno/kv can be more easily ported to Deno.

Error: Cannot find module 'module "@deno/kv-darwin-x64"'

Working in Bun and NextJS 14.0.3, got this error using server actions
ran bun install @deno/kv

<form action={write}>
        <Button type="submit">Click</Button>
 </form>
"use server";

import { openKv } from "@deno/kv";

export const write = async (formD: FormData) => {
  const kv = await openKv("kv.db");
  const result = await kv.set(["Greetings"], "hello!");
  console.log({ result });
  kv.close();
  return result;
};
image

Ran also bun i @deno/kv-darwin-x64 but I am still getting the same error.

Feature Request: Ship a WASM Binary

Since all major browsers now support the origin-private file system, I think the sqlite-backed version of Deno KV should be able to be shipped to the browser as a WASM package and run on the client.

Issues Top-level await is not available in the configured target environment

I tested the code in a minimal environment using vite and get the following error.

X [ERROR] Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)

node_modules/@deno/kv/esm/napi_based.js:34:31:
  34 │ const DEFAULT_NAPI_INTERFACE = await import('./_napi_index.cjs');
     ╵                                ~~~~~

We have prepared the code for testing in the following repository
This problem does not occur with min-node, but can be reproduced with min-vite.
https://github.com/rinjugatla/denokv-for-issue

This problem could also be solved by installing the following plugin.
https://github.com/Menci/vite-plugin-top-level-await

How to sync to s3?

what is the commandline option to sync to s3?
I see --sync-from s3 but it seems like the docs for sync to s3 are missing.

Kind Regards,
spirobel

Update docs: unexpected argument '--sqlite-path' found when following examples

When following documentation, I am trying to use the denokv standalone and am getting

error: unexpected argument '--sqlite-path' found

Usage: denokv --sqlite-path <SQLITE_PATH> serve [OPTIONS] --access-token <ACCESS_TOKEN>

For more information, try '--help'.

This is when running with either installing with cargo or the docker container, reproduce with:

export DENO_KV_ACCESS_TOKEN=$(openssl rand -base64 15)
docker run -it --init -p 4512:4512 -v ./data:/data ghcr.io/denoland/denokv serve --sqlite-path /data/denokv.sqlite serve --access-token $DENO_KV_ACCESS_TOKEN

--sqlite-path has to be before serve, docs need to be updated

Keys & Values separately

The Kv client currently has

list<T>(selector: KvListSelector, options?: KvListOptions): AsyncIterableIterator<{ key: KvKey, entry: T }[]>

Would be nice to be able to get the keys alone without needing to retrieve the entries

keys(selector: KvListSelector, options?: KvListOptions): AsyncIterableIterator<KvKey[]>

Thinking ahead, a similar function could be if you want just the values directly matching:

values<T>(selector: KvListSelector, options?: KvListOptions): AsyncIterableIterator<T>

This would match keys functionality available with other kv implementations:

A way to "NOT" expire the value when using get() ?

It seems Kv.get() will auto-expire the value every time it's used. This is nice, but I have no idea how much time it's adding to its current expire time.

I'd also like an option to use get() without increasing the expiration time, if possible.

Create subdirectories for Deno.openKv calls

My rust skills are garbage, otherwise i would just provide a PR.

The issue i am facing is that if i try to open a KV instance in a sub directory, it fails if the directory doesn't exist

const denoKv = await Deno.openKv('./denokv/deno.db');

To get around this, we create a ./denokv/.gitkeep file, but it would be nice if it worked with sub directories out of the box by creating the directory if it does not exist.

Support HTTPS

As far as I can tell, denokv only supports HTTP connections and not HTTPS which limits its ability from a self hosting perspective from a security aspect.

Expose Liveness and Readiness endpoints

Please expose unauthenticated HTTP endpoints for checking liveness and readiness of the server.

for example, the simplest implementation could just both return a HTTP 204 response:

GET /livez  --> HTTP 204
GET /readyz --> HTTP 204

this can be used for Kubernetes pod probes or other downstream systems (or monitoring)

Typo on Deno KV docs

Typo "becaus" should be "because".
It is found on this page
Screenshot so you can find it nice and easy:

Typo

Y'all are awesome and Marvin Hagemeister is an absolute legend.

Incomplete Value Type Support in Rust Crates for Deno KV

We are using deno_kv and denokv_proto both crates to interact with Deno KV from Rust. While key types are supported as expected, the available value types in the Rust crates appear to be limited compared to those documented for Deno KV itself.

Official Deno KV Documentation
Supported Value Types

Rust Crate Documentation
Supported Key Types
Supported Value Types

Request
Please consider expanding the value type support in the Rust crates to align with the Deno KV documentation.
If there are specific reasons for the current limitations, please provide clarification and potential workarounds.

TypeError: too many ranges (max 10)

Hi,
my project on Deno deploy throws the next error. I can't found anything about this on documentation. getMany operation hast limitation to 10 items?

TypeError: too many ranges (max 10)
    at Kv.getMany (ext:deno_kv/01_db.ts:58:31)
deno --version
deno 1.39.0 (release, aarch64-apple-darwin)
v8 12.0.267.8
typescript 5.3.3

Edit

Confirmed, getMany has limitation for 10 items.

Supported Features

Please add a section about supported features to the README.md

Supported Features

  • transactions
  • enqueue
  • listenQueue
  • watch

Deno.KV expireIn time

Either there's a bug, or I don't understand how {expireIn} works or the documentation is not right.

I'm doing:

await kv.set(key, value, { expireIn: 4000 });

In this code, I'm expecting the key/value to expire and return null after 4 seconds (4000 milliseconds).

However, the get() function continues to work.

It eventually does expire, but not in 4 seconds or 4000 seconds. Is this a bug?

How to delete data in Kv

For example I have a list of Kv value stored in my local machine stored like this

    //create a new UID for todo item.
    item.id = crypto.randomUUID();
    const kv = await Deno.openKv();
    await kv.set(["items", item.id], todo);

All I found is

delete(key: KvKey): Promise
Delete the value for the given key from the database. If no value exists for the key, this operation is a no-op.

How to delete all the data inserted into the database without explicitly providing all the UIDs.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.