Feat/v2 query layer - #1
Conversation
…nfrastructure Turns Exostate into a single package covering both client state and server state, and fixes several bugs that would have shipped broken. Query layer (new) - QueryClient with stale-while-revalidate caching, request deduplication, retries with exponential backoff, refetch on focus/reconnect, polling, and garbage collection of unobserved entries. - createMutation with onMutate/onError context for optimistic updates and rollback. - dehydrate/hydrate for SSR; dataUpdatedAt is preserved so staleTime is measured from the server's fetch time and the client avoids a refetch waterfall on first paint. - React bindings: QueryClientProvider, useQuery, useMutation. Core store - Single commit() write path so plugins and batching cannot be bypassed. - Plugin pipeline is now actually wired: onBeforeUpdate (can transform the committed value), onAfterUpdate, onSubscribe, onUnsubscribe, onDestroy. Previously plugins were registered into a WeakMap that nothing ever read. - Lifecycle hooks with unmountDelay for lazy resource management. - Microtask notification batching plus flush(). - destroy() tears down plugins and cancels pending notifications. Bug fixes - combineStores returned state frozen at construction time when read without an active subscription, and did not catch up after detach/re-attach. - asyncAction shared one AbortController across invocations, so aborting one call cancelled a different one; added latestOnly so a slow earlier request cannot clobber a newer one. - useSelector recreated its subscribe callback every render (tearing down and re-adding the listener) and returned an uncached getSnapshot, which trips React's "getSnapshot should be cached" infinite loop with inline object selectors. - withMiddleware did not proxy destroyed, listeners or current. - Unsubscribe was not idempotent, so a double call fired lifecycle hooks twice. - freeze() could recurse forever on self-referential state. - persistFs could interleave concurrent writes into a torn file. Packaging (these would have shipped broken) - src/vue and src/solid were excluded from tsconfig while package.json advertised ./vue and ./solid exports, so those entry points were never built. - persistFs imported node:fs from the core entry, breaking browser bundlers; moved to the exostate/node subpath. CI now asserts the core stays free of node: builtins. - Switched to moduleResolution NodeNext, which surfaced extensionless relative imports that emitted ESM Node cannot resolve. Also adds: IndexedDB persistence, shallow/deepEqual comparators, Svelte and Solid selector adapters, CI with a Node 18/20/22 matrix and published-ESM smoke test, semantic-release, CodeQL, size budgets, issue/PR templates, dependabot, CONTRIBUTING, SECURITY, LICENSE, and a rewritten README. Test suite: 205 tests across 29 files, all passing.
CI installs with `npm ci`, which only resolves what package.json declares. Verified by running every CI step against a clean lockfile install. - typescript was never declared, so `npm run build` and `npm run typecheck` worked locally only via a hoisted install and would fail in CI. - @eslint/js is required by eslint.config.cjs but was undeclared. Pinned to ^9 to match the installed eslint major (v10 demands eslint 10). - @vitest/coverage-v8 is needed by the test:coverage / test:ci scripts. - esbuild is imported directly by scripts/bundle-for-size.mjs; it previously resolved only as a transitive dependency of vitest. - Aligned size-limit and @size-limit/file, which had drifted to mismatched majors (12 vs 13). Pinned to ^12: v13 requires fs/promises.glob, which needs Node 22 and contradicts the package's Node 18 baseline.
|
Warning Review limit reached
Next review available in: 40 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (66)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
ad184c8 to
a8bc0c4
Compare
… package The Node 18 test job failed: vitest 4 declares engines `^20 || ^22 || >=24`, and its rolldown dependency imports `styleText` from node:util, which only exists in Node 20.12+. The unit suite genuinely cannot run on Node 18. Dropping Node 18 from the matrix alone would have silently weakened the `engines.node: >=18` claim in package.json, so instead: - Unit tests now run on Node 20 and 22. - A new `node18-compat` job downloads the dist artifact and exercises the built package on Node 18 with no dependencies installed — covering the store, computed, combineStores, the query layer (AbortController), microtask batching (queueMicrotask), and the exostate/node entry. The published output uses nothing newer than ES2020, so this passes; if someone later reaches for a newer runtime API, the job fails and the engines field has to be raised deliberately. - Release now also gates on node18-compat. Docs corrected: development requires Node 20+, while the published package still supports Node 18.
…t files The node18-compat job failed with "Named export 'QueryClient' not found — the requested module is a CommonJS module". That was a flaw in the test, not the package: the job downloaded only dist/, so there was no package.json and therefore no "type": "module", and Node parsed the ESM output as CommonJS. Rather than just copying package.json alongside dist/, the job now tests what a consumer actually gets: - The build job packs the publishable tarball and uploads it as an artifact. - node18-compat installs that tarball into a clean project with "type": "module" and imports by bare specifier. This is a stronger check than the original — it exercises the exports map, package resolution, and "type": "module" handling, not just file contents. It also now asserts the exostate/node subpath resolves. Verified end to end locally: npm pack, install into a fresh project, and run the exact compat script against the installed package. Also fixes `npm pack --pack-destination ./pack`, which fails when the target directory does not already exist.
|
🎉 This issue has been resolved in version 1.1.0. |
No description provided.