Skip to content

fix: add "private" property to package.json - #3

Merged
bjoerge merged 1 commit into
sanity-io:currentfrom
danielheene:current
Jun 16, 2022
Merged

fix: add "private" property to package.json#3
bjoerge merged 1 commit into
sanity-io:currentfrom
danielheene:current

Conversation

@danielheene

Copy link
Copy Markdown
Contributor

This solves console warnings, when using react-rx in a yarn environment, since yarn expects the property "private": true.

warning Workspaces can only be enabled in private projects.

@bjoerge
bjoerge merged commit 454123a into sanity-io:current Jun 16, 2022
@bjoerge

bjoerge commented Jun 16, 2022

Copy link
Copy Markdown
Member

This prevented the package from being published, so had to revert it.

cursor Bot pushed a commit that referenced this pull request Jul 30, 2026
- Leak tests now prove with WeakRef + --expose-gc that the settled value and
  the instrumented promise are collectable after unmount + ttl expiry, and
  that a preloaded-never-consumed value is released after its ttl.
- The first-emission test now asserts the parent render count is unchanged,
  locking the async-react #3 invariant: the initial Suspense unblock happens
  purely via promise resolution (identical uSES snapshot bails out), never
  via a store notification re-render.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Jul 30, 2026
Bare `#3` autolinks to this repo's PR #3 on GitHub.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Jul 30, 2026
- Leak tests now prove with WeakRef + --expose-gc that the settled value and
  the instrumented promise are collectable after unmount + ttl expiry, and
  that a preloaded-never-consumed value is released after its ttl.
- The first-emission test now asserts the parent render count is unchanged,
  locking the async-react #3 invariant: the initial Suspense unblock happens
  purely via promise resolution (identical uSES snapshot bails out), never
  via a store notification re-render.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Jul 30, 2026
Bare `#3` autolinks to this repo's PR #3 on GitHub.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Jul 30, 2026
- Leak tests now prove with WeakRef + --expose-gc that the settled value and
  the instrumented promise are collectable after unmount + ttl expiry, and
  that a preloaded-never-consumed value is released after its ttl.
- The first-emission test now asserts the parent render count is unchanged,
  locking the async-react #3 invariant: the initial Suspense unblock happens
  purely via promise resolution (identical uSES snapshot bails out), never
  via a store notification re-render.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Jul 30, 2026
Bare `#3` autolinks to this repo's PR #3 on GitHub.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Jul 30, 2026
- Leak tests now prove with WeakRef + --expose-gc that the settled value and
  the instrumented promise are collectable after unmount + ttl expiry, and
  that a preloaded-never-consumed value is released after its ttl.
- The first-emission test now asserts the parent render count is unchanged,
  locking the async-react #3 invariant: the initial Suspense unblock happens
  purely via promise resolution (identical uSES snapshot bails out), never
  via a store notification re-render.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Jul 30, 2026
Bare `#3` autolinks to this repo's PR #3 on GitHub.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
stipsan added a commit that referenced this pull request Jul 31, 2026
* feat(react-rx): add useObservablePromise and preloadObservablePromise

Introduce a Suspense-ready data-fetching hook that returns a use()-compatible
instrumented promise, with TTL cache retention, disabled option, and a preload
helper for event-driven cache warm-up.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

* docs: add Suspense guide, Activity/preload examples, and tests

Expand the test suite (Activity, concurrent tearing, StrictMode, SSR, types),
document useObservablePromise / preloadObservablePromise, and add Sandpack
examples comparing prefetch strategies.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

* fix: address lint and TypeScript issues in useObservablePromise

Add override modifiers, avoid deprecated EmptyError construction, silence
floating-promise lint on preload/thenable setup, and tighten test typings.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

* fix: remove unused exports flagged by knip

Stop exporting ObservableEmptyError and drop the unused test-only cache
reset helper so CI knip passes.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

* fix: pin cache entry to mounted components so ttl eviction never drops rendered values

useObservablePromise now holds a stable per-entry handle (useMemo, keyed by
observable identity) instead of re-looking-up the WeakMap in subscribe/
getSnapshot. Hidden <Activity> trees have no live store subscription, so the
ttl policy could evict the entry of a still-mounted component; on reveal the
fresh lookup created a new pending entry, re-activating the Suspense fallback
and refetching a completed source. The pinned entry keeps the settled promise
readable for as long as the component renders that observable (the same
local-reference pattern as useObservable), and re-registers itself in the
cache when it gains live subscribers again. ensure() now also re-arms a
pending eviction timer, so retention counts from the last touch (e.g. a
preload extending a hook-settled entry).

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

* test: WeakRef GC leak coverage + first-emission bailout assertion

- Leak tests now prove with WeakRef + --expose-gc that the settled value and
  the instrumented promise are collectable after unmount + ttl expiry, and
  that a preloaded-never-consumed value is released after its ttl.
- The first-emission test now asserts the parent render count is unchanged,
  locking the async-react #3 invariant: the initial Suspense unblock happens
  purely via promise resolution (identical uSES snapshot bails out), never
  via a store notification re-render.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

* test: prove userland useDeferredValue restores time slicing for emission updates

Emission-driven uSES re-renders are scheduled at sync priority and cannot be
time-sliced directly. The new interleaving test (createRoot outside act, DOM
sampled between event-loop turns) proves the userland escape hatch works:
useDeferredValue(promise) + memo keeps the expensive subtree on the old
promise during the synchronous store pass, re-renders it on the deferred lane
(observed lag window), lets an urgent click preempt the in-progress ~100ms
deferred render, and converges afterwards. A negative control (removing
useDeferredValue) fails the lag-window assertion, so the test discriminates.
Documented the pattern (incl. the load-bearing memo) in the guide.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

* test: link async-react discussion by full URL

Bare `#3` autolinks to this repo's PR #3 on GitHub.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

* fix: re-arm share grace when ttl is extended after unmount

When ensure() raises retentionMs while a settled entry has no live
subscribers, share's resetOnRefCountZero timer was already started with
the old retention. Re-arming only the WeakMap eviction timer left
long-lived sources disconnecting early, so emissions during the extended
window were lost. Bounce a no-op subscription so share cancels the
pending reset and starts a fresh grace period with the updated ttl.

Also document that preload starts the source immediately and that hung
observables keep the pending promise/subscription alive until settle
(prefer RxJS timeout).

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

* fix: align share grace and eviction to a single retention window

Two Bugbot findings on the ttl policy:
- finalize no longer restarts an already-pending eviction timer when share
  disconnects, which was doubling documented retention for long-lived sources
- ensure() bounces share's resetOnRefCountZero on same-ttl preloads/remounts
  (startResolver), not only when retentionMs increases, so renewing a touch
  keeps the multicast connected for the renewed window

Regression tests cover both; negative controls fail without the fixes.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

* fix: only preload renews ttl grace — idle renders must not reset the clock

ensure() was re-arming eviction (and bouncing share) whenever a timer was
pending. The hook calls ensure on every render, so disabled consumers and
hidden <Activity> trees kept resetting ttl forever — breaking the documented
retention contract for future mounts and leaving long-lived connections open.
Pinning already preserves the mounted value after a real eviction.

Grace renewal is now opt-in via ensure(..., renewGrace) and only
preloadObservablePromise passes it. Idle ensures still adopt max ttl for later
timers without restarting the current window.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

* test: void disabled useObservablePromise to satisfy no-floating-promises

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

* fix: reject empty sources with the real RxJS EmptyError

Completing without emitting now rejects with RxJS's own EmptyError (the exact
type firstValueFrom throws) instead of a private look-alike, so consumer
`instanceof EmptyError` checks succeed and the documented firstValueFrom
semantics hold. RxJS marks the constructor @deprecated as an internal detail,
but firstValueFrom/first/single throw this type, so mirroring it is
intentional — scoped oxlint-disable documents that. Test now asserts the
thrown error is an EmptyError instance.

Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Cody Olsen <stipsan@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Aug 4, 2026
Fix delay unit lebel from seconds to milliseconds
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.

2 participants