Change Log
4.2.5 June 15, 2026
Patch release: warlock add notifications now scaffolds the in-app read/dismiss HTTP surface — routes.ts + a notifications controller (list / unread-count / mark-read / mark-all-read / clear / delete), gated by authMiddleware and recipient-scoped via inApp. The family is re-published in lockstep; no other functional changes.
- Added
warlock add notificationsnow scaffolds the in-app read/dismiss HTTP surface —routes.ts+ anotifications.controller.ts(list / unread-count / mark-read / mark-all-read / clear / delete), gated byauthMiddlewareand recipient-scoped viainApp. Pulls@warlock.js/auth.
4.2.4 June 15, 2026
Patch release: corrects the worker-loader path in @warlock.js/core's build entry points — a wrong path in 4.2.3 left the worker entry broken. The family is re-published in lockstep; no other functional changes.
- Fixed Fix the worker-loader path in the build entry points — a wrong path in 4.2.3 left the worker entry broken (and blocked the 4.2.3 publish for some packages).
4.2.3 June 15, 2026
Patch release: adds the worker scripts as @warlock.js/core build entry points so they ship in the published package. A wrong entry-point path in this build blocked the npm publish for some packages — corrected in 4.2.4.
- Fixed Add the worker scripts as build entry points so they ship in the published package.
4.2.2 June 15, 2026
Patch release: adds cli/start to @warlock.js/core's build entry points so the warlock CLI entry ships in the published package. The family is re-published in lockstep; no other functional changes.
- Fixed Add
cli/startto the build entry points so thewarlockCLI entry ships in the published package.
4.2.1 June 15, 2026
Patch release: @warlock.js/core and @warlock.js/cascade now ship their bin folder, so the warlock and cascade CLIs work from the published package — they were omitted from the 4.2.0 build. The rest of the family is re-published at 4.2.1 to keep the lockstep version line; no other functional changes.
- Fixed Ship the
binfolder so thewarlockCLI works from the published package — it was omitted from the 4.2.0 build.
- Fixed Ship the
binfolder so thecascadeCLI works from the published package — it was omitted from the 4.2.0 build.
4.2.0 June 15, 2026
A security and correctness overhaul of @warlock.js/auth — brute-force login throttling, atomic refresh-token rotation with replay detection, CSPRNG signing secrets, a corrected default token lifetime, and overridable token storage for multi-tenant schemas. The jwt config block is superseded by accessToken / refreshToken. Also introduces @warlock.js/notifications — multi-channel notifications (mail, in-app, custom channels) with preferences, rate limits, idempotency, and a herald-backed async queue. Plus @warlock.js/access — authorization (RBAC + ABAC): permission checks, attribute-based policies, role management, and a pluggable resolver.
- New Shipped Warlock.js Notifications Package.
- New Shipped Warlock.js Access Package.
- Added
loginThrottleMiddleware— failure-aware brute-force / credential-stuffing protection that counts only failed logins, resets on a successful one, locks per-account and per-IP, and rejects pre-controller with429(cache-backed, fails open on a cache outage). AddsAuthErrorCodes.TooManyAttempts(EC004). - Added
accessToken/refreshTokenconfiguration blocks, making a separate refresh-token secret first-class. - Added Overridable token storage — register a custom model under
config.auth.accessToken.model/config.auth.refreshToken.modeland.extend()the exportedaccessTokenSchema/refreshTokenSchemato add columns (e.g. a multi-tenantorganization_id). Models own issuance throughissue()and expose named statics, so the service hard-codes no column names. - Added
tokenType(access|refresh) claim, stamped on issue and verified on read, so an access token can no longer be presented as a refresh token. - Added
expires_aton access tokens;warlock auth.cleanupnow purges expired access tokens as well as refresh tokens. - Fixed Default access-token lifetime was ~3.6 seconds (a numeric
expiresIninterpreted as milliseconds) and is now 1 hour. - Fixed Targeted revocation queried
userIdinstead of theuser_idcolumn, so logout and refresh-token removal threw on Postgres and silently no-oped on MongoDB. The service now routes every token query through named model statics, so no column name is hard-coded. - Fixed Token deletions were fire-and-forget inside
Promise<void>methods (false success for callers, uncatchable rejections) and are now awaited. - Fixed The route middleware matched on
userTypeinstead of theuser_typecolumn. - Fixed
revokeAllTokens/revokeTokenFamilyreported an empty set — a re-query onrevoked_at: nullafter the update matched nothing — so thetoken.revoked/token.familyRevokedevents never fired. The revoked rows are now captured before revocation. - Fixed A throwing synchronous auth-event listener no longer turns a completed login into a
500. - Deprecated The
auth.jwt.*configuration block (jwt: { secret, expiresIn, refresh }). UseaccessToken/refreshTokeninstead — the legacy shape is still read and mapped forward with a one-time deprecation warning. - Removed Unread
access_tokenscolumnsis_activeandlast_access. - Removed The unused
auth.password.saltconfiguration key. - Security
warlock jwt.generatenow derivesJWT_SECRET/JWT_REFRESH_SECRETfrom a CSPRNG (Random.token) instead ofMath.random()-backedRandom.string. - Security Refresh-token rotation is atomic: a guarded conditional
UPDATEmeans two concurrent rotations of the same token can never both succeed, and a replayed token revokes its entire family.
- Added
log.flush()— awaitable async counterpart toflushSync(). Drains every channel that implementsflush()viaPromise.allSettledwith per-channel isolation, so one channel's failure can't break shutdown.FileLog/JSONFileLogimplement it;ConsoleLogwrites synchronously and doesn't need it. - Added
SentryLogchannel — forwards entries to Sentry.eventLevels(fatal/error/warnby default) become events (captureExceptionforErrormessages,captureMessageotherwise); every other level becomes a breadcrumb.module/actionare tags,contextis a structured Sentry context.@sentry/nodeis an optional peer, lazily imported — pass an existingclientoroptions. - Added
log.fatal()+fatallog level — ranked strictly aboveerrorfor unrecoverable failures (failed bootstrap,uncaughtException). Does not auto-flush or exit; caller decides. - Added
ConsoleLogrendersfatalwith a☠icon on a bright-red background and bold red-bright message, distinct fromerror's✗. - Changed
captureAnyUnhandledRejection()now escalatesuncaughtExceptiontolog.fatal(waslog.error). Node terminates the process by default, so it's semantically fatal — makes "page only on fatal" alerting clean.unhandledRejectionstays aterror. - Changed
LoggingData.typeis now typed asLogLevel(was a duplicated inline union — code-standards cleanup). - Changed
LogContractand theLogChannelbase now expose an optionalflush?()alongside the existingflushSync?(). - Fixed
@sentry/nodeis now referenced only via local minimal types + an indirect dynamic import, so source-served consumers (the package'smain→./src/index.ts) no longer get aTS2307: Cannot find module '@sentry/node'when they (correctly) don't install the optional peer. Proven by pruning the SDK and running the full suite +tsc --noEmitclean.
- Changed MongoDB and PostgreSQL drivers now log a failed initial
connect()atlog.fatal(waslog.error). Boot-time database connection failures are unrecoverable in every realistic Warlock use case (app boot, CLI migrations, workers) —fatalmakes "page on fatal only" alerting clean. Per-query failures,createDatabase/dropDatabaselifecycle errors, and disconnect failures stay aterror. - Fixed PostgreSQL
increment/decrement(and the*Manyvariants) bound the amount parameter as$1, which collided with the first filter placeholder (SET n = n + $1 WHERE id = $1) — the filter value bound into the amount slot, so every filtered counter update wrote the wrong number. The amount now binds after the filter params.
- Fixed No-argument tools (declared without an
inputschema) no longer crash on invocation. A schemaless tool threwCannot read properties of undefined (reading '~standard');tool.invokenow skips validation when no schema is present and passes the raw input straight to the handler.
- Added Opt-in
promptCachingflag on the model config. When enabled, the tool definitions are marked withcache_control: { type: "ephemeral" }, so multi-trip agents reuse the static tool schemas at Anthropic's cache-read rate instead of re-sending them at full price every trip. Off by default — a cache write costs more, so it only pays off across repeated trips; the system prompt is left uncached because it carries per-turn content.
- Changed Redis driver now logs a failed initial
connect()atlog.fatal(waslog.error). Boot-time cache connection failures are unrecoverable in practice —fatalmakes "page on fatal only" alerting clean, aligned with the cascade drivers and the herald connector.
- Changed
herald-connectorandhttp-connectornow log a failed boot-time connection atlog.fatal(waslog.error/ a dev-only console write). A broker connection failure or an HTTP port-bind failure at boot is unrecoverable —fatalmakes "page on fatal only" alerting clean, aligned with the cascade and cache drivers. The HTTP connector additionallyawait log.flush()beforeprocess.exit(1)so the fatal entry reaches Sentry/file before the process dies. Disconnect/shutdown failures stay aterror.
4.1.15 June 4, 2026
Initial public baseline of the Warlock.js framework — 17 packages published in lockstep at 4.1.15. From this release on, every change is recorded in its package's CHANGELOG.md and aggregated here by version.
No changes recorded for this package yet.