Skip to content

feat: production readiness fixes and test coverage - #29

Merged
KingDoxik merged 1 commit into
mainfrom
feat/production-readiness
Oct 2, 2026
Merged

KingDoxik merged 1 commit into
mainfrom
feat/production-readiness

Conversation

@KingDoxik

@KingDoxik KingDoxik commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes the issues found in a pre-release review of 2.0.0-alpha.1 and adds the test coverage that was missing. Breaking changes are intentional, since the package is not public yet.

Fixes

  • React QueryErrorBoundary decides once, when an error is caught, whether it belongs to the boundary. Previously it re-checked on every render. If the failed query was removed, garbage-collected or refetched while the fallback was showing, the next re-render escalated the error to the parent boundary.
  • EffectQueryDefect (breaking):
    • The defect is no longer wrapped twice. defect is the original value, defectCause is the original Cause, and the new interrupted property is true when the Effect was cancelled.
    • The constructor now takes a Cause.
  • Error details (breaking): both error classes get a real name, a short message with no stack traces, and the standard Error.cause.
  • Throwing Effect functions: a function that throws instead of returning an Effect now becomes an EffectQueryDefect.
  • Getters on options objects stay live instead of being read once by the spread. This mainly affects Solid and Svelte.
  • Runtime lifecycle:
    • If building the layer dies, the next query builds it again, so retries can recover. A build that was only cancelled is not discarded, and a runtime the user passes in is never replaced.
    • New eq.runtime and eq.dispose() on every adapter. After dispose(), queries fail; the runtime is not quietly rebuilt.
  • Logging (breaking): only defects are logged. Typed failures and interruptions are not.
  • Custom key hashes: the React, Vue and Solid boundaries hash each query with its own queryKeyHashFn, so keys that need a custom hash (for example BigInt) no longer crash the boundary.
  • Solid SSR:
    • A boundary that rendered its fallback on the server keeps it while hydrating, instead of escalating the deserialized error.
    • Its fallback gets the typed error from the client's cache, or an EffectQueryDefect wrapping the server error.

Tests (174 → 240)

  • New core project (Node): error mapping, match/OrElse, cancellation, span names, getters, layer rebuild, dispose and logging.
  • Rewritten React query and infinite-query tests. The old ones still passed when the Effect died, because they read a cache entry under the same key that a plain query had already filled.
  • Boundary regression tests: removed or refetched query (React), BigInt keys (React, Vue and Solid), Solid hydration.
  • Type tests for runtime/dispose and createEffectQueryFromManagedRuntime in all four frameworks.
  • Verified against the old code: every new regression test fails on the old source and passes with the fixes.

CI and packaging

  • New ci.yml runs lint, build, typecheck, the Playwright browser tests, publint and arethetypeswrong on PRs and pushes to main.
  • release.yml now runs lint, typecheck and tests before publishing.
  • package.json gets "sideEffects": false.
  • README documents the error fields, runtime lifecycle, cancellation and logging, and the limits of serializing errors.

Test plan

  • pnpm turbo lint typecheck build test --force: all 11 tasks pass, including the four example apps
  • Type tests pass on TypeScript 7 and TypeScript 6
  • publint (strict) and arethetypeswrong (node16) pass
  • The new CI workflow passes on this PR

🤖 Generated with Claude Code

- Map defects without double wrapping: EffectQueryDefect exposes `defect`,
  `interrupted` and the original `defectCause`; both error classes get a real
  `name`, a short `message` and the standard `cause`
- Turn Effect functions that throw synchronously into defects
- Keep getters on options objects live instead of reading them once
- Rebuild a Layer whose build died so retries can recover; expose `runtime`
  and `dispose()` on every adapter
- Only log defects, not typed failures or interruptions
- React QueryErrorBoundary decides ownership once per caught error
- Boundaries hash queries with their own queryKeyHashFn (BigInt keys)
- Solid QueryErrorBoundary handles errors restored during SSR hydration
- Add a node `core` test project, rewrite the React query and infinite query
  tests, add boundary, hydration, getter and runtime-handle type tests
- Add CI workflow and run checks before publishing; sideEffects: false

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@KingDoxik
KingDoxik merged commit e5f50e2 into main Oct 2, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant