
Research
NPM targeted by malware campaign mimicking familiar library names
Socket uncovered npm malware campaign mimicking popular Node.js libraries and packages from other ecosystems; packages steal data and execute remote code.
I just wanted a damn simple typescript database. String keys. Json values.
Kv is an agnostic interface. You jam in different drivers to write data in-memory, or to local storage, or to leveldb.
Kv does smart stuff, like namespacing, batch operations, and atomic write transactions.
@e280/kv
npm install @e280/kv
MemDriver
by default
import {Kv} from "@e280/kv"
const kv = new Kv()
LevelDriver
to use leveldb, a local on-disk database (kinda like sqlite)
import {Kv} from "@e280/kv"
import {LevelDriver} from "@e280/kv/level"
const kv = new Kv(new LevelDriver("path/to/database"))
StorageDriver
to use browser localStorage
import {Kv, StorageDriver} from "@e280/kv"
const kv = new Kv(new StorageDriver())
await kv.set("101", "hello")
await kv.set("102", 123.456)
await kv.get("101") // "hello"
await kv.get("102") // 123.456
await kv.get("103") // undefined
// create a kv instance
const kv = new Kv()
// creating some typed namespaces for which i'll insert records
const accounts = kv.namespace<Account>("accounts")
const characters = kv.namespace<Character>("characters")
// my app's function for adding a character to an account
async function addCharacter(accountId: string, character: Character) {
// obtain the account
const account = await accounts.require(accountId)
// actually uses key `accounts:${accountId}` because of the namespace prefix
// modifying the data
character.ownerId = account.id
account.characterIds.push(character.id)
// create an atomic write transaction to save the data
await kv.transaction(() => [
accounts.write.set(account.id, account),
characters.write.set(character.id, character),
])
}
// my app's function for listing all characters
async function listCharacters(accountId: string) {
const account = await accounts.require(accountId)
return characters.requires(...account.characterIds)
}
set
saves key-value pairs
await kv.set("hello", "world")
set
can save any serializable json-friendly javascript crap
await kv.set("hello", {data: ["world"], count: 123.456})
set
will interpret undefined
as the same as a deletion (like json)
await kv.set("hello", undefined) // same as deleting "hello"
null
instead of you want the key to existsets
saves many pairs, as an atomic batch
await kv.sets(["101", "alpha"], ["102", "bravo"])
get
loads a value (or undefined if the key's not found)
await kv.get("101")
// "alpha" (or undefined)
gets
loads many values at once (undefined for not-found keys)
await kv.gets("101", "102", "103")
// ["alpha", "bravo", undefined]
del
deletes things
await kv.del("hello")
del
can also delete many things
await kv.del("101", "102", "103")
has
checks if a key exists
await kv.has("hello")
// true (or false)
hasKeys
checks many keys
await kv.hasKeys("101", "102", "103")
// [true, true, false]
require
gets a value, but throws an error if the key is missing
await kv.require("101")
// "world" (or an error is thrown)
requires
gets many things, throws an error if any keys are missing
await kv.requires("101", "102")
// ["alpha", {data: 123.45}] (or an error is thrown)
guarantee
gets or creates a thing
await kv.guarantee("hello", () => "world")
// "world"
// all these succeed or fail together
await kv.transaction(write => [
write.del("obsolete:99"),
write.set("owners:4", [101, 102]),
write.sets(
["records:101", {msg: "lol", owner: 4}],
["records:102", {msg: "lel", owner: 4}],
),
])
write.set
, write.sets
, and write.del
to schedule write operations into the transactionconst records = kv.namespace("records")
// writes to key "records:123"
await records.set("123", "lol")
const records = kv.namespace("records")
await records.set("124", {data: "bingus"})
await records.transaction(write => [write.del("124")])
const records = kv.namespace("records")
const owners = records.namespace("owners")
const accounts = records.namespace("accounts")
// writes to key "records.owners:5"
await owners.set("5", "lol")
// writes to key "records.accounts:123"
await accounts.set("123", "rofl")
type MyData = {count: number}
// provide your type
// 👇
const records = kv.namespace<MyData>("records")
// now typescript knows `count` is a number
const {count} = records.get("123")
const records = kv.namespace("records")
const owners = records.namespace("owners")
const accounts = records.namespace("accounts")
await kv.transaction(() => [
owners.write.set("5", {records: [101, 102]}),
accounts.write.set("101", {data: "alpha", owner: 5}),
accounts.write.set("102", {data: "bravo", owner: 5}),
])
const login = kv.store<Login>("login")
// save data to the store
await login.set({token: "lol"})
// load data from the store
const {token} = await login.get()
export abstract class Driver {
abstract gets(...keys: string[]): Promise<(string | undefined)[]>
abstract hasKeys(...keys: string[]): Promise<boolean[]>
abstract keys(scan?: Scan): AsyncGenerator<string>
abstract entries(scan?: Scan): AsyncGenerator<[string, string]>
abstract transaction(...writes: Write[]): Promise<void>
}
transaction
only has to support two kinds of Write objects, set
and del
// instance your new driver and give it to Kv
const kv = new Kv(new MyDriver())
FAQs
Simple abstract key-value json database
We found that @e280/kv demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Socket uncovered npm malware campaign mimicking popular Node.js libraries and packages from other ecosystems; packages steal data and execute remote code.
Research
Socket's research uncovers three dangerous Go modules that contain obfuscated disk-wiping malware, threatening complete data loss.
Research
Socket uncovers malicious packages on PyPI using Gmail's SMTP protocol for command and control (C2) to exfiltrate data and execute commands.