
Research
Malicious npm Packages Impersonate Flashbots SDKs, Targeting Ethereum Wallet Credentials
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
A type-safe, functional-inspired ORM for local JSON/YAML file-based data sources.
“The best ORM is the one you can
cat
.” – ancient proverb
Konro is a zero-config, type-safe, file-native ORM that treats your local filesystem like a grown-up database. Define a schema, get full TypeScript inference, then read/write JSON/YAML/CSV/XLSX with the same ergonomics as Prisma—no Docker, no migrations, no TCP sockets, no SaaS invoices. Perfect for CLI tools, electron apps, serverless side-projects, or that hack-day idea you swore would “only live in-memory” but somehow shipped to prod.
Konro is inspired by the art of Indonesian cooking, where a rich soup or Konro
is made by carefully combining a base broth with a precise recipe and a collection of spices. Konro treats your data with the same philosophy.
import { konro } from 'konro';
// 1. Schema = single source of truth
const schema = konro.createSchema({
tables: {
user: {
id: konro.id(),
email: konro.string({ format: 'email', unique: true }),
name: konro.string({ max: 120 }),
createdAt: konro.createdAt(),
},
post: {
id: konro.id(),
title: konro.string({ max: 255 }),
body: konro.string(),
authorId: konro.number(),
published: konro.boolean({ default: false }),
},
},
relations: ({ user, post }) => ({
user: {
posts: konro.many('post', { on: 'id', references: 'authorId' }),
},
post: {
author: konro.one('user', { on: 'authorId', references: 'id' }),
},
}),
});
// 2. Pick a persistence flavour
const adapter = konro.createFileAdapter({
format: 'json',
single: { filepath: './db.json' }, // one fat file
// multi: { dir: './tables' }, // one file per table
// perRecord: { dir: './rows' }, // one file per row (git-friendly)
});
// 3. Get a typed db handle
const db = konro.createDatabase({ schema, adapter });
// 4. CRUD like it’s 2025
const [newState, alice] = db.insert('user', { email: 'alice@konro.dev', name: 'Alice' });
const posts = db
.query(newState)
.from('post')
.with({ author: true })
.where(p => p.published)
.all();
// 5. Ship it
console.table(posts);
✅ Use Konro for:
❌ Consider other solutions if you need:
on-demand
mode helps with memory, complex relational queries still load data into memory. For gigabyte-scale relational processing, a dedicated database server is more appropriate.Postgres | SQLite | Firebase | Konro |
---|---|---|---|
Needs a process | Needs C bindings | Needs Wi-Fi | Needs fs |
100 MB Docker image | 5 MB native lib | 0 MB (until the bill) | 0 MB (already on disk) |
Migrations, locks, WAL | WAL, locks, ALTER TABLE | Offline queue... lol | Git-mergeable text files |
SELECT * FROM user | SELECT * FROM user | .collection('user').get() | db.query().from('user').all() with types |
“But CSV isn’t a real database format!” – you, seconds before realising every government on earth runs on Excel.
npm i konro
# Optional peer deps (auto-loaded when needed)
npm i js-yaml papaparse xlsx # YAML / CSV / Excel support
Strategy | Format | Mode | Use-case |
---|---|---|---|
single | json/yaml | in-memory | Side-project MVP – load everything, iterate fast |
multi | json/yaml/csv/xlsx | on-demand | Medium data – lazy-load tables, still human-readable |
perRecord | json/yaml | on-demand | Git-nirvana – each row = 1 file, git diff shows real rows |
CSV/XLSX are tabular-only (no relations stored), but great for importing that spreadsheet the PM swore was “final-final.xlsx”.
Konro’s schema is both the runtime validator and the TypeScript source-of-truth.
No code-gen step, no stale .d.ts
files. Change a column? The rest of your program lights up like a Christmas tree.
// ✅ autocomplete & typo-catching
db.insert('user', { emaiil: 'oops' }); // red squiggly
// ✅ relations are typed
const post = db.query(state).from('post').with({ author: true }).first();
post.author.name // string | null, not `any`
// ✅ aggregations too
const stats = db.query(state).from('post').aggregate({
total: konro.count(),
words: konro.sum('bodyLength'),
});
// { total: number; words: number | null }
Every write produces an immutable snapshot. Time-travel, undo/redo, or just structuredClone
for free.
const [state1, bob] = db.insert(empty, 'user', { name: 'Bob' });
const [state2, alice] = db.insert(state1, 'user', { name: 'Alice' });
// state1 still has only Bob – no spooky action at a distance
On-demand mode hides the bookkeeping and hits disk only for the rows you touch.
zod
Duplication)konro.string({ format: 'email', unique: true, max: 120 });
konro.number({ min: 0, max: 255 });
Violations throw KonroValidationError
with codes you can catch and map to UI messages.
Soft-delete? Add deletedAt: konro.deletedAt()
– Konro auto-filters unless you .withDeleted()
.
// one-to-many
konro.many('comment', { on: 'id', references: 'postId' })
// many-to-one
konro.one('user', { on: 'authorId', references: 'id' })
// cascade behaviours
konro.one('user', { on: 'authorId', references: 'id', onDelete: 'CASCADE' })
Query:
db.query()
.from('user')
.with({
posts: {
where: p => p.published,
with: { comments: true }, // nested
},
})
.all();
Array.reduce
Gets Old)db.query()
.from('invoice')
.where(i => !i.paid)
.aggregate({
count: konro.count(),
total: konro.sum('amount'),
avg: konro.avg('amount'),
min: konro.min('amount'),
max: konro.max('amount'),
});
// { count: 42, total: 1234.56, avg: 29.39, min: 0.99, max: 99.00 }
writeAtomic
) – power-loss safe: temp file → rename()
.FsProvider
– swap in memfs
for tests, or an encrypted volume for paranoia.# scaffold a typed repo
bunx konro-cli init my-cli-db
cd my-cli-db
bun db:seed
git add db.json && git commit -m "initial schema"
Dataset | Strategy | Cold Start | Warm Query | Memory |
---|---|---|---|---|
1 k rows | single | 3 ms | 0.1 ms | 1 MB |
50 k rows | multi | 5 ms | 0.3 ms | 10 MB |
1 M rows | perRecord | 8 ms | 0.5 ms | 30 MB |
All numbers on M2 Air, Bun, SSD. YMMV, but it’s local – network latency is 0 µs.
import { konro } from 'konro';
import { createFsFromVolume, Volume } from 'memfs';
const vol = new Volume();
const fs = createFsFromVolume(vol);
const db = konro.createDatabase({
schema,
adapter: konro.createFileAdapter({
format: 'json',
single: { filepath: '/test.json' },
fs, // inject fake fs
}),
});
// run your test suite, zero I/O to real disk
bun install
bun test
– should be greenWe enforce no-any
, no-unused
, and no-unchecked-indexed-access
.
If you can make the types even stricter without breaking ergonomics, you win eternal bragging rights.
MIT – do what you want, just don’t blame us when you accidentally commit the production DB to GitHub (it’s happened).
fs.readFile
”Feature | lowdb (v3+) | Konro | Prisma / Drizzle (Full-scale ORMs) |
---|---|---|---|
Paradigm | Simple Document Store | Functional, Relational ORM | Client-Server ORMs |
Schema | Schema-less, manual types | Type-First, inferred static types | Schema-first (via .prisma file or code) |
API Style | Mutable (db.data.push(...) ) | Immutable & Fluent (db.query(state)... ) or Async (await db.query()... ) | Stateful Client (prisma.user.create(...) ) |
State Mgmt | Direct mutation | Explicit state passing or Async I/O | Managed by the client instance |
Storage | JSON/YAML files | JSON, YAML, CSV, XLSX (pluggable) | External databases (PostgreSQL, MySQL, etc.) |
Best For | Quick scripts, simple configs | Local-first apps, CLIs, small servers needing safety and structure. | Production web applications with traditional client-server database architecture. |
Category | Method / Function | Purpose | Notes |
---|---|---|---|
Schema | konro.createSchema(def) | Defines the entire database structure. | |
konro.id/string/number/etc | Defines column types and validation rules. | ||
konro.createdAt/updatedAt/deletedAt | Defines managed timestamp columns. | Enables automatic timestamps & soft deletes. | |
konro.one/many(table, opts) | Defines relationships. | onDelete option enables cascades. | |
DB Context | konro.createDatabase(opts) | Creates the main db context object. | API changes based on adapter's mode . |
konro.createFileAdapter(opts) | Creates a file storage adapter. | format , mode , single /multi /perRecord | |
I/O | db.read() | Reads state from disk. | in-memory mode only. |
db.write(state) | Writes state to disk. | in-memory mode only. | |
db.createEmptyState() | Creates a fresh, empty DatabaseState object. | Useful for testing. | |
Data Ops | db.query(state?) | Starts a fluent read-query chain. | Terminals are async in on-demand . |
...withDeleted() | Includes soft-deleted records in a query. | Only applies if table has deletedAt . | |
db.insert(state?, ...) | Inserts records. Returns [newState, result] or Promise<result> . | Manages createdAt /updatedAt . | |
db.update(state?, ...) | Starts a fluent update chain. | Manages updatedAt . | |
db.delete(state?, ...) | Starts a fluent delete chain. | Performs soft delete if deletedAt exists. |
FAQs
A type-safe, functional-inspired ORM for local JSON/YAML file-based data sources.
The npm package konro receives a total of 13 weekly downloads. As such, konro popularity was classified as not popular.
We found that konro 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
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last week’s supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.