Skip to content

Personal draft DB (CLI) ​

Set up your own local nostr event DB. Drafts are real signed events with an ephemeral key that are ingested with the client flag (processEvent(json, { client: 1 }) — Notedeck's IngestMetadata::new().client(true)) and never sent to any relay. See docs/notedeck-usage.md (use-case 9) and packages/bunostrdb/src/drafts.ts.

All commands accept --db <path> (defaults to ./data). A missing directory is created for you — first run just works.

1. Draft a note ​

bash
bun run cli -- draft-note --db ./data.drafts --content "my first local draft"

Output is the stored event JSON plus its id. Re-run with --kind 30023 (or any kind) for longform/other kinds.

2. Draft a reaction to an event id ​

bash
bun run cli -- draft-reaction --db ./data.drafts --target <64-char-hex-event-id>
# custom emoji / content:
bun run cli -- draft-reaction --db ./data.drafts --target <hex> --content "🤙"

This builds a kind-7 event with an #e tag pointing at the target — stored locally only.

3. Draft a profile (kind 0) ​

bash
bun run cli -- draft-profile --db ./data.drafts --name "alice" --about "local drafts only"

4. Query it back ​

Existing commands work unchanged against the same --db:

bash
# kind-1 notes, latest 10
bun run cli -- query --db ./data.drafts --filter '{"kinds":[1],"limit":10}' --limit 10
# the reaction you just drafted
bun run cli -- query --db ./data.drafts --filter '{"kinds":[7]}' --limit 10
# fetch one note by id
bun run cli -- get-note --db ./data.drafts --id <hex>

5. Full-text search for anything ​

bash
bun run cli -- search --db ./data.drafts --query "local draft" --limit 20

Ranked standalone search (BunNdb.textSearch(), limit capped at 128). For filter-scoped search, use FilterBuilder.search() + query() instead.

Notes ​

  • Ingestion is asynchronous: the CLI waits with waitForNoteById() (default 10s, override with --timeout <ms>) before reporting success — it never reports "stored" from queue acceptance alone.
  • Draft identity: each draft mints a fresh ephemeral secret by default. To keep one identity across drafts, use the library (createDraftEvent({ secret })) instead of the CLI.
  • Programmatic use:
ts
// @ts-nocheck
import { BunNdb } from "bunostrdb";
import { buildDraftNote, ingestDraft, searchDrafts } from "bunostrdb";

{
	using ndb = new BunNdb("./data.drafts");
	const draft = buildDraftNote("hello local world");
	const id = await ingestDraft(ndb, draft.eventJson);
	console.log("stored draft", id);
	console.log(searchDrafts(ndb, "hello"));
}

Run from the repo root (after bun install, which links the bunostrdb workspace). Against an installed bunostrdb package, the same "bunostrdb" import works unchanged.

Released under the BSD-3.0 License.