Changelog
Every tekir package release in chronological order. Each package also keeps its own changelog on its detail page.
@tekir/corev0.1.39
CoreSeptember 16, 2026
- Routing now applies domain constraints and precedence consistently on native Bun and Node servers, while compiled handlers preserve request, cookie, response, and error semantics.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/runtimev0.1.8
CoreSeptember 16, 2026
- Runtime adapters now provide portable Node fallbacks for server, filesystem, password, process, garbage-collection, and SQLite operations.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/commandsv0.1.4
UtilitiesSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/configv0.1.5
UtilitiesSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/envv0.1.4
UtilitiesSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/i18nv0.1.4
UtilitiesSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/loggerv0.1.5
UtilitiesSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/logger-datadogv0.1.4
UtilitiesSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/logger-lokiv0.1.4
UtilitiesSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/logger-pinov0.1.3
UtilitiesSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/viewv0.1.3
UtilitiesSeptember 16, 2026
- Rendered responses no longer attach a body to status codes that forbid one.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/dbv0.1.8
DatabaseSeptember 16, 2026
- Transactions no longer replay or erase concurrent writes during rollback, migrations apply atomically, and SQLite snapshots preserve schema objects and integer values safely.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/mongodbv0.1.5
DatabaseSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/redisv0.1.4
DatabaseSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/cachev0.1.10
DatabaseSeptember 16, 2026
- HTTP caching now preserves binary bodies and response status, isolates host and credential variants, and refuses private, no-store, error, empty, and cookie-setting responses.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/sessionv0.1.7
DatabaseSeptember 16, 2026
- Session middleware and database storage now honor real Tekir response contexts and expiry semantics consistently.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/authv0.1.10
SecuritySeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/authorizev0.1.4
SecuritySeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/hashv0.1.4
SecuritySeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/encryptionv0.1.5
SecuritySeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/corsv0.1.7
SecuritySeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/shieldv0.1.5
SecuritySeptember 16, 2026
- Shield and CSRF middleware now operate against real Tekir request/response contexts without producing integration-time 500 responses.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/limiterv0.1.4
SecuritySeptember 16, 2026
- Database-backed limits expire correctly and request identity no longer collapses unrelated client IPs into one quota.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/validatorv0.1.5
SecuritySeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/socialv0.1.5
SecuritySeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/mailv0.1.4
CommunicationSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/queuev0.1.5
CommunicationSeptember 16, 2026
- Worker shutdown is idempotent under concurrent calls, and database/Redis backends retain consistent job state through claims, retries, and cleanup.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/notificationv0.1.5
CommunicationSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/emitterv0.1.8
CommunicationSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/cronv0.1.9
CommunicationSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/drivev0.1.5
Storage & ParsingSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/staticv0.1.4
Storage & ParsingSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/bodyparserv0.1.8
Storage & ParsingSeptember 16, 2026
- Spilled uploads now load through Node-compatible ESM imports instead of a CommonJS-only runtime require.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/decoratorsv0.1.3
DecoratorsSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/http-decoratorsv0.1.5
DecoratorsSeptember 16, 2026
- The cache decorator now loads its optional cache integration through portable ESM resolution.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/db-decoratorsv0.1.3
DecoratorsSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/cron-decoratorsv0.1.3
DecoratorsSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/event-decoratorsv0.1.3
DecoratorsSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
DecoratorsSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
create-tekir-appv0.1.12
Dev ToolsSeptember 16, 2026
- The scaffolder now uses the shared package build pipeline while preserving every starter template in the published output.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/testingv0.1.11
Dev ToolsSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/swaggerv0.1.7
Dev ToolsSeptember 16, 2026
- OpenAPI route collection now includes domain-constrained handlers.
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/healthv0.1.4
Dev ToolsSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/vitev0.1.9
FrontendSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/nextv0.1.7
FrontendSeptember 16, 2026
- Published output now uses the shared Node-targeted ESM bundle pipeline with external dependencies and generated TypeScript declarations, while Bun consumers keep the native source export.
@tekir/corev0.1.38
CoreAugust 22, 2026
- Graceful shutdown now stops accepting new connections and waits for active requests to drain before application hooks and providers close their resources. The public
gracefulflag is mapped to Bun'scloseActiveConnectionsargument correctly, while immediate shutdown still force-closes active connections.
@tekir/runtimev0.1.7
CoreAugust 22, 2026
- The Node.js HTTP fallback now returns an awaitable shutdown promise, stops accepting new connections before cleanup and waits for active requests to finish. Forced shutdown also closes active Node.js connections immediately, matching the Bun server contract.
@tekir/swaggerv0.1.6
Dev ToolsJuly 31, 2026
ApiParamOptions.schemaand fluentapiParam(..., { schema })now preserve complete OpenAPI parameter schemas, including enums, arrays, bounds, unions, and other JSON Schema keywords.- Legacy parameter options continue to emit
type,format,example, andenumcorrectly.
@tekir/corev0.1.37
CoreJuly 23, 2026
- Body-parser middleware now owns multipart consumption without an eager
formData()pass, while request helpers read the parsed middleware result directly.
@tekir/runtimev0.1.6
CoreJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/commandsv0.1.3
UtilitiesJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/configv0.1.4
UtilitiesJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/envv0.1.3
UtilitiesJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/i18nv0.1.3
UtilitiesJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/loggerv0.1.4
UtilitiesJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/logger-datadogv0.1.3
UtilitiesJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/logger-lokiv0.1.3
UtilitiesJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/logger-pinov0.1.2
UtilitiesJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/viewv0.1.2
UtilitiesJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/dbv0.1.7
DatabaseJuly 23, 2026
- Optional PostgreSQL and MySQL drivers are resolved from the package module consistently, including combined and parallel test runs.
@tekir/mongodbv0.1.4
DatabaseJuly 23, 2026
- Mongoose uses the package's resolved module instance consistently, including combined and parallel test runs.
@tekir/redisv0.1.3
DatabaseJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/cachev0.1.9
DatabaseJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/sessionv0.1.6
DatabaseJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/authv0.1.9
SecurityJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/authorizev0.1.3
SecurityJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/hashv0.1.3
SecurityJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/encryptionv0.1.4
SecurityJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/corsv0.1.6
SecurityJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/shieldv0.1.4
SecurityJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/limiterv0.1.3
SecurityJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/validatorv0.1.4
SecurityJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/socialv0.1.4
SecurityJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/mailv0.1.3
CommunicationJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/queuev0.1.4
CommunicationJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/notificationv0.1.4
CommunicationJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/emitterv0.1.7
CommunicationJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/cronv0.1.8
CommunicationJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/drivev0.1.4
Storage & ParsingJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/staticv0.1.3
Storage & ParsingJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/bodyparserv0.1.7
Storage & ParsingJuly 23, 2026
- Multipart parsing now enforces a configurable
maxPartsceiling in both streaming and fallback paths, rejecting excessive field-and-file payloads with413before they can exhaust parser resources.
@tekir/decoratorsv0.1.2
DecoratorsJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/http-decoratorsv0.1.4
DecoratorsJuly 23, 2026
- Cache decorators resolve their optional cache peer from the package module consistently instead of depending on the caller's runtime resolution base.
@tekir/db-decoratorsv0.1.2
DecoratorsJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/cron-decoratorsv0.1.2
DecoratorsJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/event-decoratorsv0.1.2
DecoratorsJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
DecoratorsJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/cliv0.1.7
Dev ToolsJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
create-tekir-appv0.1.11
Dev ToolsJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/testingv0.1.10
Dev ToolsJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/swaggerv0.1.5
Dev ToolsJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by the coordinated Tekir release.
@tekir/healthv0.1.3
Dev ToolsJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/vitev0.1.8
FrontendJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/nextv0.1.6
FrontendJuly 23, 2026
- Package metadata now follows the shared compatible
0.1.xdependency range used by this coordinated Tekir release.
@tekir/corev0.1.35
CoreJuly 16, 2026
- Compiled handlers now create real response state lazily whenever handlers or middleware consume
ctx.response; cookies, headers, status codes, finish callbacks, streams, and wrapped native Responses are no longer silently dropped. - Compiled request contexts expose the complete request API, include a Cookie-header fallback, accept structured JSON MIME types, preserve multipart files, and reject dangerous query/input keys.
- Compiled route and middleware failures now use the configured exception pipeline, while debug and
trustedHostssettings are isolated per server instance. Plain-value routes remain on the lightweight fast path.
@tekir/runtimev0.1.5
CoreJuly 16, 2026
- The Node HTTP adapter streams response bodies instead of buffering them and preserves multiple
Set-Cookieheaders correctly across runtime boundaries.
@tekir/commandsv0.1.2
UtilitiesJuly 16, 2026
- Command discovery is confined against escaping symlinks, prompt retries create clean readline sessions, and command failures no longer leave dead control flow.
@tekir/configv0.1.3
UtilitiesJuly 16, 2026
- Deep configuration redaction now handles cycles, arrays, inherited properties, and falsy namespace values without leaking the original object.
@tekir/envv0.1.2
UtilitiesJuly 16, 2026
- Environment schema regression coverage now verifies defaults, coercion, choices, optional values, and invalid-input failures across the public API.
@tekir/i18nv0.1.2
UtilitiesJuly 16, 2026
Accept-Languagenegotiation now honors quality weights, exclusions (q=0), wildcard fallback, and deterministic preference ordering.
@tekir/loggerv0.1.3
UtilitiesJuly 16, 2026
- Structured fields can no longer forge the selected severity, file transport failures are contained without unhandled rejections, and provider shutdown flushes transports reliably.
@tekir/logger-datadogv0.1.2
UtilitiesJuly 16, 2026
- Datadog metadata can no longer override reserved status, service, or message fields in emitted log events.
@tekir/logger-lokiv0.1.2
UtilitiesJuly 16, 2026
- Loki Basic authentication now supports Unicode credentials without failing during header encoding.
@tekir/dbv0.1.5
DatabaseJuly 16, 2026
orWhereconditions now participate in update, delete, increment, and decrement mutations, preventing an OR-only mutation from accidentally affecting every row.- Database CLI, transaction, model, and query-builder error paths now fail explicitly instead of silently continuing with partial state.
@tekir/mongodbv0.1.2
DatabaseJuly 16, 2026
- Write/delete ID paths reject operator objects and invalid identifiers before reaching Mongoose, and fillable assignment ignores inherited properties.
@tekir/redisv0.1.2
DatabaseJuly 16, 2026
- Distributed locks are released only by their owner through an atomic compare-and-delete operation, and connection/manager cleanup paths are more defensive.
@tekir/sessionv0.1.5
DatabaseJuly 16, 2026
- Regenerated session cookies are emitted through every supported response sink, store TTL semantics are consistent, and session/store errors no longer disappear silently.
@tekir/authv0.1.8
SecurityJuly 16, 2026
- Database-token authentication now persists and verifies APP_KEY-keyed HMACs consistently, updates token usage safely, and keeps authentication middleware failures explicit.
@tekir/hashv0.1.2
SecurityJuly 16, 2026
- Scrypt verification now rejects malformed, oversized, and attacker-controlled cost parameters before allocating memory or starting expensive work.
@tekir/encryptionv0.1.3
SecurityJuly 16, 2026
- Legacy ciphertext whose IV starts with the version byte is decoded correctly, and APP_KEY environment fallback no longer assumes a Node-style global
process.
@tekir/shieldv0.1.3
SecurityJuly 16, 2026
- CSRF exception matching now respects path boundaries, preventing a configured path such as
/api/publicfrom excluding attacker-chosen prefix lookalikes.
@tekir/limiterv0.1.2
SecurityJuly 16, 2026
- Redis rate limiting uses an atomic Lua consume operation for increment, TTL, and lockout decisions; memory-store cleanup and observation paths are bounded and consistent.
@tekir/validatorv0.1.3
SecurityJuly 16, 2026
- Validation middleware supports
safeParseandsafeParseAsyncschemas and commits transformed request data only after the full validation succeeds.
@tekir/socialv0.1.3
SecurityJuly 16, 2026
- OAuth state validation rejects future and malformed timestamps, production requires a signing key, and provider token/user parsing is stricter and safer.
@tekir/mailv0.1.2
CommunicationJuly 16, 2026
- Resend and Sevk transports normalize trailing slashes in custom API base URLs, preventing malformed double-slash endpoints.
@tekir/queuev0.1.3
CommunicationJuly 16, 2026
- Redis jobs use atomic claim and lease recovery, worker polling survives backend errors, repeated stop calls settle safely, and memory/database backends retain completed records consistently.
@tekir/notificationv0.1.3
CommunicationJuly 16, 2026
- Notification delivery isolates channel/user failures, applies configured default channels, supports both database adapter shapes, injects mail correctly, and deeply redacts persisted sensitive data.
@tekir/emitterv0.1.6
CommunicationJuly 16, 2026
- Async listener dispatch now awaits Promise-compatible thenables and cleans abort listeners without leaking wait subscriptions.
@tekir/cronv0.1.7
CommunicationJuly 16, 2026
- Cron overlap protection and error tracking now recognize Promise-compatible thenables, not only native Promise instances.
@tekir/drivev0.1.3
Storage & ParsingJuly 16, 2026
- S3 SigV4 now signs query parameters and encoded object keys correctly, remote LIST/DELETE failures are surfaced, same-key moves are safe, and local/memory drivers close symlink and mutable-buffer escapes.
create-tekir-appv0.1.10
Dev ToolsJuly 16, 2026
- Starter templates now use credential-safe CORS defaults, keep frontend dependency versions aligned, and reject unsafe project targets before scaffolding.
@tekir/testingv0.1.9
Dev ToolsJuly 16, 2026
- Test applications await startup and shut down after migration failures, explicit migrations require
@tekir/db, setup errors are surfaced, and authenticated clients retain thehead()method.
@tekir/healthv0.1.2
Dev ToolsJuly 16, 2026
- Memory health checks retain two-decimal precision so small but valid heap/RSS measurements are no longer reported as zero.
@tekir/vitev0.1.7
FrontendJuly 16, 2026
- Build embedding and production asset serving reject symlink escapes outside configured roots, including paths that pass lexical containment checks.
@tekir/nextv0.1.5
FrontendJuly 16, 2026
- The internal Next server and app now close during Tekir shutdown, listener startup errors clean up partial state, and a later request can retry initialization.
@tekir/cronv0.1.6
CommunicationJuly 2, 2026
- Jobs can now run in a fixed IANA timezone:
new Cron({ timezone: 'UTC' }),cron.setTimezone('UTC')before registering, or a per-jobcron.add(name, pattern, cb, { timezone }). Patterns then evaluate in that zone instead of the host's local time, so5 0 1 * *-style boundaries line up with UTC-based date math regardless of the server's timezone. Omitting it keeps the previous local-time behavior. - Found and fixed with Fable.
@tekir/corev0.1.34
CoreJune 13, 2026
- The compiled route fast path no longer rebuilds handlers from their source text at startup. Every route now calls your real handler closure directly, so handlers keep working unchanged after a minifier or transpiler rewrites their source, and a whole class of source-reparse edge cases is gone.
- Request body size is now capped by default (10 MB, from
bodyParser.maxSize) on both the Bun and Node paths. Oversized requests get a413before the handler runs instead of being buffered into memory. - Query strings and request helpers (
input,all,only,except) now reject__proto__,constructor, andprototypekeys and build their output on null-prototype objects, closing a prototype pollution vector. - Response headers carrying
CR/LF(includingVary) are now dropped, closing a response-splitting surface. Invalid percent-encoding in route params and wildcards no longer throws; the raw segment is used instead. response.redirect.back()now validates the referer against an optionaltrustedHostsallowlist (exact host plus*.subdomainwildcards) and otherwise keeps only the same-originpathname + search. A path that registered specific methods now answers unmatched methods with a405 Allowresponse and routesOPTIONSthrough the global middleware chain.generate:keyno longer prints the generatedAPP_KEYto stdout. Signed cookie verification is unified on a single constant-time reader, and gracefulSIGINT/SIGTERMshutdown now runs in every mode.- Found and fixed with Fable.
@tekir/runtimev0.1.4
CoreJune 13, 2026
- The Node server now streams response bodies chunk by chunk (with backpressure and client-disconnect aborts) instead of buffering the whole body into memory first.
serve()gainedmaxRequestBodySize(default 10 MB) andidleTimeout(default 120 s) on both runtimes. On Node, oversize requests are rejected with a413during accumulation, and request/header timeouts are set.fileResponse()accepts an optionalbaseDirand rejects../escapes; MIME types are now detected consistently on both runtimes.openDatabase()skips WAL on read-only opens.readFile/readFileTextnow produce a consistent error carryingcode: 'ENOENT'and thepathon both runtimes. Runtime detection now verifiesprocess.versions.nodeand throws a clear error when neither Bun nor Node is detected.- Found and fixed with Fable.
@tekir/commandsv0.1.1
UtilitiesJune 13, 2026
- Command discovery now resolves the target directory to an absolute base and verifies every file stays under it, so a
..segment or symlink cannot load code from outside the intended folder. Import failures are surfaced withconsole.errorinstead of being swallowed. - Parsed
flagsandargsare built on null-prototype objects and reject__proto__/constructor/prototypedefinition keys, closing a prototype pollution vector. - Negative numbers like
-5and-0.5are now accepted as flag values; real flags are still rejected. An invalidchoiceprompt answer re-prompts with a clear message instead of silently falling back to the first option. - Ctrl+C in a prompt now restores raw mode and exits with code
130, and the secure prompt no longer double-consumes stdin. - Found and fixed with Fable.
@tekir/configv0.1.2
UtilitiesJune 13, 2026
getAll()now redacts sensitive keys by default. Values under keys likepassword,secret,token,apiKey,privateKey,credential, anddsn(case-insensitive, at any depth) come back as[REDACTED]. PassgetAll({ redact: false })to opt back into raw values; the store itself is never mutated.register(name, value, schema?)accepts an optional validator and throws at register time when the value fails it, so a bad config object surfaces immediately instead of later at read time.get()now rejects__proto__,constructor, andprototypepath segments and returns the default value, closing a prototype pollution vector. Config files load throughfile://URLs so drive letters and UNC paths resolve correctly on Windows.loadDirimport failures are now reported with the file name instead of being swallowed.- Found and fixed with Fable.
@tekir/envv0.1.1
UtilitiesJune 13, 2026
defineEnv(schema, options?)now accepts envalid'sCleanOptions, including a customreporter, so you can throw on invalid env instead of having the process exit.- The return type now uses envalid's official
CleanedEnv<T>inference, and the schema type is tied toValidatorSpec, so invalid validator objects are caught at compile time. - Found and fixed with Fable.
@tekir/i18nv0.1.1
UtilitiesJune 13, 2026
- Locale loading and
t()lookups now reject__proto__,constructor, andprototypekeys and build their maps on null-prototype objects, closing a prototype pollution vector. - Locale files are now confirmed to resolve to a file under the locale directory, so a symlink or separator trick cannot pull translations from outside the tree.
t()output is not HTML-escaped; the docs now state explicitly that callers must escape translated strings before rendering them into HTML.- Found and fixed with Fable.
@tekir/loggerv0.1.2
UtilitiesJune 13, 2026
- Pretty-printed output now strips
CR/LF, tabs, ANSI escapes, and control characters from logged strings, closing a log-injection and terminal-escape surface. - Field redaction is now recursive. Matching keys are redacted at every depth across nested objects, arrays, and the merged context; the caller's object is never mutated and circular references are handled.
- The file transport gained a
maxQueueSize(default 10000, drop-oldest with a dropped-line counter) so a slow disk cannot grow the write queue without bound. - Found and fixed with Fable.
@tekir/logger-datadogv0.1.1
UtilitiesJune 13, 2026
- Added a
maxBufferSize(default 10000) so a stalled intake cannot grow the buffer without bound; the oldest entries are dropped and a dropped counter is kept. - Failed deliveries are now visible. Non-2xx responses (for example a
403from an invalid API key) and network errors increment an error counter and fire an optionalonError(err)callback instead of being silent. - The flush timer is unref'd so it no longer keeps the process alive on shutdown.
- Found and fixed with Fable.
@tekir/logger-lokiv0.1.1
UtilitiesJune 13, 2026
- The Loki host is now validated to close an SSRF surface. Only
http/httpsis allowed, and loopback, private, link-local, and cloud-metadata hosts are rejected by default. SetallowInsecureHost: trueto opt into local/dev targets. Behavior change:localhostnow requiresallowInsecureHost. - When
authis configured, anhttp://target is rejected withoutallowInsecureHostso credentials are not sent in plaintext. - Added a
maxBufferSize(default 10000, drop-oldest with a counter) andres.okchecking, so a stalled endpoint cannot grow the buffer without bound and failed deliveries surface via an error counter and optionalonError(err). The flush timer is unref'd. - Found and fixed with Fable.
@tekir/logger-pinov0.1.1
UtilitiesJune 13, 2026
- The bridge now checks that the selected Pino level method is actually a function before calling it, falling back to
info(or returning quietly) instead of crashing at runtime. - Added a typed
PinoLikeinterface so thepinoconfig and transport field are no longerany. - Found and fixed with Fable.
@tekir/viewv0.1.1
UtilitiesJune 13, 2026
render()now setsX-Content-Type-Options: nosniffby default; callers can override it viaheaders.- The
ViewEngineinterface now documents the security contract that engine output must return escaped HTML. - Found and fixed with Fable.
@tekir/dbv0.1.4
DatabaseJune 13, 2026
- Database TLS verification is now on by default. When SSL is in play and no explicit object is given, the driver applies
{ rejectUnauthorized: true }; turning verification off now requires an explicit{ rejectUnauthorized: false }. Thesslconfig also accepts an optionalca. - Every SQL identifier (table and column names in
createTable/dropTable/renameColumnand foreign keys) is now validated against a strict allowlist, so quote/backtick escape attempts throwInvalid SQL identifierinstead of splicing into the query. Model aggregates (sum/avg/min/max/increment/decrement) now validate the column against the model schema. transaction()now runs a realBEGIN/COMMIT/ROLLBACKagainst a single dedicated connection for Postgres, MySQL, and SQLite, so queries inside the callback are genuinely atomic and roll back together on error. Migrations run all their DDL statements inside a transaction where the engine supports it.- Connection pools now apply sane defaults (
max/idle/connection timeouts) and the Postgres pool attaches an error handler so an idle-client error cannot crash the process. Driver connection errors are masked so the connection string password is no longer leaked into error messages. - Pagination clamps
page/perPageto safe bounds (no negativeOFFSET, no zero/NaNLIMIT). - Found and fixed with Fable.
@tekir/mongodbv0.1.1
DatabaseJune 13, 2026
- Query filters are now sanitized against NoSQL injection.
find,findOne,count,exists,deleteMany,updateMany,distinct,paginate, and the soft-delete scopes strip operator keys (those starting with$or containing.) at every depth, while preservingDate/ObjectIdand hand-built queries. - Update operations are now guarded: plain field maps are wrapped in
$set, and explicit operator documents keep only a safe allowlist, so$rename/$unset/$where-style operators cannot be smuggled through. findByIdreturnsnullfor non-string, object, or invalid ObjectId ids instead of throwing a CastError, sofindOrFailgives a consistent not-found result for crafted ids.- Connections now apply pool-size and timeout defaults and attach an error handler (errors surface as a
tekir:errorevent instead of an unhandled rejection). Query debug logging is off unlessdebug: trueis set, so filter values are not logged by default. - Found and fixed with Fable.
@tekir/redisv0.1.1
DatabaseJune 13, 2026
- New
clearPrefix()deletes only this connection's<prefix>:*keys (and deletes nothing when no prefix is set).flushdb()is now flagged as dangerous and points at the safer alternative. remember()now takes a short-livedSET NX EXlock so concurrent callers wait for one computation instead of stampeding, andsetJSON()with a TTL uses a single atomicSET ... EXso a crash can no longer leave a key without its TTL.- Connecting over plaintext in production now logs a warning, and credentials in the connection URL are masked in logs.
getJSONparse failures now log a warning with the key name (return staysnull), andsend()/subscribe()document that they are advanced and that incoming messages must be treated as untrusted.- Found and fixed with Fable.
@tekir/cachev0.1.8
DatabaseJune 13, 2026
- The HTTP response cache is now secure by default. Requests carrying
AuthorizationorCookieskip the cache entirely (authenticated: 'bypass'). Setauthenticated: 'vary'to include credential headers in the cache key, or'allow'to opt back into the previous behavior; a customkeybuilder is always honored. Behavior change: authenticated GETs are no longer cached by default. getOrSetnow shares a single in-flight computation across concurrent misses for the same key (single-flight), so a cold key under load runsfactory()once instead of once per request.RedisCacheStore.flush()now deletes only this store's keys viaSCAN+DELover<prefix>*instead ofFLUSHDB, and throws on an empty prefix (which would have wiped the whole database).setuses an atomicSET ... EXwhere the client supports it.- The memory store now enforces a
maxEntriescap (default 10000, FIFO eviction) with periodic sweeping of expired entries, and both stores gained a manualprune(). - Found and fixed with Fable.
@tekir/sessionv0.1.4
DatabaseJune 13, 2026
- Session cookies are now
HttpOnly+SameSite=Lax+Secureby default.Securedefaults totruein production (and whenNODE_ENVis unset); setcookie.secure: falseto opt out explicitly. - A regenerated session ID is now emitted reliably through whichever response sink is available, and it is an error to regenerate when no sink exists, so a new ID can never be silently dropped.
put/flashnow reject__proto__,constructor, andprototypekeys, closing a prototype pollution vector.- The memory store now evicts expired and over-cap entries via a periodic sweep (default 60 s, unref'd) and a
maxEntriesbound (default 100k), with astop()for clean shutdown. Touching an existing session re-syncs its store TTL with the re-sent cookieMax-Age. - Found and fixed with Fable.
@tekir/authv0.1.7
SecurityJune 13, 2026
- JWT verification now enforces the algorithm. The header is decoded before the signature check and
algmust beHS256(andtyp, if present, must beJWT), soalg:noneand HS/RS confusion attacks are rejected. Tokens must also carry a finiteexpand asub, andnbfis honored when present. - Database token guard now requires
APP_KEYand stores keyed-HMAC tokens. Tokens are persisted asHMAC-SHA256(token, APP_KEY)instead of a plain SHA-256 hash, the plaintext token is returned to the client only once and never written to the database, and a database leak can no longer be used to forge or replay tokens withoutAPP_KEY. Existing stored tokens are invalidated and must be reissued. - Database token comparison now finishes in constant time, and an expired or unparseable
expires_atis rejected rather than treated as a token that never expires. - Failed multi-guard authentication now returns a constant
Unauthorizedto the client; the guard-specific reason is only logged, so the response no longer reveals which guard failed. - Found and fixed with Fable.
@tekir/authorizev0.1.2
SecurityJune 13, 2026
- before-hook semantics are now fail-safe and per-ability. A hook only decides the ability it returns a strict
true/falseorAuthorizationResponsefor; an accidental truthy non-boolean is no longer coerced into a global deny, so a hook can no longer lock down the whole system by mistake. can(ability, resolver)now accepts a lazy(ctx) => unknown[]resolver, so the resource can be loaded from the request and ownership/IDOR checks can run in the middleware. The static-args form stays backward compatible.can()now denies whenauth.isAuthenticated === falseeven if a user object is present, falling back to user presence only for older adapters that never set the flag.- Found and fixed with Fable.
@tekir/hashv0.1.1
SecurityJune 13, 2026
verify()now only returnsfalsefor an unrecognized or malformed hash. Real runtime/infrastructure failures (a missing native module, OOM, and similar) are thrown instead of being swallowed into a silentfalse, which previously could mask a broken setup as a wrong password.- bcrypt
make()/verify()warn when the input exceeds bcrypt's 72-byte limit (where the tail is silently ignored), pointing at pre-hashing or argon2/scrypt. - scrypt verification validates the parsed
N,r,p,keylenparameters and returnsfalseon invalid values without calling intocrypto.scrypt. - Found and fixed with Fable.
@tekir/encryptionv0.1.2
SecurityJune 13, 2026
- Each encryption now generates a fresh 16-byte random salt and embeds it in the payload, with key derivation bound to that salt. The same
APP_KEYproduces a different key per ciphertext, closing precompute/rainbow attacks and key sharing across installs. - The constructor now validates
APP_KEYfor a minimum length and basic entropy and throws a clear error otherwise. - A
decryptJSON-parse failure now throws the same generic error as a decryption failure (the JSON hint is log-only), so it does not signal payload structure to an attacker. - Found and fixed with Fable.
@tekir/corsv0.1.5
SecurityJune 13, 2026
- CORS now requires an explicit origin allowlist when credentials are enabled. Combining
credentials: truewithorigin: true(reflect any origin) now throws at construction; you must pass a concrete string, array, or function. - With credentials enabled, an
Origin: nullrequest is now passed through without CORS headers instead of echoingnull, andAccess-Control-Allow-Headersreflects only the headers the client actually asked for rather than*(the*behavior is kept when credentials are off). - Array origin matching is now exact and case-sensitive (the previous lowercasing is gone), and empty
methods/headersno longer emit an emptyAllow-*header. - Found and fixed with Fable.
@tekir/shieldv0.1.2
SecurityJune 13, 2026
- CSRF tokens are now HMAC-signed when a
secretis set. The session stores only the random value and verification recomputes the HMAC and compares in constant time. Verification is now fail-closed: a missing token is rejected instead of being lazily minted as valid. - Added
rotateCsrfToken(ctx)(call it after login/logout) pluscsrf({ rotateOnUse: true })for one-time rotation after each successful mutation. shield()now applies CSP defaults even whencspis not specified; passcsp: falseto disable it.X-Frame-Optionsis restricted toDENY/SAMEORIGIN(the deprecatedALLOW-FROMis removed), and HSTSpreloadnow defaults tofalse(opt-in).- Found and fixed with Fable.
@tekir/limiterv0.1.1
SecurityJune 13, 2026
- The rate limiter no longer trusts
X-Forwarded-ForwithouttrustProxy. The newtrustProxyoption defaults tofalse, in which case onlyctx.request.ipis used; set it totrue(left-most) or a number of hops to parse the forwarded chain, so a client can no longer spoof its identity to dodge limits. - Counting is now atomic at the store level. The check-then-consume race is gone (a single atomic consume handles increment plus lockout), verified under concurrency, so a burst of simultaneous requests can never exceed the limit.
- Identifiers are URL-encoded before building the bucket key, so a
:in an IPv6 or custom identifier cannot collide with another bucket. The memory store now sweeps expired entries on a periodic, unref'd timer. Retry-Afteris now sent only when the limit is actually exceeded.- Found and fixed with Fable.
@tekir/validatorv0.1.2
SecurityJune 13, 2026
- Validated data is now written to the context only after every source has passed, so a failure on one source can no longer leave a partially-validated request in place.
- An unrecognized schema shape now throws (fail-closed) instead of silently passing the request through unvalidated.
- Valibot schema detection is now reliable and ordered ahead of Zod, fixing a dead branch.
- Found and fixed with Fable.
@tekir/socialv0.1.2
SecurityJune 13, 2026
- Apple
id_tokenis now cryptographically verified. The token's RS256 signature is checked against Apple's JWKS (with thekid, cached for an hour) andiss/aud/exp(plus optionalnonce) are validated, so a forged or decode-only token is rejected and only a verifiedemail_verifiedaddress is accepted. - OAuth flows now use PKCE (S256) end to end. Every
redirect()generates a verifier/challenge, the authorization URL carriescode_challenge, andexchangeCodesends thecode_verifier. - OAuth state is now bound to the user's session.
handleCallbackrequires the stored state in both signed and plain modes (fail-closed) and compares the state's bound nonce in constant time, closing login-CSRF and replay. - Redirect validation now allows only
http(s)(rejectingjavascript:/data:/file:), enforces real label boundaries for wildcard matches, and requires HTTPS. The GitHub email fallback accepts only a primary verified address. Access and refresh tokens are made non-enumerable so they do not leak throughJSON.stringify, spread, or most logging. - Found and fixed with Fable.
@tekir/mailv0.1.1
CommunicationJune 13, 2026
- Every message is now sanitized for header injection before it reaches a transport.
from/to/cc/bcc/replyTo/subject, custom headers, and attachment filenames are stripped ofCR/LF, including for messages dispatched directly or via the notification mail channel that previously bypassed the builder. - SMTP now enforces TLS.
requireTLSdefaults totrueon non-secure connections (STARTTLS required) andtlsdefaults to verifying the certificate (rejectUnauthorized: true), with optionalca/servername. - The log transport now redacts by default (
LogConfig.redact, defaulttrue): addresses are masked, the body is never logged, and non-pretty mode writes only metadata. Setredact: falseto opt back into full content. - Provider error bodies returned to the caller are truncated, and the SES transport's signing date and canonical query are now deterministic and RFC-3986 correct.
- Found and fixed with Fable.
@tekir/queuev0.1.2
CommunicationJune 13, 2026
- Job claiming is now atomic on the database and Redis backends, so two workers can never pick up the same job. The database backend uses a conditional claim with a unique token; the Redis backend uses a single Lua script, which also means a crash mid-claim no longer strands a job.
- Both backends gained a visibility timeout (60 s). A job whose worker died mid-processing is recovered back to pending instead of being lost, and retries now persist the attempt count on the existing row instead of re-pushing (no primary-key collisions).
- Poison jobs no longer retry forever. A new
NonRetryableErroris thrown for invalid JSON or an unregistered job class and fails the job immediately without consuming the retry budget. concurrency(n)andpollInterval(ms)now reject non-positive,NaN, and negative values.- Found and fixed with Fable.
@tekir/notificationv0.1.2
CommunicationJune 13, 2026
- The database channel now redacts sensitive keys (
password,token,secret,apiKey,otp,pin,ssn,cvv, and similar, including nested objects) before storing a notification payload. - FCM push now sends a matching auth and endpoint pair: an OAuth access token uses the v1 endpoint with
Authorization: Bearer, otherwise the legacykey=endpoint is used, and both paths checkresponse.okand honor a configured endpoint. User ids are normalized to FCM's allowed topic character set. sendandsendManynow usePromise.allSettled, so one channel or recipient failing no longer drops the others; failures are logged.- The mail channel sanitizes its payload through
@tekir/mail's header-injection sanitizer as defense in depth. - Found and fixed with Fable.
@tekir/emitterv0.1.5
CommunicationJune 13, 2026
- A handler that throws no longer aborts dispatch or rejects the emit. A shared error path routes the error to
onError(orconsole.error) and continues to the remaining handlers, including wildcardonAnyhandlers, which previously swallowed errors silently. Behavior change: with noonErrorset,emitno longer rejects on a handler error (handlers are isolated by default). wait()and the async-iterator helpers no longer leak listeners. Timeout, abort, and normal completion all remove the handler and clear timers, so repeated timeouts or abreakout offor awaitcannot accumulate listeners.- The async-iterator buffer is now bounded by
maxBufferSize(default 1024, drop-oldest), so a fast producer with a slow or absent consumer cannot grow memory without bound. - Added a per-event listener threshold (default 100) with a one-time possible-memory-leak warning and a
setMaxListeners(n)API (0disables it). - Found and fixed with Fable.
@tekir/cronv0.1.5
CommunicationJune 13, 2026
- Overlapping runs of the same job are now prevented. A per-job in-flight flag (plus the underlying scheduler's overlap protection) skips a tick that arrives while the previous async run is still going, so a long job no longer runs concurrently with itself.
- An invalid cron pattern now throws at registration time with the job name and pattern, and the job is not registered, instead of failing later at tick time.
- Added an async
shutdown()that stops every job's timer and clears the registry, so no further ticks fire after it returns. - Found and fixed with Fable.
@tekir/drivev0.1.2
Storage & ParsingJune 13, 2026
- New
serveDrive()fallback handler that, by default (requireSignature: true), requires a validtoken+expiressignature on every request under its URL prefix and returns403for a missing, wrong, or expired signature. LocalDrivernow enforces upload validation. A newuploadoption (allowed extensions plus max size, settable per disk inconfig/drive.ts) is applied input(), including the streaming path, and helpers likesanitizeFilename/validateUploadare exported.- Local path handling is hardened: a key containing a null byte throws
Path traversal detected, andgetUrl/getSignedUrlresolve and per-segment URL-encode the key while keeping the signature round-trip intact. - The S3
list()now follows pagination to return every key and decodes XML entities in key names. - Found and fixed with Fable.
@tekir/staticv0.1.2
Storage & ParsingJune 13, 2026
- A decoded path containing a null byte is now rejected as malformed instead of reaching the filesystem.
- Symlink traversal is now blocked when opted in. With
symlinks: 'deny', the resolved real path is verified to stay under the root in both the middleware and the provider fallback (default stays'follow'for backward compatibility). - A read error mid-request now falls through to
next()instead of crashing, and the docs call out thatdotFiles: 'allow'will serve.env/.git. - Found and fixed with Fable.
@tekir/bodyparserv0.1.5
Storage & ParsingJune 13, 2026
- Multipart parsing is now streaming with limits applied as the body is read.
maxFileSize, totallimit,maxFiles(default 20),maxFields(default 1000), andmaxParts(default 1000) are enforced during the read and abort early with a413once exceeded, so a large upload is no longer buffered fully into memory. Parts overspillThreshold(default 1 MB) stream to a temp file to keep memory bounded. - JSON, form, and raw bodies are also size-limited during the read (with a
Content-Lengthpre-check) and cancel as soon as the limit is exceeded. - JSON parsing now strips
__proto__,constructor, andprototypekeys recursively, consistent with the urlencoded path, closing a prototype pollution vector. - SVG content detection is hardened so that crafted XML/HTML no longer passes as an image; the docs note that SVG is an active document and should not be added to an
extnameswhitelist without sanitization. Method spoofing is now opt-in viamethodSpoofing: trueand only upgrades real POST requests (a GET can never be mutated). - Found and fixed with Fable.
@tekir/decoratorsv0.1.1
DecoratorsJune 13, 2026
createEventDecoratornow handles instance methods instead of silently doing nothing: an instance method is registered against its constructor with a bound handler.composenow reverses a copy of the decorator list, so applying the same composed decorator to multiple classes is order-consistent (idempotent).- Found and fixed with Fable.
@tekir/http-decoratorsv0.1.2
DecoratorsJune 13, 2026
- Controller loading is now resilient. A controller whose constructor throws is skipped with a named warning instead of aborting registration, a method that is not actually a function is skipped, and the remaining routes still register.
- A subclass no longer shares its parent's
__routesarray; it inherits a copy, so adding routes on a subclass cannot mutate the parent. - Importing
@tekir/http-decoratorsno longer pulls in@tekir/cache; the cache dependency is loaded lazily only when@Cache(...)is actually used, with a clear error if the package is missing.@Websocketroutes now warn that they are skipped instead of disappearing silently. - Found and fixed with Fable.
@tekir/db-decoratorsv0.1.1
DecoratorsJune 13, 2026
- Field decorators (
@hidden,@fillable,@cast, relations) and lifecycle hooks now build their own collection per class and inherit a copy of the parent's, so adding fields or hooks on a subclass no longer mutates the parent class. This keeps the mass-assignment boundary (@hidden/@fillable) correct across inheritance. - Found and fixed with Fable.
@tekir/cron-decoratorsv0.1.1
DecoratorsJune 13, 2026
@Schedulenow validates the cron pattern at decoration time, throwing a meaningful error (with the pattern) for an empty pattern or a wrong field count.@Everynow enforces sensible ranges (1-59for seconds/minutes,1-23for hours) and rejects out-of-range or unrecognized values like90s,25h, or1dinstead of silently falling back.@CronJobnow walks the prototype chain and reads methods without triggering getters, collecting each overridden method once.- Found and fixed with Fable.
@tekir/event-decoratorsv0.1.1
DecoratorsJune 13, 2026
- Multiple event decorators on one method are now all registered. Stacking
@On('a') @On('b')(or@Onplus@Once) on the same method binds each one separately instead of the last one winning. @On/@Oncenow throw at decoration time for an empty or whitespace-only event name.@Listenernow walks the prototype chain and reads methods without triggering getters, collecting each overridden method once.- Found and fixed with Fable.
DecoratorsJune 13, 2026
- Added tests that guard the public API surface: every documented decorator is verified to be defined and each re-exported symbol is confirmed to be the same reference as its original in
@tekir/swagger, so an export drift cannot slip through unnoticed. - Found and fixed with Fable.
@tekir/cliv0.1.6
Dev ToolsJune 13, 2026
- The entry path is now validated to stay under the current working directory before it is imported, so a crafted
--entry ../../evil.ts(or an absolute path outside the repo) is refused rather than executed. Both the run and build paths share this guard. - Env-file loading no longer double-applies. After the parent loads env files it marks them so the re-exec'd watch child inherits the flag and skips reloading, removing duplicate loads and warnings. Quoted env values are taken verbatim and an unquoted trailing
# commentis trimmed without corrupting tokens likepa#ss. - Writing the temporary build entry is now wrapped so a read-only directory produces a clear warning and falls back to a full-entry import instead of crashing.
- On Node,
tekir testusesnpx --no-install vitest run, so a missing local vitest fails fast instead of silently downloading from the registry. - Found and fixed with Fable.
create-tekir-appv0.1.9
Dev ToolsJune 13, 2026
- The project name passed on the command line is now validated. A target that resolves outside the current directory (via
./.., an absolute path, a path separator, or other unexpected characters) is rejected before any directory is created, so scaffolding cannot write to an arbitrary location. - The generated
package.jsonname is normalized (lowercased, leading./_stripped, falling back toapp), so an unusual project name no longer produces an invalid manifest. - Interactive prompts now handle a closed or piped stdin (CI) by resolving empty instead of hanging forever.
- Found and fixed with Fable.
@tekir/testingv0.1.8
Dev ToolsJune 13, 2026
- Table names in test database helpers are now validated and any embedded quote is escaped, so a quoted table name cannot break the query.
FakeDatenow forwards its constructor arguments unchanged, sonew Date(timestampNumber)parses correctly instead of producing an Invalid Date.- The in-memory database override now uses a shallow structural clone (only swapping the sqlite path to
:memory:) instead of a JSON round-trip, so function/Date/undefinedfields in the config survive. - JSON assertions (
assertJson/assertJsonContains/assertJsonPath/assertError) now compare structurally and are independent of key order. - Found and fixed with Fable.
@tekir/swaggerv0.1.4
Dev ToolsJune 13, 2026
- Swagger docs are now gated by environment by default. Under
NODE_ENV=productionwith noauthconfigured, the routes are not registered and a warning is logged. UseSwaggerConfig.enabledto force the docs on or off in either direction. - New
@ApiHide()decorator plusSwaggerConfig.hidePaths(string prefix or RegExp) let you keep internal routes out of the generated spec. - Found and fixed with Fable.
@tekir/healthv0.1.1
Dev ToolsJune 13, 2026
- Debug info is no longer included in the report by default. Pass
run({ debug: true })(from an internal or authorized endpoint) to include it. Behavior change: the public report no longer exposes pid, platform, or version. - Each check now runs under a timeout (default 5000 ms, configurable via
run({ timeout })); a timed-out or throwing check is reported as anerrorresult instead of taking down the whole report. DbCheck/RedisChecknow return a genericConnection failed; the raw error is log-only, so connection details are not leaked in the response. A report with no checks registered now warns rather than reporting a misleading healthy.- Found and fixed with Fable.
@tekir/vitev0.1.6
FrontendJune 13, 2026
- Static file serving for
public/anddist/now goes through a hardened path resolver, matching@tekir/static: percent-decoding is guarded, null bytes and cross-drive paths are rejected, every segment is checked for dotfiles (.env/.git), and backslash-encoded separators are handled. This closes a path-traversal surface in the prod static fallback. - The compiled import path is now embedded safely so a crafted path cannot break out of the generated source.
- Found and fixed with Fable.
@tekir/nextv0.1.4
FrontendJune 13, 2026
- Proxied responses now stream straight through instead of being buffered into memory first, so large or streaming Next responses no longer pay a full-body buffering cost.
- A failed hop into the internal Next listener now returns
502 Bad Gatewayand is logged; a404only comes from Next's own response. If Next fails to start, the init state is reset so the next request retries instead of staying broken. - Found and fixed with Fable.
@tekir/corev0.1.33
CoreMay 28, 2026
- The server now binds the configured host. Setting
hostinconfig/app.ts(ortekir({ config: { app: { host } } })) is honoured instead of always listening on every interface. Previously the value was read for the Node fallback runtime but never passed toBun.serve, so on Bun the bind address silently stayed0.0.0.0. Usehost: '127.0.0.1'to accept only local connections,host: process.env.HOST ?? '0.0.0.0'to wire it from the environment, or leave it unset to keep the default0.0.0.0(all interfaces).hostnameis accepted as an alias forhost(matching Bun.serve's option name);hostwins if both are set.
@tekir/corev0.1.32
CoreMay 28, 2026
- Fixed:
async function*route handlers streamed nothing and returned{}with a JSON content type. Async generators exposeSymbol.asyncIteratorrather thanSymbol.iterator, and the handler dispatcher only recognised the latter, so the generator object fell through to JSON serialisation (which has no enumerable keys). Both the middleware and no-middleware dispatch paths now detect either iterator protocol. Syncfunction*handlers on a route with no middleware were also affected — that path had no generator detection at all — and now stream correctly too. - Fixed: streamed responses always went out as
Content-Type: text/plaineven when the handler yielded SSE frames (data: ...). The SSE-vs-plain decision ran inside the stream'spull()callback, butnew Response(stream, init)snapshots its headers at construction, beforepull()ever fires, so the detection was dead code. The first chunk is now pulled up front, so an SSE generator correctly emitsContent-Type: text/event-stream(plusX-Accel-Buffering: noso proxies do not buffer the stream). NativeEventSourceclients work against generator routes now; previously only manualfetch().body.getReader()consumers did. Object streams that are not SSE keep their newline-delimitedtext/plainJSON shape.
@tekir/corev0.1.31
CoreMay 17, 2026
- Inline routes that return a fully static literal (
() => ({ message: 'Hello' }),() => [1, 2, 3], primitives, deeply-nested literal objects, etc.) now serialise their body once at registration time and emit anew Response(precomputedString, frozenInit)per request. Routes that touchparams,query,body, or any closure variable keep going through the existing compiled path so behaviour is unchanged; only handlers whose entire return expression is JSON-safe and free of identifiers likenew,function,this,globalThis,Bun, etc. opt in. - The synthetic 404 fallback now lives under Bun.serve's native
/*route instead of going through thefetchcallback when the server has no WebSocket routes, no domain routes, and no user-suppliedserver.fallback(...). In that caseserveConfig.fetchis dropped entirely, so unmatched requests dispatch through the radix tree without a JS callback round trip. Apps that use websockets, multi-tenant subdomain routing, or callserver.fallback(handler)keep the previous behaviour. - Shared
JSON_RESPONSE_INITconstant used by every JSON response path (compiled handlers,response.json(),response.send(obj),response.ok(obj),response.created(obj), etc.) so the per-request header allocation drops out of the hot path. Functionally identical to the previousResponse.json(...)call; the wire format does not change.
@tekir/corev0.1.30
CoreMay 17, 2026
response.encryptedCookie(name, value, secret)now produces an authenticated AES-256-GCM ciphertext instead of a base64-encoded payload with an HMAC tag. Anyone observing the cookie value can no longer decode its contents; tampering fails the auth tag check on the read side. The cookie shape changes from${base64url}.${signature}to${iv}.${ciphertext}.${authTag}; cookies issued by older releases will not decrypt with the new reader and need to be re-issued (clear and let the next request mint a fresh one).- New top-level helpers
encryptCookieValue(value, secret),decryptCookieValue<T>(token, secret), andverifySignedCookieValue(token, secret)exported from@tekir/core. Use them on the request side to read back cookies set viaresponse.encryptedCookie(...)andresponse.signedCookie(...). Both readers returnnullon tampering, expiry, or malformed input so callers can branch on a single nullable result. response.download(path)andresponse.attachment(path, name?)now keep theContent-Dispositionheader. The helpers staged it on the response builder but the runtime file response replaced the entireHeadersobject, so browsers fell back to inline display for any extension the OS happened to know. The merged response also picks up any cookies queued viaresponse.cookie(...)before the download return.
@tekir/dbv0.1.3
DatabaseMay 17, 2026
select(...)now rejects column strings that contain parentheses, whitespace, semicolons, or SQL comment markers. The previous behaviour silently passed any string containing(through as raw SQL so callers could writeselect('COUNT(*)'), but it also meant a request value that reachedselect()could splice arbitrary SQL into the query. Aggregate expressions move to a new opt-inselectRaw(expression)API; the built-incount()/sum()/avg()/min()/max()already use the raw path and keep working unchanged.forPage(page, perPage)rejects values below 1 and non-finite numbers instead of producing negativeLIMIT/OFFSET. The check funnels through the existinglimit()andoffset()guards so the rest of the builder sees a single validated state.drizzle-ormbumped to^0.45.2to pick up the upstream SQL identifier escaping fix.
@tekir/authv0.1.6
SecurityMay 17, 2026
JwtGuard.generate(user, { claims })now throws whenclaimscarries any of the registered namessub,iat, orexpinstead of silently letting the caller override the subject or token timestamps. Reserved-claim handling is explicit, so a typo in a custom claim cannot mint a token whosesubdoes not match the user passed in. Apps that legitimately want a customsubshould switch to a different identity model rather than rewriting the claim.
@tekir/socialv0.1.1
SecurityMay 17, 2026
Socialnow refuses to construct underNODE_ENV=productionwhenAPP_KEYis missing, instead of warning and falling back to unsigned state tokens. Dev and test environments still see the warning and the unsigned fallback so quick spike work keeps moving.- Absolute redirect URLs now require
allowedRedirectsin the config. The previous behaviour treated an empty list as no restriction at all, so a freshly configured app could accept?redirect=https://evil.com/pathend to end. Protocol-relative URLs like//evil.com/pathare now resolved againsthttps:and run through the same allowlist instead of slipping past astartsWith('/')shortcut. - OAuth state HMAC comparison now runs in constant time. The library already signed the state token; this closes the timing-side-channel ambient to any HMAC verification.
@tekir/drivev0.1.1
Storage & ParsingMay 17, 2026
LocalDriver.getSignedUrl(...)now produces a real HMAC-SHA256 signature keyed byAPP_KEY(or a constructor-passedsecret) instead of returning the storage key and expiry as a base64 payload. The previous token could be decoded, edited, and re-encoded to forge access to any local file. The newLocalDriver.verifySignedUrl(key, token, expires)checks the signature in constant time and rejects expired URLs; call it from any custom handler that serves files behind signed URLs.LocalDriverconstructors that do not configure a signing secret now throw on the firstgetSignedUrl()call instead of returning a forgeable token silently. SetAPP_KEYin the environment or passsecretper disk inconfig/drive.ts.- Windows cross-drive traversal is now blocked. A
keyresolving to a different drive letter than the disk'sroot(for exampleD:\\secret.txtagainst aC:\\app\\storageroot) is rejected before any filesystem access. POSIX behaviour is unchanged.
@tekir/staticv0.1.1
Storage & ParsingMay 17, 2026
- Malformed percent-encoded paths (
/foo%, truncated sequences) now respond with400 Bad Requestinstead of crashing the request with a generic 500. The decode step is wrapped and the failure reason is surfaced to the caller. - Dotfile policy now applies to every path segment, not just the trailing filename. With the default
dotFiles: 'ignore'setting,GET /.git/configandGET /.env/foono longer reach the filesystem;dotFiles: 'deny'returns403 Forbiddenfor the same paths, anddotFiles: 'allow'opts into the previous behaviour for use cases like.well-known/. - The segment scan recognises both
/and\\as separators. Windows previously accepted backslash-encoded requests likeGET /assets%5C.git/configbecause the runtime resolves\\as a path separator while the dotfile filter only split on/. POSIX behaviour is unchanged. - Windows cross-drive paths are now blocked. A request whose decoded path resolves to a different drive than the configured
diris treated as traversal even whenrelative()does not return a..-prefixed result. POSIX behaviour is unchanged. - The middleware and the
StaticProviderfallback now share a singleresolveSafePath()helper so both surfaces apply the same encoding, dotfile, and traversal rules.
@tekir/bodyparserv0.1.4
Storage & ParsingMay 17, 2026
- Multipart uploads now reject oversize requests before parsing. When the incoming
Content-Lengthexceeds the configuredlimit,parseMultipart()throws a newPayloadTooLargeError(HTTP 413) instead of buffering the whole payload into the runtime'sFormDataparser first. Apps that catch framework errors get a clean 413 path; apps that don't were previously paying memory cost for the rejection. - A user-supplied
tmpFileName()callback can no longer write outsidetmpDir. The returned name isbasename()-stripped and the final path is verified to stay under the configured directory; paths like../../etc/passwdare rejected and surface as atmpFileNamevalidation error on the affected upload rather than escaping containment. PayloadTooLargeErroris exported from@tekir/bodyparserfor callers that want to branch on it or attach a custom error handler.
@tekir/swaggerv0.1.3
Dev ToolsMay 17, 2026
- Swagger UI assets now load from a pinned
[email protected]URL with optional Subresource Integrity. The newui.cssUrl,ui.jsUrl,ui.cssIntegrity, andui.jsIntegrityconfig keys let apps self-host the bundle or pin SRI hashes that the browser enforces before executing the CDN payload. - The
/docsHTML response now ships a strictContent-Security-Policywith nounsafe-inline. The only inline bootstrap is allowlisted via its SHA-256 hash, so any injected<script>is refused by the browser. The response also carriesX-Frame-Options: DENY,X-Content-Type-Options: nosniff, andReferrer-Policy: no-referrer. jsonPathis now embedded into the bootstrap viaJSON.stringify(...)plus</scriptescaping, so a customconfig.pathcannot break out of the inline script context.- Basic auth credential comparison now hashes both sides to fixed-length HMAC digests before
timingSafeEqual(). Earlier releases short-circuited on length mismatch, which leaked the password length to attackers timing the response. Theauthconfig surface is unchanged.
@tekir/nextv0.1.3
FrontendMay 17, 2026
- The proxy hop into the internal Next listener now drops every header that the upstream Next process should determine for itself. Hop-by-hop fields (
connection,upgrade,keep-alive,te,transfer-encoding,proxy-authorization,content-length) and authority fields (host,forwarded,x-forwarded-*,x-real-ip,x-original-url,x-original-host) are stripped before the inner fetch; an internalhostmatching the loopback port is set. Closes the SSRF/middleware-bypass surface that comes from blindly forwarding a public request's headers to a private upstream. - Starter templates and example apps are pinned to
next ^16.2.6to pick up the upstream proxy/middleware advisories.
@tekir/dbv0.1.2
DatabaseMay 12, 2026
- Internal release covered by 0.1.3 notes.
@tekir/corev0.1.29
CoreMay 10, 2026
tekir buildno longer evaluates the user entry's full top-level. The build path now parses the entry withoxc-parser, walks back from theawait tekir({...})call, keeps only the imports and declarations its argument expression depends on, and writes that to a temporary file the cli imports in place of the original. Thetekir()call still fires (soonBuildhooks register andBun.buildruns against the original entry), butapp.router.registerDir(...),app.start(...), eager service constructors with TCP connects, scheduler ticks, and fs watchers are skipped — none of which the bundler ever needed. Builds are faster and stop hanging on a misconfigured remote dependency that would never have been needed at build time. NewgenerateBuildEntry(entryPath)is exported for tools that want to drive the same extraction. Dynamic config insidetekir({...})(env-derived ports, conditional frontend types, computed providers) is preserved verbatim because the call expression is kept as-is; only unreachable top-level statements are dropped.process.env.TEKIR_RUNNERis set to'build'(via??=, so an outer caller can pin a different value first) whenever the entry detectscliCmd === 'build'. Pairs with the'test'valuetekir testalready exports. Most library code is no longer imported during build at all (the entry extractor sees to that), so the flag is a belt-and-suspenders safety net for the rare entry shape that falls back to a full-entry import; libraries that want to short-circuit eager module-init side effects can still gate onTEKIR_RUNNER === 'build' || TEKIR_RUNNER === 'test'. The contract is documented at/advanced/runner-modes.
@tekir/cliv0.1.5
Dev ToolsMay 10, 2026
tekir builddrives the new build-entry extractor in@tekir/core0.1.29. The cli reads the entry throughgenerateBuildEntry, writes the extracted source to a temp file, setsprocess.argv[1]to the original entry path so the in-app build dispatcher bundles the real file, then imports the temp source. User entries that the extractor cannot statically resolve (no literaltekir()call, multiple calls, parse error) fall through to a plain full-entry import as a last resort, so the worst case is identical to the historical behaviour.tekir buildexportsTEKIR_RUNNER=build(via??=, so a CI script that already pins the value is left alone) before handing the entry to Bun, mirroring the'test'valuetekir testsets. Most library code is no longer imported during build at all (the entry extractor sees to that), so the flag is a belt-and-suspenders safety net for the rare entry shape that falls back to a full-entry import; libraries can still gate onTEKIR_RUNNER === 'build' || TEKIR_RUNNER === 'test'to short-circuit eager init. Convention documented at/advanced/runner-modes.oxc-parseris now a regular@tekir/clidependency instead of an optional peer.bun add @tekir/cliis enough to get the build-entry extractor and the autoload inliner working out of the box; the long-standing[build] \oxc-parser\is not installedwarning that confused users who never knew what to do with it is gone.@tekir/corekeepsoxc-parseras an optional peer for the rare consumer that uses the framework without the cli (e.g. drivingBun.buildprogrammatically with hand-rolled scripts).
@tekir/corev0.1.28
CoreMay 8, 2026
app.start()honours thetekir testrunner signal. When the cli'stestsubcommand exportsTEKIR_RUNNER=testbefore launching the runtime's native test command, a user entry's top-levelapp.start(callback)short-circuits instead of binding the env-configured port. The canonical entry shape becomes the unconditionalapp.start(cb); the per-appif (env !== 'test')guard goes away. Integration tests that genuinely want a real socket passapp.start({ force: true })to opt back in. The lower-levelserver.start()(used by@tekir/testing'screateTestApp) is unaffected, so request-fixture tests keep working without changes.StartOptions.force?: booleanexported alongside the existingmodeandcallbackfields, for code paths that want a real socket regardless of how the process was launched (dashboards, smoke checks,frontend-env-exposure-style integration tests).
@tekir/cliv0.1.4
Dev ToolsMay 8, 2026
- New
tekir test [args]command: a thin runner shim that exportsNODE_ENV=testplus theTEKIR_RUNNER=testsignalapp.start()listens for, then hands control to the runtime's native test runner (bun teston Bun,vitest runon Node). The signal is what lets a user entry's top-levelapp.start(callback)short-circuit when imported by a test file, so the canonical entry shape becomes the unconditionalapp.start(cb)and the per-appif (env !== 'test')guard goes away. Forwarded args go to the runner verbatim:tekir test --watch,tekir test path/to/file.test.ts, etc. Pairs with@tekir/core0.1.28'sapp.start({ force: true })for integration tests that need a real socket.
@tekir/vitev0.1.5
FrontendMay 8, 2026
- Vite middleware honours the
tekir testrunner signal. Whenprocess.env.TEKIR_RUNNER === 'test'the dev gateway block (which would otherwise spin up its own listener onapp.port) is skipped, so a user entry can keepfrontend: { type: 'vite' }unconditional without aprocess.env.NODE_ENV === 'test' ? undefined : ...ternary. The build hook (server.onBuild) and the prod static fallback are still registered — they don't bind anything, so they're safe under tests and atekir buildrun still producesdist/client/.
@tekir/nextv0.1.2
FrontendMay 8, 2026
- Next middleware honours the
tekir testrunner signal. Whenprocess.env.TEKIR_RUNNER === 'test'the internal Next listener is not started (it would have spun up its own random-port HTTP server otherwise). The fallback handler stays registered and no-ops whennextPortis unset, matching the prod-without-dev-server path. Lets a user entry keepfrontend: { type: 'next' }unconditional under tests instead of the per-app NODE_ENV ternary.
@tekir/corev0.1.27
CoreMay 8, 2026
- Cleaned up error code naming on every built-in
HttpExceptionsubclass: theE_prefix is removed in favour of plainUPPER_SNAKE_CASEmatching the HTTP status name (NOT_FOUND,BAD_REQUEST,UNAUTHORIZED, ...). Aligns with gRPC, Google Cloud, AWS Cognito, and Stripe'ssnake_caseconventions;error.codealready implies "this is an error" so the prefix is redundant. **Breaking**: callers that branch onerr.code === 'E_NOT_FOUND'(etc.) need to drop the prefix. The companion releases ship the same change in@tekir/auth(UNAUTHORIZED),@tekir/authorize(AUTHORIZATION_FAILURE),@tekir/db(ROW_NOT_FOUND), and@tekir/validator(VALIDATION_ERROR). SSE.retrytyped asnumber | string. The runtime path always coerces withString(data.retry)and strips newlines, so passing either shape is safe; the type now matches the implementation. Letsretryflow through configs that hold the value as a string without an intermediate cast.
@tekir/cachev0.1.7
DatabaseMay 8, 2026
Cache.get<T>and the per-storeget<T>methods now defaultTtoanyinstead ofunknown. Callers no longer need a redundant generic argument or runtime type guard to read a value back out:await cache.get('user')returns a value you can use directly. Pass an explicit type (cache.get<User>('user')) when you want narrowing back.
@tekir/sessionv0.1.3
DatabaseMay 8, 2026
Session.get<T>defaultsTtoanyinstead ofunknown. Reading session data no longer needs a redundant cast or type guard for the common case (session.get('user')is usable directly). Pass an explicit type when narrowing matters:session.get<UserId>('userId').
@tekir/authv0.1.5
SecurityMay 8, 2026
- Internal release covered by 0.1.6 notes.
@tekir/encryptionv0.1.1
SecurityMay 8, 2026
Encryption.decrypt<T>defaultsTtoanyinstead ofunknown. Round-tripped values are usable directly without a generic argument; pass an explicit type when narrowing back to a specific shape (enc.decrypt<User>(token)).
@tekir/notificationv0.1.1
CommunicationMay 8, 2026
assertSentand the related sent-history matchers now accept any concreteBaseNotificationsubclass without a cast. Notification classes commonly take constructor arguments (new WelcomeNotification(userName)); the previous signature required(...args: unknown[])which is contravariantly incompatible with that pattern, so aWelcomeNotificationconstructor reference would not type-check.
@tekir/testingv0.1.7
Dev ToolsMay 8, 2026
defineFactory(defaults, model)now accepts a model that implements onlycreateor onlycreateMany. Both methods are optional on theFactoryModel<T>interface; callingfactory.create()against a model withoutcreate(orfactory.createMany()withoutcreateMany) throws a clear runtime error pointing at the missing method. Lets you back a factory with a thin wrapper around either an ORM's bulk insert or a single-row insert without faking the other.
@tekir/swaggerv0.1.2
Dev ToolsMay 8, 2026
@ApiParamaccepts anenumfield on its options, matching the OpenAPI parameter spec:@ApiParam('status', { type: 'string', enum: ['active', 'inactive'] })now type-checks and propagates into the generated spec.buildOpenApiSpec(router, config)acceptsnull/undefinedfor the router argument. The runtime path already returned an emptypathsobject for falsy routers; the signature now matches the documented behaviour.RouterLike.getis optional. Spec-only consumers (a plain trie wrapper, a test fixture, a CI script generating JSON) can satisfy the interface without supplying a handler-registration method;swagger()still requires it for live UI wiring.
@tekir/corev0.1.26
CoreMay 6, 2026
- **Breaking**:
tekir startis removed. Usetekir servefor every long-running server invocation (dev, local prod, deploy targets like PM2/Docker/systemd). The two diverged historically only becausestartcarried a buggy non-awaited auto-dispatch that double-bound the port when a user entry also calledapp.start(callback); collapsing to a single command means user code is identical across every launch shape. Migration is a one-linepackage.jsonedit:"start": "tekir serve --entry ./dist/index.js ..."(the npm script name keeps working, only the CLI subcommand changes).
create-tekir-appv0.1.8
Dev ToolsMay 6, 2026
- All five templates now scaffold
bun run startastekir serveinstead oftekir start. The two are aliases on the CLI side, butserveis the canonical name documented in the help output and in@tekir/core0.1.25's unified dispatch. New projects start on the canonical command, so the deprecated alias only sticks around for existing scripts.
@tekir/corev0.1.25
CoreMay 6, 2026
- Command dispatch is flag-aware. Operators can put options before the command word and the right path still fires:
./server --port 8080 build,bun run index.ts --watch serve, andtekir --entry foo migrateall resolve to their command instead of treating the leading flag as a positional. Critical for compiled binaries, where flag-first invocations are the common shape (PM2/Docker/systemd-style env and port flags). The same scan also feeds the earlyNODE_ENVsetter and theenvironmentdetector, so all three layers agree on what the user actually asked for. tekir serve(without--dev) defaultsNODE_ENVtoproductionwhen the shell did not set it, matching thetekir buildprecedent. The cli bin already exportsNODE_ENV='development'before re-execing the watch child for--dev, so the dev path is preserved. Combined with thebun buildbanner shipped in 0.1.24, every prod entry path now sees the right env without an explicitNODE_ENV=productionon the command line.
@tekir/vitev0.1.4
FrontendMay 6, 2026
- Fix: production builds no longer return the SPA
index.htmlfor unmatched backend paths. Requests to a configuredproxyPathsprefix (default['/api']) that the router did not claim now return a404 application/jsoninstead of the 200 HTML shell, matching the contract clients already expect from the dev gateway. The same gate applies to compiled binaries' embed map. Custom prefixes still work — setproxyPaths: ['/api', '/v2', '/internal']to extend the list.
@tekir/corev0.1.24
CoreMay 6, 2026
tekir buildnow defaultsprocess.env.NODE_ENVtoproductionat bundle-load time. Apps started with a rawbun ./dist/index.js(the shape PM2, Docker, and systemd typically use) no longer need an explicitNODE_ENV=productionon every command line. Runtime-set values still win, so dev-style overrides keep working. The default lands via a bracket-access banner so the bundler's compile-time fold ofprocess.env.NODE_ENVreads is unaffected.
@tekir/vitev0.1.3
FrontendMay 6, 2026
- Fix: vite middleware no longer crashes apps with
Logger not initialized. Call tekir() first.at startup. The internal vite logger now resolves the framework logger lazily, on each log call instead of once when the middleware is constructed, and falls back toconsolewhen the framework logger is not yet populated. This was visible in production bundles where the bundler's module init order put the vite middleware ahead oftekir()'s container setup, or when a duplicate copy of@tekir/coreended up in the bundle and the vite middleware saw a different module-scope_loggerthan the one tekir populated.
@tekir/corev0.1.22
CoreMay 5, 2026
- Fix: production builds with
router.registerDir,cron.registerDir, oremitter.registerDirnow reliably register every file in the target directory. The previous release silently registered nothing in some bundles, which surfaced as/api/*routes falling through to the SPA fallback in production while working fine in dev. - The fix is generic across decorators. Controllers, jobs, and listeners tagged with any framework-provided or user-defined decorator (
@Controller,@Schedule,@OnEvent, custom@Cron,@Subscribe, anything that stamps the registry metadata convention) are picked up the same way. No allowlist of decorator names; the build follows what the runtime would have picked.
@tekir/vitev0.1.2
FrontendMay 5, 2026
- Vite is now the dev gateway. It owns the user-configured
app.port; the Tekir backend moves to a free port picked automatically and Vite proxies/api(default, configurable viaproxyPaths) to it. HMR works natively because the browser connects to Vite directly. The previous architecture proxied through Tekir's HTTP fallback, which forced a hardcodedhmr.clientPort: 5173that collided with every other Vite project on the box (most visibly: navigating to a Tekir admin panel could serve a sibling project's HTML when 5173 was already taken). - All
process.cwd()references replaced with theappRootTekir injects via the new setupctx.vite.config.tsdiscovery,envDir,public/, anddist/client/paths now resolve from the project root regardless of launching cwd. Same fix removes theprocess.chdir(import.meta.dir)workaround monorepo apps used. - New
tekirDefaultsPlugininjectsrootandbuild.outDironly where the user'svite.config.tshas not set them. No path alias is defaulted on purpose, since@,~, and$libconventions vary per framework and~has special semantics in some CSS toolchains. - Setup signature is
vite(server, config, ctx)(third arg optional).ctx.configStoreis what lets the gateway rewriteapp.portbeforeserver.start()reads it;ctx.appRootis the project root fromtekir(). Older(server, config)integrations still work. - Fix: production builds no longer crash with a 500 (
EISDIR) when the browser navigates to/. The prod fallback now skips entries that resolve to a directory rather than a file, soGET /correctly falls through to the SPAindex.html. - Adds
get-port@^7as a runtime dependency.
create-tekir-appv0.1.7
Dev ToolsMay 5, 2026
- All five templates (
minimal,api,fullstack,with-vite,with-next) now scaffold withtekirCLI scripts:bun run devbecomestekir serve --dev(watch mode +NODE_ENV=development),bun run buildbecomestekir build --outdir ./dist,bun run startbecomestekir start(NODE_ENV=production).@tekir/cliis added to each template'sdependenciesso the bin shim resolves undernode_modules/.bin/tekirafterbun install. Replaces the previousbun run --watch index.ts/bun run index.ts buildpattern. tekir buildruns the entry through the in-app dispatcher, so@tekir/vite0.1.2'sonBuildhook fires and the frontend lands indist/client/alongside the backend bundle indist/index.js. Previouslytekir build(in the bin's old code path) calledBun.builddirectly without ever invoking the entry, so frontend templates that rely on the build hook would silently ship without the client output.
@tekir/corev0.1.21
CoreMay 5, 2026
tekir()auto-detectsappRootby walking the call stack to find the file that called it and using that file'sdirname. SameError.captureStackTracemechanismrouter.registerDiralready uses for caller-relative resolution. Falls back toprocess.cwd()only when no user frame is recoverable. Eliminates theprocess.chdir(import.meta.dir)workaround monorepo apps need when launched from a parent dir (turbo from repo root, pm2 from/, etc.). Frontend module resolution (createRequire) and config discovery now use the resolvedappRootinstead ofprocess.cwd()so the user's local@tekir/viteis found regardless of launch dir.- Frontend setup signature extended:
setup(server, frontendConfig, { configStore, appRoot }). The third arg is optional, so older(server, config)integrations stay drop-in compatible. The added context lets frontend middleware read and rewrite config (notablyapp.port) beforeserver.start()reads the value, which is what@tekir/vite0.1.2 uses to flip the dev architecture and own the user port as a gateway.
@tekir/cliv0.1.3
Dev ToolsMay 5, 2026
tekir buildnow routes through the entry like every other command, so the user'stekir({...})instance gets to registeronBuildhooks before the bundle runs. Insidetekir()core,argv[2] === 'build'is detected and triggersserver.build()(which fires the hooks, e.g.@tekir/vitebuilds the frontend intodist/client/) followed byBun.buildfor the backend bundle. CallingrunBuilddirectly from the bin (the previous behavior) skipped the entry entirely and silently dropped any frontend build, so apps withfrontend: { type: 'vite' }shipped a backend bundle withoutdist/client/.runEntryno longer callsprocess.exit(0)after the import resolves. Forcing the exit was racing with three legitimate flows: the canonical fire-and-forgetserver.start().catch(...)pattern (Bun.serve was getting killed mid-bind the moment import completed), in-app dispatchers that exit on their own, and any top-level async work the user awaited. The runtime exits naturally when the event loop drains in all three cases.
@tekir/corev0.1.20
CoreMay 4, 2026
- AST inliner now also folds literal-path runtime fs reads into the bundle, so apps that read small config / template files at startup ship as a single self-contained artifact and run from any working directory. Recognized shapes:
readFileSync('./x.json', 'utf-8')becomes a string literal;readFileSync('./x.bin')becomesBuffer.from('<base64>', 'base64');readFilefromfs/promisesandBun.file('./x').text()/.arrayBuffer()chains becomePromise.resolve(<literal>). Detection covers named, aliased ({ readFileSync as rfs }), namespace (* as fs), and default imports fromfs,node:fs,fs/promises, andnode:fs/promises. Eliminates the postbuild scripts, manual file copying, andprocess.cwd()-relative path probing that monorepo bundles otherwise need at boot. - Files larger than 1 MB, dynamic paths (template literals, variables), dynamic encodings, and callback-style
fs.readFileare silently skipped, leaving those calls as runtime fs lookups so the inliner never changes call semantics. The inliner is also a no-op when none of the recognized helpers appear in the source, so existing files pay zero analysis cost.
@tekir/bodyparserv0.1.3
Storage & ParsingMay 4, 2026
- **Security**:
UploadedFile.validateContent()now treats unrecognized magic bytes as outside theextnameswhitelist instead of silently allowing them. Previously a renamedmalware.exe→malware.jpgslipped through becausedetectExtname()returnednulland the mismatch check was guarded behindif (detected && ...), leavinghasErrorsfalseso the file reached storage. Strict whitelist semantics now: empty buffer →rule: 'content', message: 'Empty file'; magic bytes don't match any known signature →rule: 'content', message: 'Unrecognized file content'; detected format is not in the whitelist →rule: 'content', message: 'File content (.X) is not in allowed types: ...'; declared extension does not match the detected format →rule: 'extname'. The non-strict path (noextnamesoption) is unchanged.
@tekir/bodyparserv0.1.2
Storage & ParsingMay 4, 2026
- **Breaking**:
ctx.filesis now a method, not aMultipartFilescollection. Multi-file fields are read withctx.files(name)(returnsUploadedFile[]) instead ofctx.files.files(name). Matches AdonisJS' single-method-per-shape pattern (ctx.file()/ctx.files()/ctx.allFiles()) and removes the awkwardfiles.filesdouble-dot. TheMultipartFilesclass is still exported for advanced use; the parser still produces it internally. - All three accessors are installed on
ctxfor every request, including non-multipart ones, with a no-op fallback (ctx.file()→undefined,ctx.files()→[],ctx.allFiles()→[]). Removes the optional-chain dance from controllers, soconst avatar = ctx.file('avatar')works in any handler regardless of content-type. ctx.file(name)now returnsUploadedFile | undefined(was... | null) so the entire surface lines up onundefinedfor the absent case.
@tekir/corev0.1.19
CoreMay 4, 2026
- AST inliner now emits a per-call-site IIFE picker instead of a shared
__tekir_pickhelper. 0.1.18 wrapped the helper body innew Function("m", "<body>"), but Bun's bundler optimizer still parses the literal body and folds the call sites back tom.default ?? mbecause every call site's argument is a static namespace import whose shape is known at bundle time. A separate IIFE per call site, plus a reflection probe throughObject.prototype.hasOwnProperty.call(_m, "default"), blocks the static-shape analysis: the bundler cannot prove_mis an own-property holder fordefaultpurely from the namespace synthesis, so the body survives intact in the output. The fix has been verified on real production bundles (148hasOwnProperty.callreferences survive in a typical sevk-shaped app, controllers and cron jobs all register).
@tekir/corev0.1.18
CoreMay 4, 2026
- Hardens the AST inliner's
__tekir_pickhelper against Bun's bundle-time optimizer. 0.1.17 emitted the picker as a regular function declaration; Bun's optimizer was inlining the body into each call site and constant-folding the result down tom.default ?? m, which on a named-export controller (export class FooController, no default) collapsed back to the bare module namespace and crashedregister(...)withObject is not a constructor. The picker is now built from a string literal vianew Function("m", "<body>")so the bundler only sees the literal at build time and cannot fold the body. Function compiles once at app boot, no per-request impact.
@tekir/corev0.1.17
CoreMay 4, 2026
- AST inliner now picks the right export for
export class FooController(named export, nodefault) bundles. The previous output emitted(__tekir_inline_X.default ?? __tekir_inline_X)for every imported file, which collapsed to the namespace object when no default existed and maderegister(...arr)callnew <namespace>, producingObject is not a constructorat boot in production builds. Each rewritten registerDir/loadDir call now goes through an injected__tekir_pick(mod)helper that mirrors the runtimedefaultPick(default first, then single named export, then decorator-tagged class via__prefix/__routes/__schedules/__listeners, then first function-typed named export, then the namespace as a last resort). Build and runtime now resolve the same export shape for the same file. - Helper is inlined into the transformed source (one definition per file that has
loadDir/registerDircall sites), so the picker logic rides along inside the bundle without adding a new runtime dependency on@tekir/corefor files that did not already import it.
@tekir/corev0.1.16
CoreMay 4, 2026
- Fixes 0.1.15's caller capture in
router.registerDir. The previous version dynamically importedloadDirandcaptureCallerFileinside the registerDir method, which placed the call across anawaitboundary, so by the time the stack was inspected the user's frame was gone and Bun's only remaining frames (native:1:11) leaked through to be used as the resolution base. The bin would then warn(resolved against native)and load nothing. The fix moves both helpers to top-level static imports so the caller is captured synchronously on entry, before any await runs. captureCallerFile's stack-frame parser tightened: a frame's path must look like an absolute filesystem path (Unix/...or Windows<drive>:\...) or afile://URL, otherwise it is rejected. That blocks Bun'snative(after the:1:11suffix is stripped), Node'snode:internal/..., anonymous<anonymous>frames, and any other synthetic engine markers from being treated as user code.
@tekir/emitterv0.1.4
CommunicationMay 4, 2026
- Fixes 0.1.3's caller capture in
emitter.registerDir. Same root cause as@tekir/core0.1.16:await import('@tekir/core')ran beforecaptureCallerFile, so the user's frame was already gone by the time the stack was inspected and the warning printed(resolved against native). Static top-level imports forcaptureCallerFile/loadDirEntrieskeep the capture synchronous on registerDir entry. Pair with@tekir/core0.1.16+.
@tekir/cronv0.1.4
CommunicationMay 4, 2026
- Fixes 0.1.3's caller capture in
cron.registerDir. Same root cause as@tekir/core0.1.16:await import('@tekir/core')ran beforecaptureCallerFile, so the user's frame was already gone by the time the stack was inspected and the warning printed(resolved against native). Static top-level imports forcaptureCallerFile/loadDirEntrieskeep the capture synchronous on registerDir entry. Pair with@tekir/core0.1.16+.
@tekir/corev0.1.15
CoreMay 4, 2026
- **Breaking**:
router.registerDir(...)resolves a relative path against the caller's own directory, notprocess.cwd(). Aligns runtime resolution with what the AST inliner already does at build time, so the standard monorepo dev pattern (cd <root> && tekir serve --dev --entry api/index.ts) works without rewriting paths:await router.registerDir('./controllers')fromapi/index.tsresolves toapi/controllersregardless of the cwd. Base directory captured viaError.captureStackTrace. Passoptions.from = process.cwd()to keep the old cwd-relative behavior for a specific call site. - New
LoadDirOptions.fromaccepts afile://URL or absolute path (typicallyimport.meta.url) to set the resolution base explicitly when the auto-captured caller is not the right answer. captureCallerFile(boundary)exported from@tekir/coreso other registries (cron, emitter, custom) can apply the same caller-relative resolution. Both Bun and Node honorError.captureStackTrace(obj, fn); the helper handles the format differences (Bun raw paths vs. Nodefile://URLs) internally.
@tekir/emitterv0.1.3
CommunicationMay 4, 2026
- **Breaking**:
emitter.registerDir(...)now resolves a relative path against the caller's own directory, notprocess.cwd(). Matches the AST inliner's build-time behavior soawait emitter.registerDir('./listeners')fromapi/index.tslands atapi/listenersregardless of cwd, and thecd <root> && tekir serve --dev --entry api/index.tsmonorepo dev pattern works as-is. Passoptions.from = process.cwd()for the old cwd-relative behavior on a specific call site.
@tekir/cronv0.1.3
CommunicationMay 4, 2026
- **Breaking**:
cron.registerDir(...)now resolves a relative path against the caller's own directory, notprocess.cwd(). Matches the AST inliner's build-time behavior soawait cron.registerDir('./jobs')fromapi/index.tslands atapi/jobsregardless of cwd, and thecd <root> && tekir serve --dev --entry api/index.tsmonorepo dev pattern works as-is. Passoptions.from = process.cwd()for the old cwd-relative behavior on a specific call site.
@tekir/cliv0.1.2
Dev ToolsMay 4, 2026
- Bin shebang now routes through Bun (
#!/usr/bin/env bun). Bun is position-strict on its own--env-fileflag, so--env-file=...tokens after the script path pass through to the bin's argv where the in-bin loader filters missing files with a warning and keeps the rest. Thetekirshim created bybun add -g @tekir/cli(ornpm i -g) regenerates with this hint on upgrade, so existing scripts that chain--env-fileflags work unchanged. --envfile(no hyphen) added as a Node-host-safe alias of--env-file. The hyphenated form is intercepted by Node's runtime before the bin runs and hard-errors on a missing file; the un-hyphenated form is unrecognized by Node's CLI parser and is forwarded to the script's argv unchanged. Useful when invoking the bin directly under Node (node node_modules/@tekir/cli/bin/tekir.mjs --envfile=path serve).- Env files declared in
package.jsonunder"tekir": { "envFiles": ["...", "..."] }are loaded automatically before the entry runs. Recommended for keeping per-package.envchains out of every script. Paths in JSON load first, then any CLI--env-file/--envfileflags layer on top with later-wins precedence; shell-provided env always wins both.
@tekir/corev0.1.14
CoreMay 4, 2026
runBuild,parseBuildArgs, andBuildArgsErrorare now public exports of@tekir/core, so the new@tekir/clipackage and any user drivingBun.buildprogrammatically share one implementation. Same flag surface as the in-processbun run index.ts builddispatcher, plus optionalextraPlugins/extraExternals/loggeroverrides on the JS API for advanced setups.- Build flag parser rewritten on top of
node:util.parseArgs(Node stdlib, also available in Bun) so unknown flags, missing values, and bad--define/--sourcemap/--format/--envvalues surface as clear errors instead of being silently dropped. - Forwarded flags expanded to match
bun buildmore completely:--format esm|cjs|iife,--banner,--footer,--drop(multi),--env inline|disable|<PREFIX>*,--public-path,--no-bundle,--keep-names, granular--minify-syntax / --minify-whitespace / --minify-identifiers,--entry-naming,--chunk-naming, plus--metafile <path>and--metafile-md <path>for bundle analysis output. Granular minify flags emit Bun's object form so users can pick a subset (e.g.--minify-syntaxalone). - Refused with a clear error when invoked from inside a compiled binary. Detection is hybrid:
Bun.mainvirtual-fs marker (~BUN) plusprocess.execPathbasename check, two independent signals so a single Bun version drift does not break detection.
@tekir/corev0.1.13
CoreMay 4, 2026
- Pairs with the new
@tekir/clipackage. The CLI'stekir buildcommand importscreateInlinerPluginfrom@tekir/coreand runsBun.builddirectly without touching the entry file, so apps with side-effect-heavy module loads (Redis subscribers, message-bus clients, fs watchers) stay quiet during build. Drop-in replacement forbun build api/index.ts --outdir ./dist [...]once you install@tekir/cli. - Default
loadDir/registerDirpicker handlesexport class FooController(named export, no default) automatically. The picker triesmod.defaultfirst, falls through to the single named export, prefers a decorator-tagged class (__prefix/__routes/__schedules/__listeners) when there are multiple named exports, then the first function-typed export, and finally returns the namespace itself. Apps no longer need a custompick: m => m.default ?? Object.values(m).find(...)for every registry call. registerDirwarnings now name the source file:[router.registerDir] core/controllers/typo.ts: skipped (unrecognized export shape: object). Same wording oncron.registerDirandemitter.registerDir.loadDirEntries(path, options)is exported alongsideloadDirfor callers that need the file path next to every picked export.registerDir(router, cron, emitter) prints a single warning when it loaded zero modules, with a hint pointing at the inliner plugin. Replaces the previous silent failure where a misconfigured production bundle would just have no controllers/jobs/listeners with no log line explaining why.createInlinerPluginis exported from@tekir/coreso plainbun build --outdir ./distbundles (without--compile) can pick up the same inlining:Bun.build({ plugins: [await createInlinerPlugin()] }). Without it, runtimeregisterDircalls in those bundles can't see the source files and silently load nothing.bun run index.ts build --outdir ./distnow runs a plain Bun bundle through the tekir CLI (no--compilerequired). The inliner plugin is auto-injected, soloadDir/registerDircalls are still followed by the bundler, and the existing--target/--minify/--sourcemap/--external/--define/--plugin/--splittingflags are all forwarded. CLI-only build setups can keepawait router.registerDir('./controllers')instead of writing aBun.build({...})script.
@tekir/emitterv0.1.2
CommunicationMay 4, 2026
registerDirwarning now names the source file:[emitter.registerDir] core/listeners/typo.ts: skipped (unrecognized export shape: object). Replaces a genericSkipping ...log line that did not say which file dropped out.- Single
No modules loadedwarning with an inliner hint whenregisterDirmatches zero modules. Replaces the previous silent failure where a misconfigured production bundle would just have no listeners attached with no log line explaining why.
@tekir/cronv0.1.2
CommunicationMay 4, 2026
registerDirwarning now names the source file:[cron.registerDir] core/jobs/typo.ts: skipped (unrecognized export shape: object). Replaces a genericSkipping ...log line that did not say which file dropped out.- Single
No modules loadedwarning with an inliner hint whenregisterDirmatches zero modules. Replaces the previous silent failure where a misconfigured production bundle would just have no jobs attached with no log line explaining why.
@tekir/corev0.1.12
CoreMay 4, 2026
loadDir(path)returns the default export of every file in a directory, so registries like controllers, cron jobs, listeners, and commands no longer need a 25-line import block. Pass a custompickcallback to grab a named export,match/ignoreregexes to filter, andrecursive: trueto walk subdirectories. Works on Bun and Node by routing through@tekir/runtime'sreadDirRecursive, which usesBun.Globon Bun for the directory scan and falls through tonode:fs/promiseson Node.router.registerDir(path)wires up a whole controllers folder in one line. It auto-detects three export shapes per file: decorator classes (the@Controller+@Get/@Post/...pattern, registered viarouter.register), functional registrars (export default (router) => { ... }, invoked with the router), and classes with aregister(router)method (a fresh instance is constructed and itsregisteris called). Files whose default export does not match any pattern are skipped with aconsole.warnso misconfigured exports surface during boot.bun build --compilenow bundles the files referenced byloadDir('path')and*.registerDir('path')calls. The compile pipeline auto-injects an AST-based inliner (powered byoxc-parser) that finds literal-string folder calls, lists the directory at build time, and replaces each call with explicit static imports so Bun's bundler can follow them. Comments, string literals, computed-arg calls, and unrelated identifiers are left alone.oxc-parseris an optional peer dependency; install it withbun add -d oxc-parserto opt in. When the parser is missing, compile prints a one-line install hint so the silent failure mode does not bite.
@tekir/runtimev0.1.3
CoreMay 3, 2026
readDir(path)andreadDirRecursive(path, options)list directory contents across runtimes. The recursive walker usesBun.Globon Bun and falls back to a depth-firstnode:fs/promiseswalk on Node. Skipsnode_modules,.git, and dotfiles by default; passextensionsto filter by suffix andignoreto widen the skip list.
@tekir/corev0.1.11
CoreMay 3, 2026
ctx.$responseHeadersis the new way for middleware to attach response headers. Anything written here lands on the outgoing response right before it goes on the wire, on success, error, and framework-handled-error paths alike. CORS, request id, server timing, and any other header-attaching middleware now work from any position in the chain instead of breaking silently when an error handler sat between them and the route.- Unmatched paths now run the global middleware chain before responding 404, so
cors(), request loggers, and other hooks observe the request and stamp their headers on the response. Previously a stray request to/non-existentskipped the chain entirely and the browser saw a generic CORS error on what was actually a 404. ctx.requestexposespath,host,hostname,protocol,origin, andcompleteUrlas direct properties. Routes that touch any of these get a single upfront URL parse; routes that only readrequest.url/request.methodskip the parse entirely.Varyis appended (not overwritten) when both a handler and middleware set it, so aVary: Accept-Encodingfrom the cache layer keeps living next to theOrigintoken CORS adds.
@tekir/emitterv0.1.1
CommunicationMay 3, 2026
emitter.registerDir(path)loads every file in a folder and binds whatever each module exports as a listener: decorator classes (the@OnEventpattern with__listenersmetadata) go throughemitter.register, functional registrars (export default (emitter) => emitter.on(...)) are invoked with the emitter, and classes with aregister(emitter)method are constructed and called.
@tekir/cronv0.1.1
CommunicationMay 3, 2026
cron.registerDir(path)loads every file in a folder and registers whatever each module exports as a job: decorator classes (the@Schedule('* * * * *')pattern with__schedulesmetadata) go throughcron.register, functional registrars (export default async (cron) => cron.add(...)) are invoked with the manager, and classes with aregister(cron)method are constructed and called.
@tekir/corev0.1.10
CoreMay 3, 2026
- Server idle timeout default is now
120seconds, comfortably above typical SSE keepalive intervals (15-30 s) and long-poll cycles, while still reaping stuck or slowloris-style connections. Apps that need genuinely long-lived idle connections can passidleTimeout: 0to disable the timeout entirely; any other finite value is honored.
@tekir/corsv0.1.3
SecurityMay 3, 2026
- When the chain throws and no inner middleware set
ctx.$resultalong the way, the middleware no longer coerces the missing result to a 204. The previous behavior won the race against an outer error handler that returns the real error response (because the framework only adopts a returned response whenctx.$resultis still undefined), so the client could see a CORS-OK 204 instead of a 401/500. Now the throw simply propagates and the outer handler builds the actual response. When an inner middleware did setctx.$resultbefore re-throwing, CORS headers still merge onto it as before.
@tekir/corev0.1.9
CoreMay 3, 2026
- Long-lived streams (Server-Sent Events, long-polling, slow file downloads) no longer get cut off mid-flight. The server's idle timeout default is configurable; set
app.idleTimeoutin your config (or passidleTimeouttoserver.configure({...})) to override the framework default.
@tekir/corsv0.1.2
SecurityMay 3, 2026
- Error responses now carry CORS headers regardless of middleware order. The middleware wraps
await next()in a try/catch, runs the header merge whether the chain resolved or threw, and re-throws so outer error handlers and loggers still see the original error. Without this, puttingcors()ahead of an error-handling middleware silently droppedAccess-Control-Allow-Originfrom every error response, and the browser blocked the response with a generic CORS error even though the API responded correctly.
@tekir/corev0.1.8
CoreMay 3, 2026
- **Breaking**:
tekir()no longer scans<root>/env.ts,<root>/src/env.ts,<root>/config/,<root>/start/, or<root>/commands/automatically. PassenvFile,configDir, andstartDirexplicitly to keep a file-based layout:await tekir({ envFile: 'env.ts', configDir: 'config', startDir: 'start' }). With nothing set, tekir loads no files; everything is inline. This stops the framework from running unrelated root scripts namedenv.ts(e.g. interactive.envsetup CLIs in monorepos) when an app boots. - OPTIONS preflight on a path that registered only specific methods (e.g.
POST /login) now reaches the global middleware chain. Before, Bun.serve returned 405 andcors()never saw the preflight. The router now synthesizes a 204 OPTIONS handler at every path that did not register one explicitly, so middleware can intercept and short-circuit with the proper preflight response.
@tekir/corsv0.1.1
SecurityMay 3, 2026
- Actual responses (not just preflight) now carry CORS headers. The middleware previously stashed
Access-Control-*values onctx.store.__corsHeadersfor downstream code to apply, but nothing in tekir read them back, so browsers blocked every cross-origin POST/GET even when preflight succeeded. The middleware now injects the headers directly onto the response after the handler runs. - Routes that return a raw
Responseobject (SSE streams, file downloads, custom payloads) now get CORS headers too. The middleware coerces whatever the handler returned into aResponseand merges the headers in, preserving the original status, body stream, and any handler-set headers. Vary: Originis appended on every CORS-injected response so HTTP caches do not serve a response built for one origin to a request from another. When the handler already setVary,Originis added to the existing list instead of overwriting it.
create-tekir-appv0.1.6
Dev ToolsMay 3, 2026
- The
apiandfullstacktemplates now wiretekir()with explicitenvFile,configDir, andstartDirpaths, matching the loader contract in@tekir/core. New projects scaffold and boot end-to-end without any extra setup.
@tekir/testingv0.1.6
Dev ToolsMay 3, 2026
- Adapts to
@tekir/core0.1.8's explicit autoload paths.createTestApp()now auto-detectsenv.ts,config/, andstart/under the app root and forwards them totekir(), so existing test suites continue to work with no changes. PassenvFile: false,configDir: false, orstartDir: falseto opt out of any of them, or pass a custom path string to override.
@tekir/testingv0.1.5
Dev ToolsMay 3, 2026
- Tests now run on Node as well as Bun. The package detects the runtime at load time and re-exports
bun:teston Bun (built-in, zero install) orviteston Node (peer dependency:bun add -d vitest). The exported names stay the same (test,describe,expect,beforeAll/afterAll/beforeEach/afterEach,mock,spyOn,jest) and the bun-style helpers are mapped onto vitest'svi.*equivalents so handler code stays identical.
@tekir/corev0.1.7
CoreMay 2, 2026
request.headers()no longer requires theDOM.Iterablelib in the consumer's tsconfig. Some app tsconfigs only pull inDOM, which made the previousHeaders.entries()call fail to type-check at the consumer side. Switched toHeaders.forEach, available in plainDOM.
@tekir/runtimev0.1.2
CoreMay 2, 2026
- Header conversion no longer requires the
DOM.Iterablelib in the consumer's tsconfig. Replaced theHeaders.entries()call in the Node.js server adapter withHeaders.forEach, which is part of plainDOM.
@tekir/corev0.1.6
CoreMay 2, 2026
- Body parser failures no longer crash routes with a generic 500. When the declared
Content-Typedoes not match the actual payload (empty body withapplication/json, malformed urlencoded, etc.) the parse error is captured onctx.bodyErrorso handlers and middleware can respond with a real 400. ctx.response.status(code).json(...)now actually carries the status across the chain. The compiled fast path used to silently fall back to 200; routes that chain a status setter automatically switch to a stateful response object.- Middleware return values are picked up automatically. Returning a
Response(or anything else) from a middleware sets it as the route result, soreturn response.unauthorized()works the way Express, Koa, and Hono users expect without rememberingctx.$result =.
@tekir/testingv0.1.4
Dev ToolsMay 2, 2026
client.options(path)for testing CORS preflight handlers and any otherOPTIONSroute. Mirrors the existingget/post/etc. surface and is also available on thewithHeader/withToken/withBasicAuthproxies.- Streaming endpoints no longer hang assertions. Pass
{ stream: true }to skip the body drain on SSE, long-poll, and download routes; status and headers come back immediately, and the rawResponseis exposed onres.rawif you want to read the stream yourself. res.assertError({ message, statusCode })transparently unwraps the framework's{ error: { ... } }envelope, so error assertions work the same whether the route returns a wrappedHttpExceptionpayload or a plain{ message, statusCode }body.
@tekir/corev0.1.5
CoreApril 30, 2026
tekir()accepts an inlineroutescallback so single-file apps can register routes without destructuring the router first. The callback runs after providers boot, soservice()resolves to live instances inside it, and the methods passed in are pre-bound, so destructuring({ get, post })works without losingthis.
@tekir/testingv0.1.3
Dev ToolsApril 29, 2026
- Renamed
apiClient(baseUrl)toclient(baseUrl). Update imports:import { client } from '@tekir/testing'.
@tekir/swaggerv0.1.1
Dev ToolsApril 29, 2026
- Optional HTTP Basic auth on the Swagger UI and JSON spec. Pass
auth: { username, password, realm? }to gate/docs,/docs/, and/docs/json. Constant-time credential comparison; sends a 401 withWWW-Authenticate: Basic realm="docs"when credentials are missing or wrong.
@tekir/cachev0.1.6
DatabaseApril 29, 2026
RedisCacheStorenow accepts any redis-like client without requiring a matchingsend()signature. The interface droppedsendandconnectedfields so@tekir/redis,ioredis, andnode-redisclients all type-check directly without casts.
@tekir/sessionv0.1.2
DatabaseApril 29, 2026
- Memory and database session stores type-check cleanly without
@tekir/redisinstalled. The redis store loads only when the redis driver is selected.
@tekir/cachev0.1.5
DatabaseApril 29, 2026
RedisCacheStorenow accepts both@tekir/redis(returnsboolean) and node-redis / ioredis (returnnumber) clients without a TypeScript cast. Existence checks normalise both shapes at the call site.
@tekir/corev0.1.4
CoreApril 29, 2026
response.redirect.back(fallback?)sends users back to the page they came from. Reads theRefererheader and restricts it to same-origin URLs, so attackers cannot bounce users off-site through a crafted referer. Falls back to the provided URL (or/) when the referer is missing or cross-origin.
@tekir/cachev0.1.4
DatabaseApril 29, 2026
- Memory and database cache setups now type-check cleanly without
@tekir/redisinstalled. The redis store is loaded only when the redis driver is used.
@tekir/authv0.1.4
SecurityApril 29, 2026
- Apps that augment
TekirAuthUserwith their own model shape (for exampleextends ModelFields<User>) no longer trip on a baseidtype conflict. The augmentation hook is now field-free so any user model fits.
@tekir/queuev0.1.1
CommunicationApril 29, 2026
- Memory and database queue setups now type-check cleanly without
@tekir/redisinstalled. The redis backend is loaded only when the redis driver is used.
@tekir/cachev0.1.3
DatabaseApril 29, 2026
- Added
cache()middleware that caches full HTTP responses by URL with TTL, conditional revalidation viaIf-None-Match, andVaryheader support. Skips mutating methods, error responses, andno-storerequests by default. - Added
setDefaultCacheStore()soCacheProviderauto-wires the middleware. Routes can usecache({ ttl: 60 })once the provider is registered, nostoreoption needed.
@tekir/http-decoratorsv0.1.1
DecoratorsApril 29, 2026
- Added the
@Cachedecorator. It is a thin wrapper around@Middleware([cache(opts)])from@tekir/cache, so controller methods can opt into HTTP response caching with a single line.
@tekir/corev0.1.3
CoreApril 27, 2026
- Added a
NOTICE.mdand inline attribution comments crediting Elysia (MIT, Copyright 2022 saltyAom) for the implementation details that were adapted from its source: the AOT body parser'scharCodeAt(12)content-type switch, the arrow-handler source separator, the query parser's bit-flag layout, the SSE helper, and thebeforeHandle/afterHandlelifecycle hooks.
create-tekir-appv0.1.5
Dev ToolsApril 27, 2026
request_loggermiddleware now reads the response status viactx.response.getStatusCode()so it type-checks under strict TypeScript.AuthControllerreads validated bodies throughRegisterBody/LoginBodytypes exported fromvalidations/auth.ts(z.infer<typeof schema>), so destructured fields are typed instead ofunknown.
create-tekir-appv0.1.4
Dev ToolsApril 27, 2026
- Auth wiring simplified: the kernel no longer needs an explicit
silentAuth()/attachAuth()middleware.AuthProviderregisters its ownctx.authinitializer. Public routes like/registerand/loginjust callauth.login(user)directly. AuthControllernow uses the natural destructured signature({ body, response, auth }) => ...and works after a login swap (the framework mutatesctx.authin place).- Logout endpoint switched to
auth.logout()(no-op for JWT, since JWT is stateless); the comment in the controller points the user atauth.revokeAll()for revocable token guards. - Test files in templates renamed from
auth.test.tstoauth.test.ts.templateso the framework's own test runner stops trying to execute them in-place. The installer still strips.templatewhen scaffolding.
@tekir/authv0.1.3
SecurityApril 27, 2026
AuthProvidernow wires up a lightweightctx.authinitializer onto the router automatically. Apps no longer have to add a global middleware instart/kernel.tsfor handlers like/registerto callauth.login(...).auth.login()andauth.logout()mutatectx.authin place instead of replacing the object, so destructured handlers like({ auth }) => { await auth.login(user); auth.generate() }keep working after a login swap.- New
attachAuth()middleware exported for apps that prefer wiring it manually instead of relying on the provider.
@tekir/testingv0.1.2
Dev ToolsApril 27, 2026
- The in-memory sqlite override now happens before
tekir()boots, so the database provider opens:memory:from the start. Previously the override mutated config after the connection was already open, which left tests pointing at the dev sqlite file. createTestApp()reads the app'sconfig/database.{ts,js,mjs}(when present) and clones it with sqlite paths swapped to:memory:, preserving any other connections and provider-specific options.
@tekir/cachev0.1.2
DatabaseApril 27, 2026
- Split
CacheConfig(loose, whatconfig/cache.tsexports) from a newCacheManagerOptions(strict, what theCacheclass accepts). The provider expands driver configs before instantiating, so directnew Cache({...})callers and config-driven setups both type-check.
@tekir/testingv0.1.1
Dev ToolsApril 27, 2026
createTestApp()now picks an in-memory sqlite by default and runs pending migrations fromdatabase/migrationsautomatically. Tests no longer need a manual setup file withMigrationRunnerboilerplate.appRootis optional and defaults toprocess.cwd(). Pass a string (typicallyimport.meta.dir) only when tests live in a nested folder.- New options on
createTestApp:migrate(force-on/off auto-migration) andinMemoryDb(opt out of the sqlite override).
@tekir/authv0.1.2
SecurityApril 27, 2026
- Guard configs accept a
modelshortcut (any class with a staticfind(id)) and skip the resolver boilerplate. The shipped templates now passmodel: Userdirectly. findUserconfig field renamed toresolveto reflect that the resolver works for any auth subject, not just users (members, accounts, admins, …).- New
AuthModeltype exported for typing custom resolver shortcuts.
@tekir/corev0.1.2
CoreApril 27, 2026
AppConfiginterface added soconfig/app.tscan be authored withsatisfies AppConfigfor autocomplete on the framework-known fields without losing extensibility.- Service providers can now expose CLI commands via a
static commands = [...]array. Registered providers contribute their commands automatically, so apps no longer need astart/commands.tsto surface things likemigrateorseed.
@tekir/cachev0.1.1
DatabaseApril 27, 2026
CacheConfig.storesnow accepts driver-config objects ({ driver: 'memory' }) alongsideCacheStoreinstances, so apps can declare stores inconfig/cache.tswithout importing store classes.
@tekir/dbv0.1.1
DatabaseApril 27, 2026
static hooks = { beforeCreate: [(user: User) => ...] }on a subclass now type-checks. Previously the hook callback's typed parameter clashed with the base class's stricterunknownsignature.DatabaseProvidernow auto-exposes its migration commands (migrate,migrate:rollback,migrate:status,migrate:fresh, etc.). Apps that register the provider get the commands wired intobun run index.ts <command>without listing them instart/commands.ts.
create-tekir-appv0.1.3
Dev ToolsApril 27, 2026
apiandfullstacktemplates now declare every package they actually import (@tekir/bodyparser,@tekir/cron,@tekir/drive,@tekir/emitter,@tekir/notification). Fresh scaffolds no longer surfaceCannot find moduleerrors inservices.ts.- All
start/*.tsfiles cleaned up: broken imports for non-existent listeners, schedules, controllers, and middleware were removed. Templates boot end-to-end on the firstbun run dev. AuthControlleradded withPOST /api/auth/register,POST /api/auth/login,POST /api/auth/logout, andGET /api/auth/me. Validation schemas live undervalidations/, mapped via#validations/*import alias and a matching tsconfig path.- Database setup moved from
db.exec(Model.createSQL)to a real migration pipeline:database/migrations/with timestamped files, run viabun run index.ts migrate. Demo migrations create theusersandauth_tokenstables. - Tests added:
tests/auth.test.tscovers register/login/logout/me end-to-end. Backed by@tekir/testing's in-memory sqlite + auto-migration so they're hermetic. request_loggermiddleware ships out of the box and is wired into the kernel.- Generated config files use
satisfies(AppConfig,AuthConfig,CacheConfig,CorsConfig,DatabaseConfig,HashConfig,LoggerConfig) for autocomplete without losing literal-type narrowing. - Auth config now passes
model: Userinstead of afindUserarrow, removing per-app boilerplate. - Health controller no longer leaks server time (
new Date().toISOString()removed from the response). - Every template ships a
.gitignorecoveringnode_modules,.env, build artifacts, and sqlite files. zodis declared as a dependency where templates use it, and@tekir/dbmigration commands are auto-registered throughDatabaseProvider.commandsso no manualstart/commands.tsis needed.
create-tekir-appv0.1.2
Dev ToolsApril 27, 2026
- Every template now ships an
eslint.config.tswith the required dev dependencies (eslint,@eslint/js,globals,typescript-eslint) andlint/lint:fixscripts wired up. with-vitetemplate upgraded to Vite 7.
create-tekir-appv0.1.1
Dev ToolsApril 27, 2026
- Dropped the misleading
awaitbeforestart(...)in every template (start()is sync). with-nexttemplate now scaffolds a Next.js 16 project. Cleaned upnext.config.tsandtsconfig.jsonso a fresh scaffold runs without warnings on first boot.- Sqlite-backed templates with
path: './database/app.sqlite'boot cleanly on a fresh project even without a pre-existingdatabase/directory.
@tekir/corev0.1.1
CoreApril 27, 2026
bun run index.ts build --compilenow exposes the full Bun compile surface:--define KEY=VAL,--exec-argv,--asset-naming,--splitting --outdir,--plugin, plus autoload toggles for tsconfig, package.json,.env, and bunfig.frontend: { type: 'vite' }apps can now be compiled into a single executable.- Compiled builds auto-clean their intermediate
dist/<buildDir>after writing the binary. Pass--keep-artifactsto inspect the build output.
@tekir/runtimev0.1.1
CoreApril 27, 2026
openDatabase()now creates missing parent directories automatically. A path like'./database/app.sqlite'works on a fresh project even when nodatabase/folder exists yet.
@tekir/configv0.1.1
UtilitiesApril 27, 2026
- Now installs alongside
@tekir/runtime0.1.1 so the SQLite auto-mkdir fix reaches downstream apps.
@tekir/vitev0.1.1
FrontendApril 27, 2026
- Single-executable support via
bun run index.ts build --compile. Vite output is bundled into the binary and served at runtime with nonode_moduleson disk. - Auto-discovers your
vite.config.ts(or.js,.mts,.mjs) in the project root, so plugins like@vitejs/plugin-react,@vitejs/plugin-vue, and the Svelte and Solid plugins are picked up correctly in both dev and production builds. - Inlines only
VITE_*env vars into the client bundle so secrets stay server-side.
@tekir/nextv0.1.1
FrontendApril 27, 2026
- Now supports Next.js 16. Peer range is
>=14.0.0 <17.0.0.
v0.1.0Initial ReleaseApril 1, 2026
- Core framework with router, DI container, and kernel lifecycle
- ActiveRecord ORM with SQLite, PostgreSQL, and MySQL support
- Fluent query builder with joins, aggregates, and pagination
- File-based migration system with Schema Builder
- Guard-based authentication (JWT, session, database tokens)
- Policy-based authorization system
- Request validation with Zod integration
- Email via SMTP, Sevk, Resend, Mailgun, and SES
- Background job queues with retry and delay
- Multi-channel notifications (mail, database, push)
- Typed event emitter with wildcard support
- Cron job scheduler with overlap safety
- Multi-driver caching (memory, Redis, database)
- Session management with flash messages
- File storage with local, S3, R2, and GCS drivers
- Structured logging with Datadog, Loki, and Pino transports
- CLI framework with args, flags, prompts, and terminal UI
- Engine-agnostic views (Eta, EJS, Pug, React)
- CORS, CSRF, rate limiting, and security headers
- Password hashing (bcrypt, argon2, scrypt) and encryption
- OpenAPI / Swagger documentation
- HTTP testing utilities with chainable assertions
- Internationalization with JSON locale files
- Health check endpoints
- Redis client with pub/sub and pipeline support
- Optional decorator packages (HTTP, DB, cron, events, Swagger)
- Generic decorator creation toolkit
- Vite and Next.js frontend integration
- 45 first-party packages, 5,000+ tests