GM builders ☀️
$BJBN core just shipped v0.6.21 while you were sleeping 🛠️
✅ Prototype-pollution guard — nested query parsing locked down tight
✅ queue:work now dies instantly on ctrl+C, no more hanging bags
✅ RequestMiddleware now unwraps bracket-notation keys (filters[status]=active) into real nested objects/arrays, resolvable via dot or bracket notation on every request.* accessor — GET routes finally get proper structured query parsing
✅ CLI won't crash from one broken module anymore
We don't stop building 🚧
Full notes 👇
https://t.co/mVtdPdsgYi
🚀 New benchmark thread is live!
We stress-tested Bejibun v0.6.1 vs v0.6.17 under identical load and the results speak for themselves:
• RPS: 1,603.99 → 3,458.78 (2.16x)
• avg latency: 31.19ms → 14.46ms
• p99: 77.37ms → 20.01ms
• v0.6.1 was silently failing 97% of requests under load (deadline_exceeded) — v0.6.17: zero errors
Full thread with raw output + the exact endpoint code we tested: https://t.co/qB2t6BHnC4
v0.6.1 was silently dropping >97% of requests under this exact workload — deadline_exceeded, not clean errors. v0.6.17 clears it entirely while more than doubling throughput.
If you're running Bejibun in production, this upgrade isn't optional. $BJBN
Here's the exact endpoint under test — not a hello-world stub. Mixed I/O: Redis get/set, a named custom connection, a pipelined batch, Cache (remember/has/add/put/forget), and structured logging, all in one request path.
1/
🚀 @bejibun/logger v0.2.0 is out — focused entirely on speed.
Threw out Luxon, killed per-call builder chains, cached what didn't need recomputing.
Numbers below 👇
5/
⚠️ Breaking: Chalk/ChalkBuilder facade removed — colorizing now happens internally via cached colorizers.
🩹 Fixed: separator() no longer throws when stdout.columns is undefined (piped output) — falls back to 80 cols.
bun add @bejibun/logger
Update: @bejibun/core v0.6.1
🩹 Fixes
- Fixed a race condition in `queue:work` and `queue:retry` where multiple concurrent workers could pick up and process the same job simultaneously
📖 Changes
Response Cookies
`ResponseBuilder` and the `Response` facade can now set and delete cookies on outgoing responses, on top of Bun's native `CookieMap`.
Cookies are automatically applied as `Set-Cookie` headers on both `.send()` and `.stream()`.
- Added `Response.setCookie(key, value, options?)` / `ResponseBuilder.setCookie()` -- set a single cookie
- Added `Response.setCookies(cookies, options?)` / `ResponseBuilder.setCookies()` -- set multiple cookies in one call, each with its own optional `Bun.CookieInit`
- Added `Response.deleteCookie(key, options?)` / `ResponseBuilder.deleteCookie()` -- expire a single cookie (`domain` / `path` only)
- Added `Response.deleteCookies(cookies, options?)` / `ResponseBuilder.deleteCookies()` -- expire multiple cookies in one call, each with its own optional `domain` / `path`
- `ResponseBuilder` now holds an internal `Bun.CookieMap`; `.send()` and `.stream()` merge `Set-Cookie` headers in via a new `applyCookies()` helper alongside existing CORS headers
Example:
return Response
.setData(user)
.setCookie("sessionId", sessionId, {httpOnly: true, sameSite: "strict", path: "/"})
.send();
return Response
.setMessage("Signed out")
.deleteCookie("sessionId")
.send();
return Response
.setCookies([
{key: "sessionId", value: sessionId, options: {httpOnly: true}},
{key: "theme", value: "dark", options: {maxAge: 60 * 60 * 24 * 30}}
])
.send();
Queue System
Added a configurable `queue` config file, plus a dedicated `QueueException` for queue-related failures.
`queue:work` now reads its retry/poll interval from config instead of a hardcoded value, and jobs are now reserved before processing
so concurrent workers don't step on each other.
- Added `config/queue.ts` -- defines the default connection and per-connection `driver` / `table` / `retry_after`, loaded from the app's own `config/queue.ts` when present, falling back to the package default
- Added `QueueDriverEnum` (`src/enums`), currently exposing `Database`
- Added `QueueException`, registered in `ExceptionHandler` alongside the other framework exceptions
- `QueueWorkCommand` now sleeps for `connections[default].retry_after` seconds (default `60`) both when polling finds no job and after a failed job attempt, instead of the previous hardcoded `1000`ms poll delay
- `QueueWorkCommand` and `QueueRetryCommand` now use `JobModel`'s `reserved_at` column to atomically claim a job (via a conditional `update()`) before processing it, closing a race where multiple workers could pick up the same job
- `QueueWorkCommand` treats a reservation older than `retry_after` seconds as stale and eligible for reclaim, so a job doesn't stay locked forever if the worker holding it crashes mid-processing
- A job's reservation is cleared (`reserved_at: null`) if its handler throws, so it becomes claimable again on the next pass instead of staying locked until attempts increment
https://t.co/EDR2sWNVe6
Update: @bejibun/core v0.6.1
🩹 Fixes
- Fixed a race condition in `queue:work` and `queue:retry` where multiple concurrent workers could pick up and process the same job simultaneously
📖 Changes
Response Cookies
`ResponseBuilder` and the `Response` facade can now set and delete cookies on outgoing responses, on top of Bun's native `CookieMap`.
Cookies are automatically applied as `Set-Cookie` headers on both `.send()` and `.stream()`.
- Added `Response.setCookie(key, value, options?)` / `ResponseBuilder.setCookie()` -- set a single cookie
- Added `Response.setCookies(cookies, options?)` / `ResponseBuilder.setCookies()` -- set multiple cookies in one call, each with its own optional `Bun.CookieInit`
- Added `Response.deleteCookie(key, options?)` / `ResponseBuilder.deleteCookie()` -- expire a single cookie (`domain` / `path` only)
- Added `Response.deleteCookies(cookies, options?)` / `ResponseBuilder.deleteCookies()` -- expire multiple cookies in one call, each with its own optional `domain` / `path`
- `ResponseBuilder` now holds an internal `Bun.CookieMap`; `.send()` and `.stream()` merge `Set-Cookie` headers in via a new `applyCookies()` helper alongside existing CORS headers
Example:
return Response
.setData(user)
.setCookie("sessionId", sessionId, {httpOnly: true, sameSite: "strict", path: "/"})
.send();
return Response
.setMessage("Signed out")
.deleteCookie("sessionId")
.send();
return Response
.setCookies([
{key: "sessionId", value: sessionId, options: {httpOnly: true}},
{key: "theme", value: "dark", options: {maxAge: 60 * 60 * 24 * 30}}
])
.send();
Queue System
Added a configurable `queue` config file, plus a dedicated `QueueException` for queue-related failures.
`queue:work` now reads its retry/poll interval from config instead of a hardcoded value, and jobs are now reserved before processing
so concurrent workers don't step on each other.
- Added `config/queue.ts` -- defines the default connection and per-connection `driver` / `table` / `retry_after`, loaded from the app's own `config/queue.ts` when present, falling back to the package default
- Added `QueueDriverEnum` (`src/enums`), currently exposing `Database`
- Added `QueueException`, registered in `ExceptionHandler` alongside the other framework exceptions
- `QueueWorkCommand` now sleeps for `connections[default].retry_after` seconds (default `60`) both when polling finds no job and after a failed job attempt, instead of the previous hardcoded `1000`ms poll delay
- `QueueWorkCommand` and `QueueRetryCommand` now use `JobModel`'s `reserved_at` column to atomically claim a job (via a conditional `update()`) before processing it, closing a race where multiple workers could pick up the same job
- `QueueWorkCommand` treats a reservation older than `retry_after` seconds as stale and eligible for reclaim, so a job doesn't stay locked forever if the worker holding it crashes mid-processing
- A job's reservation is cleared (`reserved_at: null`) if its handler throws, so it becomes claimable again on the next pass instead of staying locked until attempts increment
https://t.co/EDR2sWNVe6
Update: @bejibun/core v0.6.0 ⚠️ breaking changes
📖 Changes
Storage moved to @bejibun/storage
Storage facade, disk builders, and disk config are out of core and now live in the standalone @bejibun/storage package.
- Removed Storage, StorageBuilder, StorageLocalBuilder/StorageS3Builder, DiskException, DiskDriverEnum, config/disk.ts
- Import Storage from @bejibun/storage going forward
- Move config/disk.ts → config/storage.ts
RateLimiter moved to @bejibun/limiter
RateLimiter facade, RateLimiterBuilder, and RateLimiterException are out of core and now live in the standalone @bejibun/limiter package.
- Import RateLimiter from @bejibun/limiter going forward
- RateLimiterMiddleware stays in core, works as-is — just points to @bejibun/limiter internally
- config/limiter.ts shape (limit/duration) unchanged
Newly exported
- EpochTimestamps model
- RuntimeException
📦 Dependencies
- Added @bejibun/storage ^0.1.0
- Added @bejibun/limiter ^0.1.1
Changelog: 👇
https://t.co/afLu9VLwqL
Update: @bejibun/core v0.6.0 ⚠️ breaking changes
📖 Changes
Storage moved to @bejibun/storage
Storage facade, disk builders, and disk config are out of core and now live in the standalone @bejibun/storage package.
- Removed Storage, StorageBuilder, StorageLocalBuilder/StorageS3Builder, DiskException, DiskDriverEnum, config/disk.ts
- Import Storage from @bejibun/storage going forward
- Move config/disk.ts → config/storage.ts
RateLimiter moved to @bejibun/limiter
RateLimiter facade, RateLimiterBuilder, and RateLimiterException are out of core and now live in the standalone @bejibun/limiter package.
- Import RateLimiter from @bejibun/limiter going forward
- RateLimiterMiddleware stays in core, works as-is — just points to @bejibun/limiter internally
- config/limiter.ts shape (limit/duration) unchanged
Newly exported
- EpochTimestamps model
- RuntimeException
📦 Dependencies
- Added @bejibun/storage ^0.1.0
- Added @bejibun/limiter ^0.1.1
Changelog: 👇
https://t.co/afLu9VLwqL
Introducing: @bejibun/limiter 🚦
A rate limiter for the Bejibun Framework, backed by @bejibun/cache.
📘 Overview
Throttle repeated actions — login attempts, API calls, anything you need to cap — with a simple key-based counter.
🧩 Standalone Ready
You don't need the full Bejibun ecosystem to use it — @bejibun/limiter works as a standalone package in any project.
⚙️ Features
Simple, fluent API — .attempt(), .tooManyAttempts(), .clear()
Configurable limit & duration per key
Built on @bejibun/cache for the counter store
Throws RateLimiterException (429) when the limit is hit
📦 Installation
bun add @bejibun/limiter
Docs & source: 👇
https://t.co/6a6ZMrezsr
Introducing: @bejibun/limiter 🚦
A rate limiter for the Bejibun Framework, backed by @bejibun/cache.
📘 Overview
Throttle repeated actions — login attempts, API calls, anything you need to cap — with a simple key-based counter.
🧩 Standalone Ready
You don't need the full Bejibun ecosystem to use it — @bejibun/limiter works as a standalone package in any project.
⚙️ Features
Simple, fluent API — .attempt(), .tooManyAttempts(), .clear()
Configurable limit & duration per key
Built on @bejibun/cache for the counter store
Throws RateLimiterException (429) when the limit is hit
📦 Installation
bun add @bejibun/limiter
Docs & source: 👇
https://t.co/6a6ZMrezsr
Update : @bejibun/core v0.5.0
📖 Changes
X402 Middleware Refactor -- `@bejibun/x402` v0.2.0
Bumped `@bejibun/x402` from `^0.1.1` to `^0.2.1` and updated the `.x402()` route middleware to match its new multi-network payment API.
What changed under the hood (@bejibun/x402 v0.2.0):
- Multi-network support (EVM + SVM) -- routes can now accept payment from both EVM chains (Base, etc.) and Solana simultaneously, matching @x402/express behavior, instead of the old single-network setup
- Payment resolution follows a 4-level priority cascade: explicit `accepts` array -> route-level `network` + `payTo` shorthand -> config-wide `networks` block -> built-in defaults (Base, Polygon, Arbitrum, World Chain for EVM; Solana mainnet for SVM)
- New `BunAdapter` implements @x402/core's `HTTPAdapter` directly against `Bun.BunRequest`
- Payment verification/settlement now delegates to @x402/core's `x402HTTPResourceServer` instead of the old hand-rolled verify/settle/decode chain, and initializes each route's server only once via a static cache
- Underlying dependency swapped from `x402` to @coinbase/x402, @x402/core, @x402/evm, and @x402/svm
How this surfaces in @bejibun/core:
- `Router.x402()` / `RouterBuilder.x402()` -- signature changed from `x402(config?, facilitatorConfig?, paywallConfig?)` to `x402(facilitator?: TFacilitator, routePayment?: TRoutePayment)`
- `TRoutePayment` replaces `TX402Config` and supports the new `accepts` array for full multi-network control (per-network `scheme`, `price`, `network`, `payTo`, `description`, `mimeType`)
- `TFacilitator` is now a plain `{ url?, createAuthHeaders? }` object; defaults to the Coinbase facilitator
- **`X402Middleware`** -- constructor and internal `X402` calls updated to use `.setFacilitator()` and `.setRoutePayment()`, replacing the removed `.setConfig()` and `.setPaywall()`
- Types now imported from `@bejibun/x402/types` instead of `@bejibun/x402`
⚠️ Breaking change: existing calls to `Router.x402(config, facilitatorConfig, paywallConfig)` must be updated to `Router.x402(facilitator, routePayment)`.
Example:
Router.x402(
{
url: "https://t.co/qstW29HD0b"
},
{
accepts: [
{
network: "eip155:8453",
price: "$1.00",
payTo: "0x..."
}
]
}
);
CLI
- Documented new `route:list` and `schedule:work` ace commands in the README
- `db:seed` help output now shows `[options]`
Misc
- Simplified the "Support / Donate" section in the README (replaced crypto address table with a donate badge/link) and removed the Contributors section
📦 Dependencies
- Bumped `@bejibun/cache` from `^0.1.23` to `^0.1.24`
- Bumped `@bejibun/x402` (devDependency) from `^0.1.1` to `^0.2.1`
- Bumped `commander` from `^14.0.3` to `^15.0.0`
- Bumped `cron-parser` from `^5.5.0` to `^5.7.0`
- Bumped `@types/luxon` from `^3.7.1` to `^3.7.3`
- Bumped `tsc-alias` (devDependency) from `^1.8.17` to `^1.9.1`
https://t.co/YkhvebYrrs
Update : @bejibun/core v0.5.0
📖 Changes
X402 Middleware Refactor -- `@bejibun/x402` v0.2.0
Bumped `@bejibun/x402` from `^0.1.1` to `^0.2.1` and updated the `.x402()` route middleware to match its new multi-network payment API.
What changed under the hood (@bejibun/x402 v0.2.0):
- Multi-network support (EVM + SVM) -- routes can now accept payment from both EVM chains (Base, etc.) and Solana simultaneously, matching @x402/express behavior, instead of the old single-network setup
- Payment resolution follows a 4-level priority cascade: explicit `accepts` array -> route-level `network` + `payTo` shorthand -> config-wide `networks` block -> built-in defaults (Base, Polygon, Arbitrum, World Chain for EVM; Solana mainnet for SVM)
- New `BunAdapter` implements @x402/core's `HTTPAdapter` directly against `Bun.BunRequest`
- Payment verification/settlement now delegates to @x402/core's `x402HTTPResourceServer` instead of the old hand-rolled verify/settle/decode chain, and initializes each route's server only once via a static cache
- Underlying dependency swapped from `x402` to @coinbase/x402, @x402/core, @x402/evm, and @x402/svm
How this surfaces in @bejibun/core:
- `Router.x402()` / `RouterBuilder.x402()` -- signature changed from `x402(config?, facilitatorConfig?, paywallConfig?)` to `x402(facilitator?: TFacilitator, routePayment?: TRoutePayment)`
- `TRoutePayment` replaces `TX402Config` and supports the new `accepts` array for full multi-network control (per-network `scheme`, `price`, `network`, `payTo`, `description`, `mimeType`)
- `TFacilitator` is now a plain `{ url?, createAuthHeaders? }` object; defaults to the Coinbase facilitator
- **`X402Middleware`** -- constructor and internal `X402` calls updated to use `.setFacilitator()` and `.setRoutePayment()`, replacing the removed `.setConfig()` and `.setPaywall()`
- Types now imported from `@bejibun/x402/types` instead of `@bejibun/x402`
⚠️ Breaking change: existing calls to `Router.x402(config, facilitatorConfig, paywallConfig)` must be updated to `Router.x402(facilitator, routePayment)`.
Example:
Router.x402(
{
url: "https://t.co/qstW29HD0b"
},
{
accepts: [
{
network: "eip155:8453",
price: "$1.00",
payTo: "0x..."
}
]
}
);
CLI
- Documented new `route:list` and `schedule:work` ace commands in the README
- `db:seed` help output now shows `[options]`
Misc
- Simplified the "Support / Donate" section in the README (replaced crypto address table with a donate badge/link) and removed the Contributors section
📦 Dependencies
- Bumped `@bejibun/cache` from `^0.1.23` to `^0.1.24`
- Bumped `@bejibun/x402` (devDependency) from `^0.1.1` to `^0.2.1`
- Bumped `commander` from `^14.0.3` to `^15.0.0`
- Bumped `cron-parser` from `^5.5.0` to `^5.7.0`
- Bumped `@types/luxon` from `^3.7.1` to `^3.7.3`
- Bumped `tsc-alias` (devDependency) from `^1.8.17` to `^1.9.1`
https://t.co/YkhvebYrrs