Releases: gramiojs/dialogs
Release list
v0.3.1
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
-
D2-1: createDialogs().background edits the last message with no update
-
D2-5: over-long callback_data throws a named error into onError
-
D2-2: concurrent taps on one stack don't lost-update (withLock + reload)
three fixes that previously had no e2e coverage:
test: cover D2-1/D2-2/D2-5 end-to-end via @gramio/testAdds real-bot integration tests through TelegramTestEnvironment for the
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Strictly more permissive — not a breaking change. Tests: datadict-interface.
-
export
AnyData/RenderDatablocked
Window<interface>⊆Window<DataDict>);isHiddenmade generic -
widen
Dialogwindow storage toWindow<AnyData>(Getter's covariant returninterface, and untyped windows alike
DataDict
collapses toDataDict, sod.dialogData` keeps working for typed,render callback: the engine injects
dialogData/startData, and `AnyData & -
new
RenderData<Data> = Data & DataDicttypesRenderContext.dataand every -
DataDictstays the concrete, indexable bag the engine stores/indexesspelled out for intent); ~30 user-facing
extends DataDict→extends AnyData -
new
AnyData = Record<PropertyKey, unknown> | objectconstraint (≡ object,
failed extends DataDict (interfaces have no implicit index signature).
feat: accept interface-typed window Data (not just type)A typed Window<Data> / getter now accepts a TS interface, which previously
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
messages. No behavior change.
compiler; the bare alias reads better in hovers and constraint-violation
refactor: simplify AnyData to object (same type, cleaner tooltips/errors)Record<PropertyKey, unknown> | object is identical to object for the
chore(release): v0.3.0Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
check` (CI) failed on formatting only. No logic change.
style: biome-format plugin.test.ts (unbreak CI lint)The D2 e2e tests were committed without running bun run lint; `bun run
data-derived, undefined return, and Url combo).
Add test coverage for function-style resolution (static → ✓,
LinkWidget (Url/WebApp), and SwitchInlineWidget render paths.
Add resolveStyle() helper, wire it through ButtonWidget,
WhenCondition and TextSource for render-data-derived values.
in addition to a static value, matching the pattern used by
feat: support dynamic style function on Button (like TextSource)Make ButtonChrome.style accept a function (rc) => ButtonStyle
chore: v0.3.1
fix: allow undefined return in style function, update CLAUDE.md with full check
Full Changelog: v0.2.1...v0.3.1
v0.2.1
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Version intentionally not bumped. Tests: feedback-d2; routing/robustness updated.
-
D2-6: document that
Select.itemIdmust be collision-free as a string.build time, instead of warning then letting Telegram reject the send into onError.
-
D2-5: over-long
callback_datanow throws a clear error naming the widget atinstead of leaving a no-op stub on the shared gramio context.
-
D2-4: scope the reply-keyboard
ctx.answershim — restore it after routing(was mutated in memory but dropped, only relevant with
StartMode.NewStack). -
D2-3: persist the
currentIdreselection on the stale/denied return pathsheadlessCtxalso fleshesfrom.is_bot.fromwith a locale, ort) so getters/i18n needing more thanfrom.idwork; -
D2-1:
background(bot, key, overrides?)— enrich the headless ctx (e.g. realcreateDialogs().withLocksobackground()callers can serialize against taps.(
_reloadStore), so concurrent updates can't clobber each other. Exposed asupdate path now locks per stack key and re-reads the store under the lock
fix: address v0.2.0 feedback round 2 (background/persist/routing hardening)- D2-2: lost-update race — StackRepository.withLock keyed async mutex; the live
chore(release): v0.2.1Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Full Changelog: v0.2.0...v0.2.1
v0.2.0
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Tests: tests/feedback-fixes.test.ts (6 new; full bun run check green)
DataDict-needs-type-not-interface constraint, and the new APIs
-
docs: getter↔dialogData flow, headless getter contract, the
backed by external state
-
feat: Select({ selected, selectedMark }) — auto-✓ for stateless selects
rendering the target window (back-compat with the bare ShowMode arg)
-
feat: switchTo(state, { data, mode }) — merge into dialogData before
-
feat: DialogManager.setData(patch) — merge dialog data + persist, no render
ctx.from.id no longer crash when re-rendered from background()
-
fix: headlessCtx synthesizes
from: { id: chatId }so getters reading
feat: harden background() renders and add data-navigation APIsAddresses production feedback on the background()/headless seam:
chore(release): v0.2.0Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Tests: answer-binding (stale + handled taps with a this-dependent answer).
and route the success-path spinner close through the same helper.
Now call it bound on ctx inside try/catch (catches sync throw + rejection),
bot's onError (surfaced as a prod crash on stale/denied taps and timeouts).
and .catch() only catches rejections, so the throw escaped past it into the
this.bot.api.answerCallbackQuery, so the detached call threw SYNCHRONOUSLY —
undefined. gramio's answer is a prototype alias delegating to
fix: bind answer in silentAnswer so detached call can't crash the botsilentAnswer detached the method (const a = ctx.answer; a()), so this was
Full Changelog: v0.1.0...v0.2.0
v0.1.0
feat: update readme.md and .gitignore
fix: ci badge url
fix: biome format
fix: typed text param for strict gramio + quiet changelog tag lookup
Full Changelog: https://github.com/gramiojs/dialogs/commits/v0.1.0