Skip to content

Releases: burrr-ai/comwit

v2.2.0 — Local-first resources

Choose a tag to compare

@Moon-DaeSeung Moon-DaeSeung released this 17 Aug 06:29
7e4cf1c

Highlights

  • Added standalone IndexedDB-backed local resources for durable server-owned snapshots without requiring a client request.
  • Added local.query and local.infinite adapters with exact argument restore, stale-time revalidation, and graceful in-memory fallback.
  • Added normalized collections with custom entity identity, fragment merge and revision controls, version cleanup, and list/detail fan-out.
  • Added static and lazy collection-level scopes for public, user, and tenant cache isolation, including protection against cross-scope response commits.
  • Added documentation and agent guidance covering local-first boundaries, server initialization, optimistic updates, and synchronization behavior.
  • Fixed selector .load calls on frozen snapshots produced by derived, computed, validation, and history model extensions.

Upgrade

npm install @comwit/state@2.2.0

The deprecated comwit compatibility package is also available at 2.2.0 and re-exports @comwit/state.

Both packages are published under the npm latest tag.

Validation

  • 369 library tests passed.
  • TypeScript type checking passed.
  • Library and documentation production builds passed.

Full changelog: v2.1.0...v2.2.0

v2.1.0 — Selector-owned query loading

Choose a tag to compare

@Moon-DaeSeung Moon-DaeSeung released this 05 Aug 05:44
4171274

Selector-owned query loading

React components can now declare a query and its typed argument directly inside the existing useModel() / create() selector:

const products = useProduct((state) =>
  state.products.load({ page, filter })
)

const stats = useProduct((state) => state.stats.load())

The argument is inferred from Query<Data, Arg>. Calling .load() is the explicit opt-in; selecting the resource without it remains a passive read and never starts a request.

Behavior

  • reports first-load state during the initial render, avoiding the empty → skeleton flash before an effect runs
  • starts the request after React commits
  • changes cache keys when the serialized argument changes
  • does not restart a stable mounted query on unrelated rerenders
  • deduplicates concurrent selector loads for the same resource and key
  • supports single, infinite, and realtime resources
  • keeps call-time query options in imperative actions

Fully backward compatible

Existing action methods remain unchanged:

await this.model.products.query({ page, filter })
await this.model.products.refetch()
this.model.products.set(serverData)

useEffect-driven loading continues to work. Use selector .load() for view-owned requests and action .query() for commands, preloads, forced requests, multi-query workflows, and side effects. No additional React hook was added.

Documentation

  • rewrote llms.txt as a concise English domain implementation guide
  • documented selector-owned versus command-owned query loading
  • added cache-aware App Router Suspense fallback guidance using existing silent() + .set() initialization instead of a new hydration API
  • added the v2.1.0 release article

Validation

  • 25 test files, 345 tests passed
  • TypeScript and selector type-contract checks passed
  • ESM/CJS bundle and declaration generation passed
  • docs production build passed
  • published package tarballs were inspected

Packages

  • @comwit/state@2.1.0
  • comwit@2.1.0 compatibility shim → @comwit/state@^2.1.0

Closes #77. Implemented in #80.

v2.0.0 — The package is now @comwit/state

Choose a tag to compare

@Moon-DaeSeung Moon-DaeSeung released this 03 Jul 10:53

The package is now @comwit/state

comwit is now published on npm as @comwit/state. That's the whole change — there are no API changes, no renamed exports, no behavioral differences. Only two things move:

  1. The package you install: comwit@comwit/state
  2. The specifier you import from: from 'comwit'from '@comwit/state'

The ComwitProvider component, the library.comwit.io docs, and this GitHub repo keep their names. Only the npm package identifier changed.

Migration

For most projects this is a two-line change:

yarn remove comwit
yarn add @comwit/state
- import { model, action, query, ComwitProvider } from 'comwit'
+ import { model, action, query, ComwitProvider } from '@comwit/state'

A project-wide find-and-replace of from 'comwit'from '@comwit/state' is safe — the export surface is identical.

You don't have to migrate immediately

We took the soft path — nothing breaks on upgrade:

  • comwit@2.0.0 was published as a thin compatibility shim that simply re-exports @comwit/state. Existing import ... from 'comwit' code keeps working unchanged.
  • The comwit package is now deprecated on npm with a notice pointing to @comwit/state.

New projects should install @comwit/state directly; existing projects can migrate whenever convenient. The shim is a bridge, not a long-term home.

Why a major version?

The public API is unchanged, but renaming the package is breaking for consumers (install name + import path move), so this ships as 2.0.0. Both @comwit/state and the comwit compatibility shim are published at 2.0.0 and track the same version line going forward.

Links


🤖 Generated with Claude Code

v1.3.0

Choose a tag to compare

@Moon-DaeSeung Moon-DaeSeung released this 28 May 15:15

First stable release of the 1.3.x line (supersedes 1.2.0 on the latest tag).

Highlights

  • Model history (undo/redo). Built-in undo/redo for models, with a configurable history limit (default 100) and safe handling of concurrent async transactions.
  • Observer-based gcTime (TanStack Query v5 semantics). Garbage collection now starts when a model loses its last useModel observer instead of from lastFetchedAt. Cache entries are never evicted while a model has active subscribers, which fixes isLoading flicker on same-key refetches. gcTime now defaults to 5 minutes, applied only after a model reaches zero observers.
  • Improved flush / cancel helpers for @Debounce / @Throttle. flushDebounce / cancelDebounce / flushThrottle / cancelThrottle are now keyed per instance (two instances of the same class no longer share a window) and return a deferred result, so the surrounding interceptor stack (@OnError, @Retry, …) observes the flushed call's return value or rejection.

Fixes

  • refetch() always returns a Promise, even when the query has no active entry yet — previously it returned undefined and broke .then / .catch callers (#76).

Breaking / migration

  • Removed the cacheTime option (it was an alias for gcTime). Use gcTime instead.
  • FieldPlugin.bindState gains an optional modelKey argument and a new optional onSubscriberChange(modelKey, bag, registryState, hasObservers) hook. External plugins implementing the FieldPlugin interface must accept (or ignore) the extra argument.

Docs

  • New History and Utilities API documentation, plus a refreshed llms.txt.

v1.0.0 — stable

Choose a tag to compare

@Moon-DaeSeung Moon-DaeSeung released this 26 Apr 10:31

First stable release of comwit.

Highlights since 0.x

Features

  • computed() primitive for derived state (#44)
  • Model lifecycle hooks: onObserve / cleanup (#43)
  • Streaming query support via AsyncIterable (#45)
  • DevTools integration layer (__COMWIT_DEVTOOLS__) (#42)
  • toPlain() utility for proxy-to-POJO conversion (#55)
  • Removed valtio dependency — inline proxy reactivity engine (#52)

Fixes

  • Reset query state when arg changes without keepPreviousData (#60)
  • Synchronous subscribe() to fix IME composition (#56)
  • Expose .snapshot() type on nested proxy objects (#64)

Docs

  • Full docs site moved to https://library.comwit.io
  • computed(), lifecycle hooks, dependent queries, suspense docs (#54)
  • SWC decorator setup step in llms.txt (#57, #59)
  • Class-level lazy decorator example (#65)

Install

npm i comwit

LLM setup: pass https://library.comwit.io/llms.txt to Claude Code.

v0.2.5

Choose a tag to compare

@Moon-DaeSeung Moon-DaeSeung released this 26 Feb 02:33

Fix

  • fix(proxy): synchronous notification for IME composition support (#48, #49)
    • Replaced microtask-based (Promise.resolve().then()) listener notification with synchronous notification
    • Fixes Korean/Japanese/Chinese IME composition breaking in controlled inputs
    • Fixes cursor jumping to end of input on every keystroke
    • React 18's automatic batching handles grouping multiple synchronous updates, so no performance regression
    • Matches the approach used by Zustand (synchronous by default) and Valtio ({ sync: true } option)

Migration

No breaking changes. This is a drop-in upgrade — controlled inputs with CJK IME will now work correctly without needing onCompositionStart/onCompositionEnd workarounds.

v0.2.1

Choose a tag to compare

@Moon-DaeSeung Moon-DaeSeung released this 20 Feb 15:23

Bug Fix

query().query() no longer throws on second call (#35)

Calling .query() on a resource field threw TypeError: Cannot assign to read only property '0' on subsequent calls. The proxy engine now shallow-clones frozen snapshot objects before wrapping, preventing in-place mutation of cached state.

Fix: #36

Upgrade

yarn add comwit@0.2.1

Drop-in replacement. No API changes.

v0.2.0

Choose a tag to compare

@Moon-DaeSeung Moon-DaeSeung released this 20 Feb 15:03

What's New in v0.2.0

Features

  • Suspense Supportquery() and query.infinite()suspense: true 옵션 추가. React <Suspense>와 자연스럽게 통합되며, 별도 hook 없이 기존 useModel() / create()로 동작. TypeScript에서 dataNonNullable<T>로 자동 추론됨 (#32)

  • Real-time Subscriptionsquery.realtime() 디스크립터 추가. WebSocket, SSE 등 실시간 데이터 소스를 query() 패턴으로 통합. connectionStatus, isConnected 상태 제공, subscribe 콜백으로 update(), set(), onStatus(), onError() 지원 (#30)

  • Persist Pluginpersist() 필드 디스크립터 추가. localStorage, sessionStorage 기본 어댑터 제공, 커스텀 PersistAdapter 인터페이스 지원. 크로스탭 동기화, 디바운스 write-back, SSR 안전, 커스텀 직렬화/역직렬화 (#31)

  • Decorators@Retry, @Queue, @Log, @Validate 데코레이터 추가. 글로벌 인터셉터, derived state, model validation 지원

Architecture

  • Plugin System — 모놀리식 구조에서 플러그인 아키텍처로 리팩토링. FieldPlugin 인터페이스를 통해 query, persist, realtime 등 기능이 코어 수정 없이 동적으로 등록됨. registerPlugin()으로 확장 가능 (#33)

  • Custom Proxy Layer — valtio 의존성 제거, 자체 프록시 기반 반응성 엔진 구현

Bug Fixes

  • query isLoading 계산 순서 수정 — error-retry 시 로딩 상태 정상 표시 (#17)
  • stale response race condition 수정 — 빠른 query arg 변경 시 최신 응답만 반영 (#17)
  • set() 호출 시 캐시 동기화 — staleTime 내 읽기 시 set 데이터 유지 (#17)
  • nextFetch cursor history 개선 — 다단계 뒤로가기 네비게이션 지원 (#17)
  • infinite query withCursor 제거, hasMore 가드 추가 (#15)

Docs

  • llm.txt 모듈형 레퍼런스 분리 — query, decorator 상세 레퍼런스 추가 (#34)

Full Changelog: v0.0.2...v0.2.0

v0.0.2 — Initial Release

Choose a tag to compare

@Moon-DaeSeung Moon-DaeSeung released this 17 Feb 08:20

comwit v0.0.2

React state management for vibe coding. Pass llm.txt to Claude Code.

Highlights

  • model() / action() / create() — core state management API
  • query() / query.infinite() — built-in data fetching with caching
  • silent() — SSR hydration without re-renders
  • Decorators: @OnError, @OnSuccess, @Debounce, @Throttle, @Authorized
  • createInterceptor — reusable decorator factories
  • MuchaProvider — React context with default query options
  • Full llm.txt support — just pass the URL to Claude Code

Links