Repository navigation
Description
Motivation
An application already using SqliteKvStore should be able to adopt a feature that needs atomic multi-key state without constructing another backend-specific store. The shared contract is useful for general application state as well as delivery suspension and durable backlog. This issue makes the existing @fedify/sqlite adapter a usable AtomicKvStore in its documented support scope.
Proposed API and use
Implement AtomicKvStore on SqliteKvStore. Keep its existing constructor and ordinary KV methods. Add the proposed signatures below, with the supporting entry types defined by the contract issue:
getMany<T = unknown>(keys: readonly KvKey[]): Promise<(T | undefined)[]>;
setMany(entries: readonly KvStoreSetEntry[]): Promise<void>;
deleteMany(keys: readonly KvKey[]): Promise<void>;
casMany(entries: readonly KvStoreCasEntry[]): Promise<boolean>;Keep cas() and make all five methods meet the shared contract. A proposed application use is:
import type { AtomicKvStore } from "@fedify/fedify";
import { DatabaseSync } from "node:sqlite";
import { SqliteKvStore } from "@fedify/sqlite";
const db = new DatabaseSync("./fedify.sqlite");
const store: AtomicKvStore = new SqliteKvStore(db);
const keys = [["example", "notice"], ["example", "budget"]] as const;
const [notice, budget] = await store.getMany(keys);
const committed = await store.casMany([
{ key: keys[0], expectedValue: notice, newValue: nextNotice },
{ key: keys[1], expectedValue: budget, newValue: nextBudget },
]);The application computes nextNotice and nextBudget from the snapshot and re-evaluates its rule when the result is false. Connection configuration and client shutdown remain the application's responsibility. These calls are proposed additions, not currently shipped methods.
Backend implementation and choices
Implement the complete batch within a SQLite transaction through each existing supported wrapper. Validate and encode inputs before starting mutation; consistently check logical expiry and reject duplicate mutation keys. Protect absent and existing keys against competing writers using the database's actual transaction semantics.
Test Node/Deno's node:sqlite path and Bun's bun:sqlite path. Exercise competing handles where supported, rollback after an early mutation, expired entries, mixed writes/deletes and reopen persistence. An in-memory single-connection test alone is insufficient to establish behavior for a persistent database with competing handles. Preserve current constructor and initialization behavior.
A JavaScript mutex cannot coordinate other database handles or processes. Sequential single-key operations also expose intermediate state. Use database transactions and the existing runtime-specific wrappers, without a new storage dependency or FEP-f799-specific store class.
Shipping criteria
Run the shared Atomic KV conformance suite and the SQLite-specific concurrency/failure cases against a supported backend. Verify the package's declared Node, Deno and Bun support, its consumer declarations, and existing KV regression tests. Document unsupported batch scope and limits; do not silently weaken an atomic call or treat method presence as proof of durability.
Revise the SqliteKvStore support row and custom-adapter contract in docs/manual/kv.md, packages/sqlite/README.md, public JSDoc, and relevant KV-selection skill guidance. Add the adapter's changelog fragment. Ship this adapter independently of other backend implementations and of delivery suspension.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Effort
Activity
AtomicKvStore#1363