Update npm package effect to v3.20.0 [SECURITY]#8565
Update npm package effect to v3.20.0 [SECURITY]#8565hash-worker[bot] wants to merge 1 commit intomainfrom
effect to v3.20.0 [SECURITY]#8565Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryMedium Risk Overview Regenerates Written by Cursor Bugbot for commit 437b27c. This will update automatically on new commits. Configure here. |
🤖 Augment PR SummarySummary: Updates the 🤖 Was this summary useful? React with 👍 or 👎 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8565 +/- ##
==========================================
- Coverage 62.60% 62.49% -0.11%
==========================================
Files 1317 1318 +1
Lines 133975 134209 +234
Branches 5517 5517
==========================================
+ Hits 83877 83878 +1
- Misses 49183 49416 +233
Partials 915 915 Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Benchmark results
|
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2002 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 1001 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 3314 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 1526 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 2078 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 1033 | Flame Graph |
policy_resolution_medium
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 102 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 51 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 269 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 107 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 133 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 63 | Flame Graph |
policy_resolution_none
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 8 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 3 | Flame Graph |
policy_resolution_small
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 52 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 25 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 94 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 26 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 66 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 29 | Flame Graph |
read_scaling_complete
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id;one_depth | 1 entities | Flame Graph | |
| entity_by_id;one_depth | 10 entities | Flame Graph | |
| entity_by_id;one_depth | 25 entities | Flame Graph | |
| entity_by_id;one_depth | 5 entities | Flame Graph | |
| entity_by_id;one_depth | 50 entities | Flame Graph | |
| entity_by_id;two_depth | 1 entities | Flame Graph | |
| entity_by_id;two_depth | 10 entities | Flame Graph | |
| entity_by_id;two_depth | 25 entities | Flame Graph | |
| entity_by_id;two_depth | 5 entities | Flame Graph | |
| entity_by_id;two_depth | 50 entities | Flame Graph | |
| entity_by_id;zero_depth | 1 entities | Flame Graph | |
| entity_by_id;zero_depth | 10 entities | Flame Graph | |
| entity_by_id;zero_depth | 25 entities | Flame Graph | |
| entity_by_id;zero_depth | 5 entities | Flame Graph | |
| entity_by_id;zero_depth | 50 entities | Flame Graph |
read_scaling_linkless
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | 1 entities | Flame Graph | |
| entity_by_id | 10 entities | Flame Graph | |
| entity_by_id | 100 entities | Flame Graph | |
| entity_by_id | 1000 entities | Flame Graph | |
| entity_by_id | 10000 entities | Flame Graph |
representative_read_entity
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1
|
Flame Graph |
representative_read_entity_type
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| get_entity_type_by_id | Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba
|
Flame Graph |
representative_read_multiple_entities
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_property | traversal_paths=0 | 0 | |
| entity_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=0 | 0 | |
| link_by_source_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true |
scenarios
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| full_test | query-limited | Flame Graph | |
| full_test | query-unlimited | Flame Graph | |
| linked_queries | query-limited | Flame Graph | |
| linked_queries | query-unlimited | Flame Graph |
This PR contains the following updates:
3.18.4->3.20.0Warning
Some dependencies could not be looked up. Check the Dependency Dashboard for more information.
GitHub Vulnerability Alerts
CVE-2026-32887
Versions
effect: 3.19.15@effect/rpc: 0.72.1@effect/platform: 0.94.2@clerk/nextjs: 6.xRoot cause
Effect's
MixedSchedulerbatches fiber continuations and drains them inside a single microtask or timer callback. TheAsyncLocalStoragecontext active during that callback belongs to whichever request first triggered the scheduler's drain cycle — not the request that owns the fiber being resumed.Detailed mechanism
1. Scheduler batching (
effect/src/Scheduler.ts,MixedScheduler)scheduleTaskonly callsstarve()whenrunningisfalse. Subsequent tasks accumulate inthis.tasksuntilstarveInternaldrains them all. ThePromise.then()(orsetTimeout) callback inherits the ALS context from whichever call site created it — i.e., whichever request's fiber first setrunning = true.Result: Under concurrent load, fiber continuations from Request A and Request B execute inside the same
starveInternalcall, sharing a single ALS context. If Request A triggeredstarve(), then Request B's fiber reads Request A's ALS context.2.
toWebHandlerRuntimedoes not propagate ALS (@effect/platform/src/HttpApp.ts:211-240)Effect's own
Context(containingHttpServerRequest) is correctly set per-request. But the Node.js ALS context — which frameworks like Next.js, Clerk, and OpenTelemetry rely on — is not captured at fork time or restored when the fiber's continuations execute.3. The dangerous pattern this enables
The
async () => auth()thunk executes when the fiber continuation is scheduled byMixedScheduler. At that point, the ALS context belongs to an arbitrary concurrent request.Reproduction scenario
Minimal reproduction
Impact
auth()returns wrong user's sessioncookies()/headers()from Next.js read wrong requestWorkaround
Capture ALS-dependent values before entering the Effect runtime and pass them via Effect's own context system:
Suggested fix (for Effect maintainers)
Option A: Propagate ALS context through the scheduler
Capture the
AsyncLocalStoragesnapshot when a fiber continuation is scheduled, and restore it when the continuation executes:AsyncLocalStorage.snapshot()(Node.js 20.5+) returns a function that, when called, restores the ALS context from the point of capture. This ensures each fiber continuation runs with its originating request's ALS context.Trade-off: Adds one closure allocation per scheduled task. Could be opt-in via a
FiberRefor scheduler option.Option B: Capture ALS at
runForkand restore per fiber stepWhen
Runtime.runForkis called, capture the ALS snapshot and associate it with the fiber. Before each fiber step (in the fiber runtime'sevaluateEffectloop), restore the snapshot.Trade-off: More invasive but provides correct ALS propagation for the fiber's entire lifetime, including across
flatMapchains andEffect.tryPromisethunks.Option C: Document the limitation and provide a
contextinjection APIIf ALS propagation is intentionally not supported, document this prominently and provide a first-class API for
toWebHandlerto accept per-request context. The existingcontext?: Context.Context<never>parameter on the handler function partially addresses this, but it requires callers to know about the issue and manually extract values before entering Effect.Related
AsyncLocalStoragedocs: https://nodejs.org/api/async_context.htmlAsyncLocalStorage.snapshot(): https://nodejs.org/api/async_context.html#static-method-asynclocalstoragesnapshotcookies(),headers(),auth()in App RouterFiberRefpropagation for this)POC replica of my setup
Used util functions
The actual effect that was run within the RPC context that the bug was found
Release Notes
Effect-TS/effect (effect)
v3.20.0Compare Source
Minor Changes
8798a84Thanks @mikearnaldi! - Fix scheduler task draining to isolateAsyncLocalStorageacross fibers.Patch Changes
#6107
fc82e81Thanks @gcanti! - BackportTypes.VoidIfEmptyto 3.x#6088
82996bcThanks @taylorOntologize! - Schema: fixSchema.omitproducing wrong result on Struct withoptionalWith({ default })and index signaturesgetIndexSignaturesnow handlesTransformationAST nodes by delegating toast.to, matching the existing behavior ofgetPropertyKeysandgetPropertyKeyIndexedAccess. Previously,Schema.omiton a struct combiningSchema.optionalWith(with{ default },{ as: "Option" }, etc.) andSchema.Recordwould silently take the wrong code path, returning a Transformation with property signatures instead of a TypeLiteral with index signatures.#6086
4d97a61Thanks @taylorOntologize! - Schema: fixgetPropertySignaturescrash on Struct withoptionalWith({ default })and other Transformation-producing variantsSchemaAST.getPropertyKeyIndexedAccessnow handlesTransformationAST nodes by delegating toast.to, matching the existing behavior ofgetPropertyKeys. Previously, callinggetPropertySignatureson aSchema.StructcontainingSchema.optionalWithwith{ default },{ as: "Option" },{ nullable: true }, or similar options would throw"Unsupported schema (Transformation)".#6097
f6b0960Thanks @gcanti! - Fix TupleWithRest post-rest validation to check each tail index sequentially.v3.19.19Compare Source
Patch Changes
#6079
4eb5c00Thanks @tim-smart! - add short circuit to fiber.await internals#6079
4eb5c00Thanks @tim-smart! - build ManagedRuntime synchronously if possible#6081
2d2bb13Thanks @tim-smart! - fix semaphore race condition where permits could be leakedv3.19.18Compare Source
Patch Changes
12b1f1eThanks @tim-smart! - prevent Stream.changes from writing empty chunksv3.19.17Compare Source
Patch Changes
a8c436fThanks @jacobconley! - FixStream.decodeTextto correctly handle multi-byte UTF-8 characters split across chunk boundaries.v3.19.16Compare Source
Patch Changes
#6018
e71889fThanks @codewithkenzo! - fix(Match): handle null/undefined inMatch.tagandMatch.tagStartsWithAdded null checks to
discriminatoranddiscriminatorStartsWithpredicates to prevent crashes when matching nullable union types.Fixes #6017
v3.19.15Compare Source
Patch Changes
#5981
7e925eaThanks @bxff! - Fix type inference loss inArray.flattenfor complex nested structures like unions of Effects with contravariant requirements. Uses distributive indexed access (T[number][number]) in theFlattentype utility and addsconstto theflattengeneric parameter.#5970
d7e75d6Thanks @KhraksMamtsov! - fix Config.orElseIf signature#5996
4860d1eThanks @parischap! - fix Equal.equals plain object comparisons in structural modev3.19.14Compare Source
Patch Changes
488d6e8Thanks @mikearnaldi! - FixEffect.retryto respecttimes: 0option by using explicit undefined check instead of truthy check.v3.19.13Compare Source
Patch Changes
#5911
77eeb86Thanks @mattiamanzati! - Add test for ensuring typeConstructor is attached#5910
287c32cThanks @mattiamanzati! - Add typeConstructor annotation for Schemav3.19.12Compare Source
Patch Changes
a6dfca9Thanks @fubhy! - Ensureperformance.nowis only used if it's availablev3.19.11Compare Source
Patch Changes
#5888
38abd67Thanks @gcanti! - filter non-JSON values from schema examples and defaults, closes #5884Introduce JsonValue type and update JsonSchemaAnnotations to use it for
type safety. Add validation to filter invalid values (BigInt, cyclic refs)
from examples and defaults, preventing infinite recursion on cycles.
#5885
44e0b04Thanks @gcanti! - feat(JSONSchema): add missing options for target JSON Schema version in make function, closes #5883v3.19.10Compare Source
Patch Changes
#5874
bd08028Thanks @mattiamanzati! - Fix NoSuchElementException instantiation in fastPath and add corresponding test case#5878
6c5c2baThanks @Hoishin! - prevent crash from Hash and Equal with invalid Date objectv3.19.9Compare Source
Patch Changes
3f9bbfeThanks @gcanti! - Fix the arbitrary generator for BigDecimal to allow negative scales.v3.19.8Compare Source
Patch Changes
f03b8e5Thanks @lokhmakov! - Prevent multiple iterations over the same Iterable in Array.intersectionWith and Array.differenceWithv3.19.7Compare Source
Patch Changes
7ef13d3Thanks @tim-smart! - fix SqlPersistedQueue batch sizev3.19.6Compare Source
Patch Changes
af7916aThanks @tim-smart! - add RcRef.invalidate apiv3.19.5Compare Source
Patch Changes
079975cThanks @tim-smart! - backport Effect.gen optimizationv3.19.4Compare Source
Patch Changes
#5752
f445b87Thanks @janglad! - Fix Types.DeepMutable mapping over functions#5757
d2b68acThanks @tim-smart! - add experimental PartitionedSemaphore moduleA
PartitionedSemaphoreis a concurrency primitive that can be used tocontrol concurrent access to a resource across multiple partitions identified
by keys.
The total number of permits is shared across all partitions, with waiting
permits equally distributed among partitions using a round-robin strategy.
This is useful when you want to limit the total number of concurrent accesses
to a resource, while still allowing for fair distribution of access across
different partitions.
v3.19.3Compare Source
Patch Changes
7d28a90Thanks @gcanti! - Use standard formatting function in Config error messages, closes #5709v3.19.2Compare Source
Patch Changes
#5703
374f58cThanks @tim-smart! - preserve Layer.mergeAll context order#5703
374f58cThanks @tim-smart! - ensure FiberHandle.run state transition is atomicv3.19.1Compare Source
Patch Changes
#6079
4eb5c00Thanks @tim-smart! - add short circuit to fiber.await internals#6079
4eb5c00Thanks @tim-smart! - build ManagedRuntime synchronously if possible#6081
2d2bb13Thanks @tim-smart! - fix semaphore race condition where permits could be leakedv3.19.0Compare Source
Minor Changes
#5606
3863fa8Thanks @mikearnaldi! - Add Effect.fn.Return to allow typing returns on Effect.fn#5606
2a03c76Thanks @fubhy! - BackportGraphmodule updates#5606
24a1685Thanks @tim-smart! - add experimental HashRing modulePatch Changes
3c15d5fThanks @KhraksMamtsov! -Array.windowsignature has been improvedv3.18.5Compare Source
Patch Changes
#5669
a537469Thanks @fubhy! - Fix Graph.neighbors() returning self-loops in undirected graphs.Graph.neighbors() now correctly returns the other endpoint for undirected graphs instead of always returning edge.target, which caused nodes to appear as their own neighbors when queried from the target side of an edge.
#5628
52d5963Thanks @mikearnaldi! - Make sure AsEffect is computed#5671
463345dThanks @gcanti! - JSON Schema generation: addjsonSchema2020-12target and fix tuple output for:Configuration
📅 Schedule: Branch creation - "" (UTC), Automerge - "before 4am every weekday,every weekend" (UTC).
🚦 Automerge: Enabled.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR has been generated by Renovate Bot.