AI prompts
base on A self-hosted backend for Deno KV # denokv
A self-hosted backend for [Deno KV](https://deno.com/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](./.github/diagram-dark.png#gh-dark-mode-only)
![Diagram showing how a `denokv` setup looks](./.github/diagram-light.png#gh-light-mode-only)
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](https://deno.com/blog/building-deno-kv) on
[Deno Deploy](https://deno.com/deploy), or with this self-hostable Deno KV
backend.
To run `denokv`, just run:
```sh
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:
```ts
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](https://docs.deno.com/kv/manual/on_deploy#connect-to-managed-databases-from-outside-of-deno-deploy).
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](https://deno.com/blog/kv-is-open-source-with-continuous-backup).
## 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.
```sh
$ mkdir -p /data
```
Then run the `denokv` Docker image, mounting the `/data` directory as a volume
and specifying a random access token.
```sh
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](https://fly.io/docs/hands-on/install-flyctl/).
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.
```toml
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](https://github.com/denoland/denokv/releases/tag/0.1.0) 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:
```ts
const kv = await Deno.openKv("http://localhost:4512");
```
Make sure to specify your access token in the `DENO_KV_ACCESS_TOKEN` environment
variable.
<!-- TBD: ### Node.js -->
## 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:
```sh
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:
```sh
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:
```sh
denokv --sqlite-path /data/denokv.sqlite pitr list
```
To checkout the snapshot at a specific recoverable point:
```sh
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`](./proto/kv-connect.md).
", Assign "at most 3 tags" to the expected json: {"id":"5043","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"