You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
`action.ts` was checking yielded values with `instanceof Promise`. That skips anything whose `then` is a method but whose prototype isn't `Promise.prototype` — userland thenables, cache library handles (the `syncThenable` shape used elsewhere in this same package), and engines that pass cross-realm promises across worker boundaries. Every such yield landed in the synchronous `run(r)` branch, so the generator resumed immediately with the raw thenable object — `got: [object Object]` in the StackBlitz repro.
The fix replaces both `instanceof Promise` checks with a small `isThenable` predicate (`value != null && (object|function) && typeof value.then === "function"`), the same shape `await` itself uses, and casts the awaited path to `PromiseLike<...>`. Native Promises still satisfy the predicate, so the existing test cases for `yield Promise.resolve(42)` etc. keep their behavior — the change only widens what counts as awaitable.
Test
Added `should await a non-Promise thenable and resume with its fulfilled value (#2765)` in `packages/solid-signals/tests/action.test.ts`:
asserts the generator does NOT resume synchronously with the raw object (pre-fix bug)
asserts the resumed value is `42` after the microtask drains
Without the patch the new test fails at `expect(receivedValue).toBe(42)` (receives the thenable object); with the patch it passes. The full `pnpm --filter @solidjs/signals test tests/action.test.ts` suite (57 tests) stays green.
Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.
This PR includes no changesets
When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types
Good catch — action() only awaited native Promise instances, so a yielded thenable that wasn't instanceof Promise resumed the generator with the raw object instead of its settled value. We've landed an equivalent fix on next: yield handling now uses a thenability check (typeof value.then === "function") at both sites, matching how await treats thenables, with a regression test.
The map.ts/repeat change bundled here is already on next (the _offset reset from the earlier repeat fix), so there's nothing to take there. Closing since the action fix is in — thanks for the thenable fix.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2765.
`action.ts` was checking yielded values with `instanceof Promise`. That skips anything whose `then` is a method but whose prototype isn't `Promise.prototype` — userland thenables, cache library handles (the `syncThenable` shape used elsewhere in this same package), and engines that pass cross-realm promises across worker boundaries. Every such yield landed in the synchronous `run(r)` branch, so the generator resumed immediately with the raw thenable object — `got: [object Object]` in the StackBlitz repro.
The fix replaces both `instanceof Promise` checks with a small `isThenable` predicate (`value != null && (object|function) && typeof value.then === "function"`), the same shape `await` itself uses, and casts the awaited path to `PromiseLike<...>`. Native Promises still satisfy the predicate, so the existing test cases for `yield Promise.resolve(42)` etc. keep their behavior — the change only widens what counts as awaitable.
Test
Added `should await a non-Promise thenable and resume with its fulfilled value (#2765)` in `packages/solid-signals/tests/action.test.ts`:
Without the patch the new test fails at `expect(receivedValue).toBe(42)` (receives the thenable object); with the patch it passes. The full `pnpm --filter @solidjs/signals test tests/action.test.ts` suite (57 tests) stays green.