stardance has been extended another month! the new deadline is october 31 :)

You are browsing as a guest. Sign up (or log in) to start making projects!

inkan

  • 6 Devlogs
  • 8 Total hours

Inkan is a Node.js API framework that generates OpenAPI docs, TypeScript types, validation, and tests from a single schema per route. It enforces that your API docs and code always match through automated contract validation.

Open comments for this post

1h 25m 16s logged

Hello again my little Stardancers ✨inkan 0.6.0 is out, and this one was a big one. The plan was simple to say and hard to do: make inkan faster than Fastify on plain node:http, without generating code at runtime the way Fastify does with new Function. I wrote a plan with phases, measured main before touching anything, and then went through it step by step, keeping only what the numbers carried.First the fixed costs. Every request used to make about twenty little objects where six would do, and the request id came from a random UUID. Now the id comes from a counter, everything a route can work out ahead of time is worked out once at start, and a request with a body is only routed once. That alone saved about four percent of CPU per request. Then something odd happened: over HTTP, under full load, it was ten percent slower, even though it spent less CPU. I spent a good while hunting that down, measuring one change at a time against the last one, and it turned out to be fields I had made lazy. Filled on first use, they cost more under load than they saved. Made at once again, and the ten percent were back.Then the schemas. Every schema now checks through one function made once from its rules, which I call its stamp, instead of walking the schema tree on every request. To make sure nothing changed, a test builds every schema twice, once the old way and once the new, and compares two thousand random schemas and values. Same values, same messages, same paths.Writing answers was the lesson of the week. My first idea was a writer in plain JavaScript that writes only what the contract lists in one pass. It was clean, and it was almost twice as slow as the native JSON.stringify. So it went. What stayed: a plain object that holds exactly what the contract lists goes straight to the native writer, and anything else is copied with only the declared fields first. While pinning the old writer down with tests I also found five places where it wrote something it should not have, and two of them could let a key the contract never listed slip out. All five are fixed.And the honest result: on the bench inkan 0.6.0 scores 89.1 against Fastify’s 88.6, with node:http as 100. That is level, not ahead, because the runs overlap, so I am not calling it faster. It is 5.5 percent faster than 0.5, and with inkan seal a body of 50 objects is checked faster than by any server on the bench. Every number, phase by phase, is in the repository, including the ideas that did not work.There is more than speed in this one. The context can answer with text, html, a redirect or a 404 now, and the html tag escapes everything you put into it, so a name someone typed can never become a script on your page. Layouts work per scope, cookies are safe by default, and a handler can hand back rows straight from a database cursor: they go out as they are read, each one trimmed to the contract, as JSON or as one line per row. ctx.csv writes a million rows without holding them in memory, ctx.signal stops a query when the client leaves or the time is up, and a route can cache its answers and ask the database once when ten people ask at the same time.The website got a new logo too, 印 between braces, and the docs now have a real API section with every method and every option in one place.Next up is winning the scenarios where Fastify is still ahead: small requests, the router and middleware. I have a few ideas.See you next time ✨

0
0
9
Open comments for this post

1h 8m 19s logged

Hello again my little Stardancers ✨ It’s devlog time, and this one comes with a confession: I moved a real app onto inkan.

Not a todo list. A real one with 55 routes, file uploads, backups of a couple hundred MB, sessions and a mail setup. It ran on Express, and I wanted to know what happens when inkan has to do real work. Turns out: mostly fine. But not completely. And that “not completely” turned into inkan 0.5.0

The first problem was request bodies. inkan read every body into memory, with one 1 MB limit for the whole app. Fine for JSON, less fine for “hey, can I upload this 2 GB backup?” No ❤️ So I paused the migration and fixed the framework first.

0.5.0 brings t.binary() for files sent as the request body, and t.stream() for real streaming uploads: your handler gets the upload chunk by chunk, so the file never sits in memory. Limits are per route, so one endpoint can take 2 GB while the rest stays at 1 MB. On the way I found a fun bug: when a stream hit its limit, or the server answered 401 before the upload was done, the connection could just… hang. Fixed, the response arrives and the rest gets drained properly

Then the frontend. Now there’s serveStatic(): hashed assets cached for a year, index.html never stuck in a cache, and unknown routes fall back to the SPA. Except /api, where a typo gets a real 404 instead of your entire frontend 💅 compress() does Brotli and gzip, streams included. In the app I migrated, the bundle went from 75 KB to 18 KB.

There’s also ctx.ip for the login rate limiter (Bun and Deno too), per-route body limits and app.bodyFor() for adapter authors. And the benchmarks say no potato: every scenario stayed within ±4% of main on the same GitHub runner.

And then something else happened: inkan got integrations 🧩 All in one repo at github.com/inkanjs/integrations.

@inkanjs/vite runs your API inside the Vite dev server, so frontend and API share one port. No proxy, no second terminal, just npm run dev. The API reloads on every save, each reload counts as a fresh restart so your timers don’t multiply, the docs and inspector links show up in Vite’s banner, and a broken API shows up in Vite’s error overlay.

@inkanjs/next turns an inkan app into Next.js route handlers with one line, works with the Pages Router too, and has direct(app): a typed client for Server Components that calls your API in the same process. CI builds and starts a real Next.js app, because “works on my machine” isn’t a testing strategy.

@inkanjs/query is for TanStack Query: keys and types straight from the API paths, failed responses as errors with the problem document, and a retry() that won’t retry a 404 until the heat death of the universe.

@inkanjs/uws runs inkan on uWebSockets.js, with graceful shutdown and HTTPS, and it’s the fastest way to run inkan. Nuxt, SvelteKit, Astro and Remix don’t even need a package: app.fetch is enough, and the repo has recipes.

And the migration? All 55 routes run on inkan now, split into files by area instead of one 1300-line index.js. Every test passes, the frontend didn’t change a single line, and dev went from two processes, two ports and a proxy to npm run dev on one port. Express, compression and concurrently are gone, 74 packages fewer

A real project is great at showing you where your framework doesn’t hold up. inkan had a few of those places. Now it has fewer.

npm install @vxnsin/inkan@0.5.0

See you next time, Stardancers 🌙

0
0
29
Open comments for this post

2h 9m 14s logged

Hello again my little Stardancers ✨

inkan 0.4.0 is out, and I closed the entire milestone in one day. Every single issue. I don’t know who I am anymore either.

The one I’m proudest of: npx @vxnsin/inkan learn. It’s a tutorial that lives in your terminal. It sets up a tiny tea shop, gives you twelve quests, and checks your work every time you hit save. Forgot a validation rule? It tells you. Stuck? Press h for a hint, press it again for a less subtle hint. By quest 12 you’ve built routes, contracts, auth, hooks, plugins, and you’ve broken a client on purpose (for science). No other web framework ships a tutorial inside itself, so I figured: why not be the first one.

inkan also got grown-up stuff this time. Hooks, plugins and decorators, so you can bolt on your own things without touching the core, and a little rate limiter built on exactly those APIs to prove it works. Routes can now live in a folder tree, routes/teas/[id].ts and friends. And inkan finally leaves the house: app.fetch runs it on Bun, Deno and serverless, workers: “auto” uses every CPU core you own, and there’s an adapter for uWebSockets.js if you want to go absolutely feral.

Then there’s inkan seal. It stamps your contracts into plain code ahead of time, so big requests get checked in about half the time. No eval, no runtime magic, just a file you can actually read. And if your contract changes and you forget to reseal, inkan notices and quietly ignores the stale seal. It’s basically a very responsible goldfish.

Speed check, because I promised honest numbers: on a fair benchmark inkan beats Hono, by 0.4 points. I’m choosing to celebrate that like it’s 40. Fastify is still a bit ahead, Express is still Express. But put inkan on the uWS adapter and it’s a third faster than plain Node itself. Who’s the framework now.

Also: inkan moved into its own home at github.com/inkanjs, and routes can now say who’s allowed in (security: “bearer”) and actually mean it.

0
0
12
Open comments for this post

2h 25m 54s logged

Hello again my little Stardancers ✨

inkan 0.3.0 is out, and it has learned to read the room. Specifically: it now notices when you’re about to break things for everyone who depends on you. Which is more than I can say for some group projects.

The big one is inkan diff. You give it the OpenAPI document from your last release and your app as it is now, and it tells you exactly which changes would make your clients cry. A field that suddenly became required? Breaking. A route you “cleaned up”? Very breaking. A new optional field? Totally fine, go off. Put it in CI and your pipeline turns red before your users do.

Also new: npx @vxnsin/inkan examples drops a whole explained project into your folder. Six of them, from “hello” to “deploy”, each with a README that tells you what to read first and a list of ways to break it on purpose, because honestly that’s how we all learn anyway. There’s a typed client now too: your frontend gets its types straight from the server routes, no codegen, no ritual sacrifices. Typo in a path? It doesn’t compile. Beautiful.

And the rest of the goodie bag: server-sent events with a schema per event (even endless streams can be tests now, don’t ask how, it’s magic and also a counter), file uploads with size and type limits, examples that build on each other (“create a tea, then fetch it”), request ids in every log line and every error, a replay button in the inspector that turns real traffic into examples, and you can now edit requests right on the docs page. Huge thanks to AndrewCMD for dates, refinements and recursive schemas, inkan’s brain got noticeably bigger.

0
0
28
Open comments for this post

18m 53s logged

Hello again my little Stardancers ✨

inkan 0.2.0 is out, and it has trust issues now, just like my ex. The difference is that inkan’s trust issues are actually helpful.

The big one: inkan check now tells you what you forgot to test. If your route promises a 409 but none of your examples ever triggers it, inkan points at it and says “that one, nobody checked that one.” Add –strict and your CI refuses to go green until you write that example. Your docs page shows the same hint, so the lie gets caught twice.

Browsers can finally talk to inkan from another origin too. There’s a little cors() middleware, and OPTIONS requests get answered automatically instead of a sad 405. The terminal got its colours, RinZ27’s lifecycle hooks made it in, and the CLI now has real tests of its own. Releasing is one click now as well: a GitHub release publishes to npm with a signed link back to the exact commit, so you can check that what you install is what’s on GitHub.

0
0
34
Open comments for this post

24m 14s logged

Hello my little Stardancers ✨

Devlog time! No ship yet, but here’s what’s been cooking.

inkan (印鑑) is an API server for Node where the docs can’t lie. Every route gets one contract, and from that inkan validates requests, types your handler, writes OpenAPI and serves docs.

The fun part: every example in the docs also runs as a test, so if your code drifts away from what the docs promise, inkan check goes red before anyone reads a lie. Zero dependencies, so your node_modules can finally rest.

This week I merged my first community PR 🎉 It adds lifecycle hooks for connecting your database on startup and closing it cleanly on Ctrl+C. Before merging I caught two sneaky bugs: a failing startup hook took the whole server down, and a stuck shutdown hook could keep the process alive forever, like a guest who won’t leave the party. Both are fixed and tested.

Next up is better logging, and then the ship is coming soon™ 🫡

0
0
14

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…