[2.2.0-rc1][2.2.0-rc1] - 2026-09-07
Long polling
- A
409 Conflictis now treated as a recoverable poll error instead of
permanently stopping the loop (#1350). AddedLongPollOptions.conflictRetryDelayMs
(default 5000ms) andmaxConflictRetries(default 10) - after that many
consecutive conflicts (a genuine two-instance deploy) the loop throws. The
existingretrytoggle now also governs 409s. Added the publicisPollConflict()
predicate and theHTTP_STATUS_CONFLICTconstant.
Transport
- An empty or whitespace-only
apiRootnow falls back to the default API root
instead of being used verbatim (which produced malformed request URLs) (#1354).
Node helpers
run()gained an opt-inexitOnError(defaultfalse): when a polling pump
fails fatally, the process exits non-zero after teardown instead of staying
alive and silent, so a supervisor can restart it (#1351).RedisSessionStoragenow owns and closes a client it constructs from aurl,
via acreateClientseam (#1351).
Reply and callback tracking
- Added an opt-in per-chat LRU bound on the reply/press tables, configured on
the session:createSession({ store, replyTracking: { maxEntries, maxBytes, defaultTtlSeconds, slidingTtl } }).ttlSecondscaps a marker's age but not the
table's size, so a chat that fires many short-lived keyboards could still grow
its envelope between prunes (#1357). maxEntries/maxBytescap the tables (combined across replies and presses),
evicting the least-recently-used markers once a budget is exceeded - recency,
not age, so an actively-pressed old keyboard outlives an idle newer one; a match
refreshes recency, not just a record.defaultTtlSecondsgives every expectation
a TTL, andslidingTtlre-arms it on use.- All fields are optional; with no
replyTrackingthe tables stay unbounded, as
before. Recency metadata (lastUsedAt) is written only when a size budget
(maxEntries/maxBytes) is set, so configs without one keep byte-identical
envelopes. - Added the example
examples/18-reply-tracking-lru.ts.
Sessions
- Dropped the
createdAt/updatedAtenvelope timestamps (and thenowclock
option that fed them): nothing read them, and slimming the envelope directly
serves the growth the LRU bound targets. Stale timestamp fields on already-stored
rows fall out on the next write. (These shipped only in2.2.0-rc0.)
Full changelog: v2.2.0-rc0...v2.2.0-rc1