github Effect-TS/effect effect@4.0.6

Patch Changes

  • #9674 ce13a48 Thanks @effect-bot! - Allow Response.AllParts, Response.Part and Response.StreamPart to be called without a toolkit, decoding tool call and tool result parts for any tool name with unknown parameters and results.

  • #9696 f3bbbb4 Thanks @gcanti! - Fix Array.unionWith calling custom equivalence callbacks with values from the wrong input or in the wrong order.

  • #9511 5547315 Thanks @sledorze! - Speed up field copying in Data.Class, Data.Error, Request.Class and Persistable constructors.

  • #9743 6093cfb Thanks @effect-bot! - Fix AsyncResult equality treating unrelated Equal values with a matching tag and hash as equal.

  • #9607 30319d5 Thanks @effect-bot! - Fix Effect atoms dropping the latest exposed success when an asynchronous run fails, so an initialValue or a success published with get.setSelf remains available as the failure's previous success.

  • #9313 74a7596 Thanks @effect-bot! - Preserve Reactivity and global layers when replacing an atom runtime layer through registry initial values, so injected test layers retain shared invalidation and global services.

  • #9190 bfb32a3 Thanks @danieljvdm! - Log Atom scope finalizer failures at References.UnhandledLogLevel when an atom is disposed, using the atom runtime's logger. Interruption-only cleanup is not logged.

  • #9522 f8bf7f4 Thanks @tim-smart! - Add a skipInitialRun option to Atom.serializable and Atom.initialValue. A seeded effect or stream atom then keeps its hydrated or initial value instead of running on mount, until it is refreshed or a dependency changes. Factory get(...) calls and withReactivity keys are still tracked; dependencies read inside the effect are tracked from its first real run.

  • #9718 7f3d3df Thanks @fubhy! - Add Base64Url.encodePadded and a padding option to SchemaGetter.encodeBase64Url for consumers that require padded URL-safe Base64.

  • #9698 db1046d Thanks @effect-bot! - Encode HttpClientRequest.basicAuth credentials as UTF-8 before base64 encoding, so non-ASCII usernames and passwords no longer throw or get mangled.

  • #9326 3c4f88a Thanks @effect-bot! - Block imports of nested internal modules in the development and published package exports. These implementation details are not public APIs; public entry points remain available.

  • #9441 916e709 Thanks @fubhy! - Add the unstable Bytes module with concat, Equivalence, and Order for Uint8Array values. Stream.mkUint8Array now returns Uint8Array<ArrayBuffer>. Browser HTTP clients collect streamed request bodies without repeatedly copying accumulated bytes.

  • #9470 916f843 Thanks @tim-smart! - Reduce EventLog remote replay overhead by reusing decoded conflict payloads within each batch.

  • #9617 66ec757 Thanks @Marve10s! - Fix Effect.cachedInvalidateWithTTL caching a stale result when invalidated while the effect is running.

  • #9499 daac06f Thanks @schutzelaars! - Fix Effect.callback retaining completed suspension state, such as values received by Deferred.await or PubSub.take, until the next full GC.

  • #9727 c2552ec Thanks @Marve10s! - Fix Cause.pretty, Cause.prettyErrors, loggers and runMain overflowing the stack when an error's cause chain is cyclic.

  • #9540 b02c1cd Thanks @Marve10s! - Preserve falsy nested error causes (0, false, "", null) in Cause.prettyErrors and Cause.pretty.

  • #9418 1855f1d Thanks @jpowersdev! - Fix Channel.fromTransformStream so an upstream failure is reported when a read is pending, instead of the error raised by aborting the transform stream.

  • #9602 683ed2c Thanks @effect-bot! - Preserve Prompt.FilePart byte and URL data when chat history is exported or persisted as JSON. Encoding now produces tagged { _tag: "Uint8Array", base64 } and { _tag: "URL", href } objects that decode back to their original types, and Chat.Persistence reports undecodable stored history as a PersistenceError instead of a defect.

  • #9238 ac68940 Thanks @effect-bot! - Fix child-process cleanup without forceKillAfter to give remaining process-group members up to one second to exit after the leader exits. Clarify that waiting for the leader has no time limit and never escalates to SIGKILL when forceKillAfter is omitted.

  • #9611 22a8401 Thanks @itisrmk! - Fix Chunk.get and Chunk.getUnsafe throwing on in-range fractional indexes of one-element chunks, and treat NaN and infinite indexes as out of bounds.

  • #9287 c53c194 Thanks @devangpratap! - Fix the CLI lexer treating a short option cluster with an inline value, such as -vn=3, as one unknown flag instead of -v -n=3. A single dash followed by a multi-character name, such as -num=3, is now also split into separate flags; use --num=3 instead.

  • #9655 ca6d1cc Thanks @effect-bot! - Add Command.validate and CliError.ValidationError to the unstable CLI. validate checks the parsed input before the handler runs, for rules such as mutually exclusive flags. A failure is shown with the command help, like any parse error.

  • #9650 47940c5 Thanks @effect-bot! - Add Flag.withNegation and Flag.withoutNegation (with Param counterparts) to rename or remove the --no-<name> form of boolean flags in parsing and shell completions.

  • #9285 e8b24ef Thanks @okarin1511! - Fix the CLI treating --=value as a flag with an empty name. The argument is now passed through unchanged as a plain value, so it no longer fails with Unrecognized flag: --.

  • #9666 2e8aae0 Thanks @effect-bot! - Allow Command.withExamples to take a function that receives { commandPath }, so help examples match wherever a command is mounted.

  • #8350 ad7497b Thanks @ArjunCodess! - Add a TerminalCapabilities reference and layer to effect/cli; built-in Command help, version, and error output now follows it, so FORCE_COLOR enables color off a TTY and TERM=dumb disables it.

  • #9248 7f504a3 Thanks @bezff! - Fix the ClickHouse migrator creating its ledger with SQLite syntax and wrapping the run in BEGIN TRANSACTION.

  • #9395 99e365d Thanks @effect-bot! - Prevent Effect.forkIn and Effect.forkScoped from running work in an already-closed scope, even when startImmediately or uninterruptible is enabled. They now return an interrupted fiber without executing the supplied effect.

  • #9407 954067d Thanks @effect-bot! - Log and retry failures when scheduling the initial ClusterCron run so transient failures no longer leave the cron stopped.

  • #9677 3e1a035 Thanks @effect-bot! - Fix ClusterCron with calculateNextRunFromPrevious: true not resuming after its pending run was lost.

    In this mode every run is now processed by a single executor entity per cron job, so a restart no longer starts a second chain: runs never overlap and missed runs are caught up in order. Pending runs scheduled by earlier releases join the executor's chain. As a result, Entity.CurrentAddress inside execute no longer identifies the scheduled time; use the new ClusterCron.CurrentScheduledTime service instead, which is available in both modes.

    Failed runs are still retried until they succeed or are older than skipIfOlderThan, but in this mode a failing run now blocks later runs while it is retried, instead of later runs executing alongside it.

  • #9577 41a1fe7 Thanks @tim-smart! - ClusterMetrics.entities now reads the active entity count when metrics are snapshotted, instead of being updated by a loop once a second. The series is recorded in the MetricRegistry of the entity manager's context and removed when the entity manager shuts down.

  • #9475 bcb3a86 Thanks @effect-bot! - Warn when a forced cluster shard release remains pending beyond shardLockExpiration, including the affected shards and pending entity types and singletons. Release failures now emit rate-limited warnings while preserving the requirement that teardown and lock release finish before reacquisition.

  • #9336 739d3d1 Thanks @effect-bot! - Answer fresh, locally owned persisted cluster requests from a reply handler registered before the request is saved, instead of reading every local reply back from storage or polling for it. Duplicates and streams still read their replies from storage, and a dropped reply handler now falls back to storage immediately instead of waiting for the next poll. MessageStorage.registerReplyHandler must register its handler as soon as the effect starts.

  • #9732 ed4da35 Thanks @effect-bot! - Read persisted cluster messages from storage as soon as their entity type registers, instead of waiting for the next entityMessagePollInterval.

  • #9716 3d84e19 Thanks @tim-smart! - Fix cluster shard releases waiting out entityTerminationTimeout when the shard moves while an entity is waiting to restart after a defect.

  • #9256 cc00906 Thanks @Tanner-Scadden! - Add ClusterMetrics.shardReleaseDuration, a timer recording how long each completed shard release takes.

  • #9244 09ba1f5 Thanks @effect-bot! - Keep the cluster shards gauge accurate when shards are released or shard locks are lost.

  • #9513 9ff1a73 Thanks @effect-bot! - Repeat the stalled forced shard release warning every max(shardLockExpiration, 30 seconds) while the release stays pending, and add the ClusterMetrics.shardsReleasing gauge (effect_cluster_shards_releasing) counting the shards a runner is still releasing.

  • #9443 06bc532 Thanks @effect-bot! - Fix a Sharding startup race that could access singleton synchronization before initialization, causing a ReferenceError and delaying shutdown.

  • #6441 97bfd84 Thanks @sbking! - Fix SQL Server support in cluster SqlMessageStorage. Message claims and duplicate checks now use valid T-SQL. The SQL Server tables use filtered unique indexes instead of nullable UNIQUE constraints, and NVARCHAR(MAX) instead of TEXT, so keyless messages and chunked replies can be stored.

  • #9645 25efaef Thanks @effect-bot! - Fix ClusterWorkflowEngine losing a Workflow.interrupt sent while a run was still saving its Suspended reply.

  • #9394 c10335b Thanks @effect-bot! - Fix suspended cluster workflow scopes not being released when an execution completes. Earlier runs retain their resources through suspension and release them on completion or owner teardown, without running durable workflow finalizers on abandonment.

  • #9490 a808972 Thanks @tim-smart! - Remove regex lookbehind from ConfigProvider variable expansion to prevent module-loading syntax errors on Safari versions before 16.4, while preserving interpolation and escaping behavior.

  • #9621 20e844c Thanks @Marve10s! - Fix Config.schema dropping record entries for numeric key schemas such as Schema.Int or Schema.Number.

  • #9539 b9f73f3 Thanks @Marve10s! - Fix Cron.prev skipping an occurrence earlier in the same second as the input.

  • #9719 5739878 Thanks @Marve10s! - Fix DateTime.formatIsoDate and DateTime.formatIsoDateUtc dropping the day for years before 0000 or after 9999.

  • #9654 28acdf3 Thanks @okarin1511! - Fix DateTime.zoneFromString rejecting "GMT" and accept compact UTC offsets without colon

  • #9582 59b6396 Thanks @itisrmk! - Accept lowercase z and gmt zone designators in DateTime.make and DateTime.makeUnsafe. These strings previously had a second Z appended and were rejected.

  • #9725 0bccc9c Thanks @Marve10s! - Fix DateTime values in named time zones turning year zero and BCE dates into CE years.

  • #9437 fed70de Thanks @effect-bot! - Add DecisionModel.decideSettled to retain valid answers alongside per-decision Result failures (Missing, Refused, NoDistribution, or Invalid). Provider failures still fail the effect; decide remains all-or-nothing.

    OpenRouter now passes missing distributions to core validation. OpenAI reports refusals per decision and wrong-kind score answers as invalid rather than missing.

    Update hand-built services to implement decideSettled, handle optional provider probabilities and refusal answers, and use settled outcomes instead of the removed OpenAiContentPolicyMetadata and metadata.openai.refusedDecisions.

  • #9422 82648a2 Thanks @candrewlee14! - DecisionModel.decide now returns the response id, the modelId that answered and provider metadata. OpenRouterDecisionModel reports cost and the serving provider under metadata.openrouter.

  • #9436 afb5f32 Thanks @jpowersdev! - Fix Channel.decodeText and Stream.decodeText dropping incomplete trailing characters. Flush buffered bytes on normal completion, emitting U+FFFD by default or a defect with fatal: true.

  • #9325 28813f5 Thanks @effect-bot! - Rerun reactive queries only once per invalidation or batch flush when multiple keys match the same query, avoiding duplicate query results and atom refreshes.

  • #9692 0fae934 Thanks @effect-bot! - Destroy the AsyncResource a fiber captures when it yields once the fiber resumes, so tools like vitest's detectAsyncLeaks no longer report effect/Fiber leaks.

  • #9410 f260830 Thanks @effect-bot! - Send an initial DevTools Ping immediately so a server that only responds to client messages can complete startup without waiting for the connection timeout.

  • #9329 19b63eb Thanks @effect-bot! - Include disposal library types in the Effect and ManagedRuntime declarations so non-Node consumers can type-check imports without explicitly enabling ESNext.Disposable.

  • #9258 14db221 Thanks @devangpratap! - Fix Duration.fromInputUnsafe losing nanosecond precision for large integer tuple and object inputs.

  • #9506 679f956 Thanks @tim-smart! - Use Effect.fnUntraced for internal functions that returned Effect.gen.

  • #9604 b72707c Thanks @effect-bot! - Document how Effect.result and Effect.option handle causes that mix typed errors with interruptions or defects, and the parameter-count rule that decides whether Effect.promise, Effect.tryPromise and Effect.callback provide an AbortSignal.

  • #9552 44c8c1d Thanks @wmaurer! - Add an optional batchKey to EmbeddingModel.make to group concurrent embed calls by provider-relevant context. OpenAI and OpenAI-compatible providers now separate batches with different configuration overrides or client transforms. Undeclared context, such as per-call FetchHttpClient.RequestInit, still uses the first caller's value.

  • #9148 1e7909b Thanks @fubhy! - Add effect/encoding/Tar for streaming tar decoding and encoding. Decode v7, USTAR, PAX and non-sparse GNU archives; encode USTAR with PAX headers as needed. Entry constructors use reproducible defaults.

  • #9420 0611a65 Thanks @jpowersdev! - Add the experimental Xml module to effect/encoding for streaming XML 1.0 decoding and encoding over text or UTF-8 bytes. Decoding checks well-formedness, enforces size and depth limits, and never reads external resources or expands DOCTYPE entities. elements collects repeated elements, such as feed items, into trees.

  • #9419 2fadc65 Thanks @jpowersdev! - Add experimental effect/encoding/Zip for streaming zip encoding and decoding. Encode and decode stored and deflated entries, with ZIP64 when needed; decoding reads entries as the archive arrives and checks each body's CRC-32 and sizes. This API may receive breaking changes in patch releases.

  • #9578 feb6ce5 Thanks @tim-smart! - Add the always-on ClusterMetrics.entityMailboxSizeMax gauge, which reports the largest mailbox size among the resident entities of each type, read when metrics are snapshotted.

  • #9572 5a2ed53 Thanks @tim-smart! - Add the unstable Metric.remove, Metric.removeUnsafe and Metric.registerUnsafe APIs for removing series and registering series whose value is read on snapshot. The OTLP and OpenTelemetry exporters now drop delta state for series that are no longer registered. Add the opt-in ClusterMetrics.entityMailboxSize gauge, enabled with ShardingConfig.entityMailboxMetrics or the mailboxMetrics entity option, which reports the mailbox size of each resident entity and removes the series when the entity is released.

  • #9721 c8d26a4 Thanks @Marve10s! - Fix Equivalence.combineAll losing its criteria after the first comparison when given a one-shot iterable.

  • #9482 0c8b446 Thanks @tim-smart! - Track the source remote of each imported entry in SqlEventJournal and the IndexedDB EventJournal, instead of one row per entry per remote.

    • Storage grows with entries rather than entries times remotes. An imported entry is still relayed to other remotes and never uploaded back to its source.
    • Journals from earlier releases migrate on first open: SQL drops the remotes table and IndexedDB upgrades to version 2. SQL needs a writable connection.
    • An entry acknowledged by a remote, or known to several remotes before migrating, may be uploaded to a remote once more. The server treats it as a duplicate.
  • #9448 05c3409 Thanks @tim-smart! - Fix the memory and IndexedDB EventJournal advancing a remote's sequence for a batch whose callback failed, and the memory journal missing conflicts while a clock-skewed local write leaves it unordered.

  • #9479 b04191b Thanks @tim-smart! - Encrypted event log replication now encrypts entries in batches of up to 100 entries or about 256 KB of payload, one AES-GCM call per batch, and encrypted servers store and stream those batches. Each batch authenticates its store id and plaintext entry ids. This changes the encrypted protocol, APIs and server tables without migration: upgrade encrypted clients and servers together, and start encrypted servers on fresh storage because existing per-entry rows are not read.

    Breaking changes

    • EncryptedEntry and EncryptedRemoteEntry are replaced by EncryptedBatch and EncryptedRemoteBatch, and WriteEntries.encryptedEntries becomes batches.
    • EventLogEncryption.encrypt and decrypt take the store id and work on batches, and the decodeChanges option of EventLogRemote.makeWith receives the store id.
    • EventLogServerEncrypted.Storage.write and changes use batches, PersistedEntry is removed, and SqlEventLogServerEncrypted no longer accepts insertBatchSize.

    Event journals now keep the first copy of an entry that is repeated within one remote delivery, and SqlEventJournal advances an entry's remote sequence when it arrives again later, so nextRemoteSequence passes it.

  • #9448 05c3409 Thanks @tim-smart! - EventJournal.writeFromRemote now hands its effect the whole batch with conflicts read up front, and EventLog.HandlerTransaction runs a replayed batch's handlers in one transaction.

  • #9445 4067e64 Thanks @tim-smart! - Flush EventLog reactivity invalidations once per replayed remote batch instead of once per entry.

  • #9471 e04563d Thanks @tim-smart! - Speed up UUID formatting and memoize EventJournal.Entry.idString.

  • #9491 02d7fc5 Thanks @tim-smart! - Add EventLog.groupBatchCompaction for compaction across primary keys, with explicit forwarding or dropping of undecodable entries. Both compaction APIs now provide forward(entry) to preserve entries unchanged at their original batch positions. Align server compaction output ordering with client replay.

  • #9521 561d2a1 Thanks @tim-smart! - Generate EventLog entry ids from a hybrid logical clock, so a local write always sorts after every entry committed to its journal, even when the local clock is behind.

    • The memory, IndexedDB and SQL journals generate each local id after the latest id in their store, without adopting it into the process's id sequence. The IndexedDB and SQL journals read it from the store, because other tabs or processes sharing the store keep their own sequence. This adds one read per writeMany. Inside an enclosing SQL transaction, local ids also sort after its uncommitted rows, and a rollback leaves nothing behind.
    • Clocks that run ahead are not clamped. A warning is logged when an imported id is more than 24 hours ahead of the local clock, read from the Clock service.
    • If a store holds an id at the end of the UUID v7 timestamp range, local writes to that store fail with an EventJournalError instead of committing ids that sort before it. makeEntryIdUnsafe throws a RangeError once its own sequence passes the range. Ids created with an explicit msecs still clamp.
  • #9520 8fe2dcc Thanks @tim-smart! - Order EventLog conflicts by entry id in every journal and the unencrypted server, so replicas converge. A conflict is now a stored entry for the same event and primary key with a strictly greater id, remote batches replay in id order after compaction, and compaction replacements are ordered and conflict-checked by the source entry they are anchored to.

  • #9507 a8086fa Thanks @tim-smart! - Fix event log server compaction failing with an argument-limit error on large groups, and stop scanning the whole in-memory journal on replay.

  • #9444 88a33b4 Thanks @tim-smart! - Decode EventJournal entry timestamps without allocating, and merge remote imports into the in-memory journal instead of re-sorting it on every batch.

  • #9508 e77372a Thanks @tim-smart! - Send chunked event-log remote writes with up to four parts in flight instead of one at a time.

  • #9480 3dd4388 Thanks @tim-smart! - Reduce per-entry overhead in EventLog remote replay by caching payload decoders per handler and merging handler contexts once per batch.

  • #9523 ba2b00c Thanks @tim-smart! - Add the unstable effect/eventlog/EventRow module for convergent row updates with set, patch and remove events. It supports single-field, composite and derived keys, per-field conflict resolution through typed storage callbacks, and compaction that drops superseded entries. The constructors return { event, payload }, which spreads into EventLog.write and works as a writeMany item or client argument.

    Breaking: the function returned by EventLog.makeClient now takes one { event, payload } object instead of positional event and payload arguments.

  • #9224 a049d4a Thanks @effect-bot! - Allow event-log authentication to retry failed session-auth binding lookups after storage recovers, while continuing to cache successful lookups.

  • #9478 84aeede Thanks @tim-smart! - Skip decrypting remote changes the local event journal already stores, and pass entry bytes to WebCrypto without copying them. EventJournal gains a required entriesById method, which custom journal implementations must add.

  • #9526 43e5e19 Thanks @tim-smart! - Fail and retry an EventLog remote replay batch when an entry fails to decode or its handler fails, instead of committing the entry without applying it.

  • #9473 77bbf16 Thanks @tim-smart! - Speed up decoding of eventlog entries and unencrypted write frames by building instances from already validated fields. The wire format is unchanged.

  • #9477 6af3a47 Thanks @tim-smart! - Acknowledge event log writes instead of echoing them to the writing connection. Breaking protocol change: upgrade clients and servers together; mixed versions are unsupported.

    Custom implementations must add EventJournal.writeRemoteAcks, add encrypted Storage.entrySequences (the sequence each entry was first stored at, used to acknowledge skipped batches), and return RemoteEntry values from unencrypted Storage.entriesAfter. Set firstSequence when sequences start above 0. Custom remotes can still return void from write to confirm uploads through the change stream.

    SqlEventLogServerEncrypted adds a sequence column to its entry id tables, so encrypted servers still need fresh storage.

  • #9452 aac8d21 Thanks @tim-smart! - Add EventLog.writeMany and EventJournal.writeMany, which write a batch of local events under one lock, one handler transaction and one journal commit. Clock-based entry ids are now strictly ascending within a process.

  • #9690 84c8dc4 Thanks @effect-bot! - Document that HttpClient.followRedirects needs FetchHttpClient.RequestInit with { redirect: "manual" } when used with FetchHttpClient.

  • #9603 78d1988 Thanks @effect-bot! - Wait for replaced FiberMap and FiberHandle fibers to finish their interruption cleanup before the owning scope finishes closing.

  • #9729 5676a2a Thanks @Marve10s! - Fix Fiber.runIn and Effect.forkIn hanging when the attached fiber closes its own scope.

  • #9433 4b437bf Thanks @effect-bot! - Give defects precedence when the runtime combines a typed failure with a defect, so typed-error recovery can no longer swallow a crashing finalizer or a dying concurrent sibling.

  • #9290 1af11fd Thanks @effect-bot! - Fix AtomHttpApi query response mode inference so literal and union response modes are accepted and produce the corresponding success types.

  • #9524 716f8df Thanks @tim-smart! - Fix Atom.Serializable encode and decode types to use Schema.Json, matching the JSON codec used at runtime.

  • #9404 ee27718 Thanks @effect-bot! - Fix SchemaGetter.BigInt to return SchemaIssue.InvalidValue for inputs that cannot be converted to a bigint. This also makes SchemaTransformation.bigintFromString and Snowflake.SnowflakeFromString reject invalid strings with typed schema errors instead of defects.

  • #9411 4d86d1b Thanks @effect-bot! - Start Stream.callback and Channel.callback registration before the first pull, so synchronous listener setup no longer misses early events. Browser HTTP response stream listeners now stay installed until the stream is finalized.

  • #9323 5462ed7 Thanks @effect-bot! - Fix Cause runtime JSON and inspection output to use reasons instead of failures, including within failed Exits. Schema validation error paths now also use reasons; Cause and Exit schema encodings are unchanged.

  • #9400 658837c Thanks @effect-bot! - Preserve input order in concurrent Effect.filter results and record Effect.all keys, including mode: "result".

  • #9226 00261cc Thanks @effect-bot! - Reconnect the DevTools client after startup connection failures or dropped connections, and log connection failures at Debug level. Stop failed or pending connections on shutdown while preserving queued telemetry flushing for healthy connections.

  • #9261 7cccb93 Thanks @effect-bot! - Preserve nanosecond precision when parsing large decimal Duration strings in units from milliseconds through weeks, and avoid intermediate overflow when converting large finite durations to numeric units.

  • #9403 7c98228 Thanks @effect-bot! - Fix Effect.effectify discarding synchronous throws after a synchronous callback. These throws now become defects by default, or typed failures when onSyncError is provided.

  • #9469 5a8e248 Thanks @tim-smart! - Fix encrypted SQL event-log storage to return and publish only newly inserted entries, avoiding duplicate broadcasts when clients re-upload a batch.

  • #9227 8037a65 Thanks @effect-bot! - Preserve undecodable event payloads unchanged during group compaction so they do not stall replication or prevent valid events from being compacted.

  • #9393 25912db Thanks @effect-bot! - Preserve remote replay order for unaffected events when compaction is enabled, and replay replacements in compactor write order at their source position.

  • #9457 7f32606 Thanks @tim-smart! - Fix IndexedDB event journal uploads resending entries the remote has not echoed back. Upload progress is now checkpointed by insertion order, so entries imported later with older ids are still forwarded. Existing databases upgrade automatically; entries the remote has not confirmed may be uploaded once more after the upgrade.

  • #9239 0386f88 Thanks @effect-bot! - Prevent WorkflowEngine.layerMemory from running duplicate compensations after workflow replays. Each replay now starts with a fresh workflow scope, as with the cluster engine, so only the final run's compensations run.

    Finalizers registered in runs that suspended still run once the execution finishes, in the same order, but they now observe Exit.void instead of the execution's final exit.

  • #9237 403298a Thanks @effect-bot! - Align safe interruption in WorkflowEngine.layerMemory with the cluster engine: workflows that finish without suspending now complete normally instead of being interrupted and running compensation. Preserve unsafe interruption across suspended replays.

  • #9203 5a3ebc0 Thanks @effect-bot! - Allow absolute HTTP URLs in opaque-origin documents, such as sandboxed srcdoc iframes, by ignoring an invalid inferred base URL. Preserve relative URL resolution when the document provides a valid base.

  • #9390 fac2191 Thanks @effect-bot! - Fix rate limiter delay mode to charge oversized token requests against the shared store, preserving queue ordering and delay/reset timing for fixed-window and token-bucket limits.

  • #9600 fdb12dc Thanks @effect-bot! - Fix RequestResolver.persisted to persist only refresh results when using staleWhileRevalidate. Whole-batch refresh failures now replace stale values, while refreshes that complete no entries leave the original expiry unchanged.

  • #9519 97909b8 Thanks @tim-smart! - Fix dependency tracking for hydrated plain serializable atoms. They now build on first read or mount like wrapped atoms, so hydrated effect and stream atoms run on mount after SSR instead of skipping that initial run.

  • #9241 c3983f4 Thanks @effect-bot! - Preserve fractional token counts in the Redis fixed-window rate limiter so remaining capacity, excess-request rejection, and delay reservations are calculated correctly.

  • #9568 3a5e65e Thanks @tim-smart! - Run each RequestResolver.fromEffect entry with its own caller context, without inheriting another caller's services.

  • #9386 8b40fbc Thanks @effect-bot! - Fix Resource.auto to wait for the first scheduled run before refreshing, avoiding an extra acquisition immediately after construction.

  • #9379 3f3e119 Thanks @boozedog! - Fix TestSchema round-trip assertions to use schema equivalence, avoiding false failures for object prototypes and signed zeros.

  • #9317 7c7b8ed Thanks @effect-bot! - Fix hooks and parse options being ignored or reused across calls to Schema.toStandardSchemaV1. Both Schema.toStandardSchemaV1 and Schema.toStandardJSONSchemaV1 now return fresh shallow copies and compose in either order. Access statics that use this.#field through the original class.

  • #9383 d4f71bc Thanks @effect-bot! - Fix unordered Stream.mapEffect, Stream.flattenEffect, and Stream.bindEffect dropping in-flight results when concurrency is Infinity or an oversized positive number. These concurrency values now use the same safe bound as "unbounded", so successful completion waits for pending effects.

  • #9397 c66241e Thanks @effect-bot! - Invalidate atom Stream mutation reactivity keys only after successful completion, rather than on failure, defects, interruption, or replacement by a newer write.

  • #9225 f0e941e Thanks @effect-bot! - Fix unencrypted event-log replication to acknowledge already committed entries without re-running their handlers, even when storage order differs from timestamp order or entries share a timestamp. Exclude older entries from handler conflicts regardless of storage order.

  • #9466 5f8a6e5 Thanks @effect-bot! - Prevent unhandled errors from Node ws WebSockets when a pending handshake is closed after an open timeout or fiber interruption.

  • #9549 2800a09 Thanks @effect-bot! - Flatten redundant nested anyOf alternatives in Schema.toJsonSchemaDocument output while preserving annotations, references, and oneOf boundaries.

  • #9319 e9749b0 Thanks @effect-bot! - Prevent atom hydration from replacing newer AsyncResult values with older dehydrated state.

  • #9468 eaef09c Thanks @tim-smart! - Fix EventLog remote reconnects resuming from the sequence captured at startup instead of the journal's current sequence, which replayed already-written entries and re-triggered reactivity invalidations.

  • #9569 a3c56e5 Thanks @tim-smart! - Pre-response handlers and HttpMiddleware.withLoggerDisabled now apply to exactly one server request. HttpApiTest no longer accumulates handlers across retry attempts that reuse the same client request. HttpEffect.appendPreResponseHandlerUnsafe now takes the fiber context instead of the request.

  • #9385 bb61152 Thanks @effect-bot! - Restart the random sequence from the seed on each evaluation of an effect wrapped with Random.withSeed. This also ensures repeated evaluations of TestCrypto.make and independent builds of TestCrypto.layer start fresh deterministic sequences.

  • #9240 e9c842b Thanks @effect-bot! - Fix SQL persistence reads to check expiry on every execution, so reused get and getMany effects stop returning expired entries in both SQL layouts.

  • #9401 6d8c8e2 Thanks @effect-bot! - Apply GraphQL resolver batch limits independently per protocol URL and batchKey, so interleaved lookups for different tenants or servers do not fragment each other's batches. GraphQLResolver.request resolves each lookup's URL in the calling fiber, so lookups that rely on a Context.Reference default are no longer routed with another lookup's value.

  • #9536 1f28187 Thanks @schutzelaars! - Fix HashMap.set discarding equal-but-distinct replacement values.

  • #9548 0b9842b Thanks @effect-bot! - Load the bundled Scalar and Swagger UI assets when HttpApiScalar.layer or HttpApiSwagger.layer is built instead of when effect/http-api is imported. Importing the module no longer evaluates about 5 MB of embedded JavaScript and CSS.

  • #9575 c29ddd8 Thanks @tim-smart! - Add streaming request payloads to HttpApi. An endpoint can declare HttpApiSchema.StreamUint8Array or the new HttpApiSchema.StreamNdjson({ schema }) as its payload, and the handler receives a lazy Stream that reads the body as it pulls. Bad NDJSON lines fail the stream with HttpApiSchemaError (400). The new maxBytes and maxElementBytes limits fail it with the new HttpApiPayloadTooLarge (413), and a content-length over maxBytes is rejected before the handler runs. StreamNdjson also works as a success response.

    HttpApiClient sends a Stream payload without buffering it and infers the stream's requirements. HttpApiTest passes stream payloads through unbuffered. OpenApi.fromApi marks streaming request bodies with x-effect-stream, and openapi-generator maps them, and NDJSON or JSON Lines bodies with an itemSchema, back to StreamUint8Array and StreamNdjson.

    The Node server drains up to 256 KiB of a body the handler left unread, then closes the connection, instead of reading the whole upload or leaving the socket stuck.

  • #9563 84c3405 Thanks @tim-smart! - Allow undeclared HttpServerRespondable errors in HttpApiBuilder to render their own responses when error schema encoding fails. Oversized multipart streaming uploads now return 413 instead of 500, while declared error schemas retain precedence.

  • 3934c0c Thanks @tim-smart! - Return 413 instead of 400 when buffered or decompressed request bodies exceed their size limit, while preserving 400 for other parse failures. Node HTTP servers drain oversized bodies so the response can reach the client without destroying the socket. Node stream readers expose MaxBytesError and an optional destroyOnOverflow setting; their default destruction behavior is unchanged.

  • #9728 048e7c8 Thanks @Marve10s! - Fix HttpClient.followRedirects dying on an invalid Location header; it now returns the redirect response unchanged.

  • #9673 1121334 Thanks @effect-bot! - Add HttpClientResponse.toWeb, which returns the original Web Response of a fetch-backed response as Some, and None for other backends. The original body keeps runtime capabilities such as workerd's known length, so it can be written to Cloudflare R2 without copying.

  • #9339 9a680d6 Thanks @fubhy! - Add raw HTTP/1.1 upgrades through HttpClientRequest.upgrade, HttpClientResponse.upgrade, the Node HTTP server, and HttpApiSchema.Upgrade. Node clients expose the upgraded connection as a Socket; HttpApi clients return { headers, socket } and OpenAPI documents the 101 response.

    Custom HttpClientResponse implementations must add upgrade. Fetch and XMLHttpRequest reject upgrade requests with a TransportError before anything is sent; Bun and Deno servers still support only WebSocket upgrades.

  • #9709 85e2aee Thanks @tim-smart! - Add typed HTTP date and Retry-After header values to Headers, and parse them consistently across the HTTP client, OTLP exporter, GraphQL client, AI clients and static server.

    • Headers.parseHttpDate / Headers.formatHttpDate read all three RFC 9110 date formats as UTC, whatever the process time zone, and emit IMF-fixdate.
    • Headers.parseRetryAfter, Headers.formatRetryAfter and Headers.retryAfterDelay accept whole non-negative seconds of any size, read exactly, or an HTTP date, and the delay is never negative. HTTP dates accept the 23:59:60 leap second, read as the following second.
    • Headers.RetryAfter holds either a Duration (RetryAfterDuration) or a DateTime.Utc (RetryAfterDateTime). Headers.retryAfterDuration builds the first from any Duration.Input: infinite durations throw, finite negative ones become zero, and fractional seconds are rounded up when formatted.
    • Parse failures are reported as Headers.HeaderParseError.
    • Schema.DateTimeUtcFromHttpDate and Schema.RetryAfterFromString expose the same parsing as string codecs for HTTP API headers.
    • Invalid Retry-After values such as -5, 1.5, 1e3 or Infinity are now ignored everywhere. HttpClient.retryTransient and HttpClient.withRateLimiter no longer honour fractional seconds, and the AI clients no longer produce negative or infinite retryAfter durations.
    • HttpStaticServer reads If-Modified-Since and Last-Modified as UTC; asctime dates were previously shifted by the process time zone.
  • #9293 34ec440 Thanks @bezff! - Keep HTTP message bodies unread during inspection.

  • #8691 343a149 Thanks @Marve10s! - Document how to define HttpMiddleware.make middleware that preserves app error and service types, including with Effect.fn.

  • #9447 915117b Thanks @bezff! - Describe HttpRouter route misses caused by a path parameter longer than maxParamLength.

  • #9417 7f823c1 Thanks @fubhy! - Fix HTTP response framing: omit bodies for 204, 205 and 304, and remove content-length for 204 and 205. Node now aborts responses whose bodies do not match content-length. Deno and Bun preserve raw Web Response objects when merging headers, and Deno preserves their status and headers for HEAD requests.

  • #9415 6e614e6 Thanks @fubhy! - - Fix HTTPS detection in HttpServerRequest.toURL and tracing. An exact http or https in x-forwarded-proto takes precedence; otherwise, infer HTTPS from originalUrl. Paths starting with // preserve the request host.

    • Node server requests now expose an absolute originalUrl when a Host header is present, fixing HttpMiddleware.searchParamsParser. Use url instead of originalUrl to read the path. Hostless requests are unchanged.
    • For absolute-form Node requests, derive url and headers.host from the request target, ignoring a conflicting Host header.
  • #9726 9990b39 Thanks @Marve10s! - Remove path parameter regex constraints from HttpApiClient URLs and OpenApi paths.

  • #6837 22bf781 Thanks @aryasaatvik! - Fix HttpApiSchema.status forking named schemas, so a schema reused across response statuses emits a single OpenAPI component.

  • #9518 41f08b7 Thanks @pujitha24! - Fix Hydration.hydrate to notify existing atom subscribers immediately instead of on the next read.

  • #9476 e8482ca Thanks @tim-smart! - Index duplicate and conflict detection in the unencrypted event-log server once per incoming batch instead of rescanning stored history for every entry. EventLogServerUnencrypted.Storage.entriesAfter now receives the batch as an optional third argument. The built-in storages use it to read only matching entries, and SQL storage creates a <prefix>_event_key_idx index on startup for SQLite, Postgres and MySQL. Custom storages that ignore the argument keep working.

  • #9474 5ae85fa Thanks @tim-smart! - Speed up conflict detection in the IndexedDB event journal. Remote writes now read only the stored entries that share an event and primary key with the batch, through a new [event, primaryKey, id] index, and no longer re-validate stored rows. Existing databases upgrade to version 3, which only adds the index.

  • #9609 c477a0a Thanks @itisrmk! - Fix Ini.parse dropping a trailing backslash from unquoted keys, values and section names.

  • #9267 8fbb39e Thanks @effect-bot! - Isolate AtomHttpApi and AtomRpc mutations by service ID so services sharing endpoint names or RPC tags invoke their own clients with their own arguments.

  • #9493 1c70828 Thanks @Marve10s! - Fix Iterable.dedupeAdjacent and Iterable.dedupeAdjacentWith overflowing the stack on long runs of equal elements.

  • #9431 8207d1e Thanks @jpowersdev! - Add JsonArray to effect/encoding. Its decoders stream the elements of one JSON array, at the root or selected by a JSON Pointer, without buffering the whole document; its encoders write a stream of values as one JSON array.

  • #9247 7886b84 Thanks @gcanti! - Add includeAnnotationKey to SchemaRepresentation.fromJsonSchemaDocument and fromJsonSchemaMultiDocument to preserve selected custom JSON metadata as schema annotations. Selected annotations survive normalization of retained values and can be re-exported with the exporter's matching option. Discarded annotated references no longer force resolution, while surviving annotated circular aliases are consistently rejected, including annotations introduced through allOf.

  • #9252 4839c60 Thanks @nikelborm! - Made catchIf not put Refinement function arg as generic Err param

  • #9324 2595d83 Thanks @effect-bot! - Fix Effect.fromOption to evaluate a custom onNone error factory on each execution rather than during construction. Exceptions thrown by the factory now become runtime defects.

  • #9723 f5ae278 Thanks @Marve10s! - Fix ManagedRuntime interrupting requests that dispose it before their first async step.

  • #8862 7a8ce00 Thanks @lloydrichards! - Add the experimental McpClient and McpClientError modules, a scoped MCP client for the 2025-11-25 and 2026-07-28 protocols over stdio or Streamable HTTP. It discovers tools, prompts and resources, calls tools with optional schema decoding, and exposes discovered tools to a language model through McpClient.toolkit.

    MCP schemas now check _meta, structuredContent, capability records and other JSON-valued fields only one level deep when decoding, and type them as unknown or Readonly<Record<string, unknown>>. McpServer still rejects non-JSON tool results when it serializes 2026-07-28 responses.

  • #8553 688d302 Thanks @Floriferous! - Stop publishing a non-recursive MCP tool schema root in $defs as well as inline, so tools/list no longer sends it twice. A custom toJsonSchema $ref into the root's own definition, such as #/$defs/Note/properties/title when Note is the tool schema, no longer resolves.

  • #9634 c7072e4 Thanks @tim-smart! - Memoize composed layers by identity, as in v3. Layer.provide, Layer.provideMerge and Layer.mergeAll (and the operators built on them) now check the MemoMap, so a composed layer referenced from several parents is built once per memo map instead of once per path. Deeply shared .Default-style layers no longer rebuild their whole chain on every path, which could leave millions of scopes open at startup.

    A composed layer that is shared now shares everything inside it, including dependencies wrapped in Layer.fresh. Wrap the composed layer itself in Layer.fresh to get a separate copy. As with leaf layers, a shared build runs on the first requester's fiber, so if that fiber is interrupted, every requester waiting on the shared build sees the interruption.

  • #9234 425cedb Thanks @effect-bot! - Fix WorkflowEngine.layerMemory so interruptUnsafe completes running and suspended workflows with an interrupted exit without requiring an external wake.

  • #9598 88bc680 Thanks @effect-bot! - Fail SQL migrations with a typed MigrationError instead of a defect, so Effect.catchTag("MigrationError") and retries can handle them.

  • #9668 268e09c Thanks @effect-bot! - Fix Model.Class and VariantSchema class .extend to accept variant fields and regenerate every variant schema from the merged fields.

  • #9715 7e94505 Thanks @tim-smart! - Fix SQL Server deadlocks in the SQL PersistedQueue store. Offers no longer use a serializable MERGE, and claims skip rows locked by other claims or settlements.

  • #9699 afa5da3 Thanks @effect-bot! - Fix MultipartParser handling of Content-Disposition: decode RFC 8187 filename* values with an optional language tag in UTF-8 or ISO-8859-1, and report malformed disposition headers as InvalidDisposition instead of silently producing a nameless field.

  • #9575 c29ddd8 Thanks @tim-smart! - Ndjson byte decoders split lines on raw bytes and decode each line as strict UTF-8. They accept \n, \r\n and a bare \r, skip a leading BOM, and take a maxLineBytes option. NdjsonError now has a reason ("InvalidJson", "InvalidUtf8" or "LineTooLarge") and an unterminated flag. Byte and string decoders emit the lines before the first bad line, then fail.

  • #9430 48102ac Thanks @effect-bot! - Add non-retryable AiError.InvalidResponseError for provider response schema and SSE decoding failures, with optional HTTP context; model-generated output validation remains retryable. Update exhaustive matches on AiErrorReason to handle the new tag, and update serialized-error consumers to accept it.

  • #9270 463eca3 Thanks @Marve10s! - Fix Number.nextPow2 returning the wrong power of two for some large inputs, such as 2 ** 29 and 2 ** 52 + 1.

  • #9694 e7162ea Thanks @effect-bot! - Render bare numbers with a standard leading integer check as Schema.Int, preserving custom annotations and other checks. Only emit the decodeError helper in generated HTTP clients when an operation has error responses.

  • #7340 95752db Thanks @astahmer! - Add an includeAnnotationKey option to OpenApi.fromApi that selects custom schema annotation keys, such as x-* vendor extensions, to include in the generated OpenAPI schemas. It mirrors the Schema.toJsonSchemaDocument option of the same name, which fromApi previously did not forward.

  • #9462 4577a28 Thanks @tobimori! - Support the nullable single-member allOf tooling convention in JsonSchema.fromSchemaOpenApi3_0 when no string type or anyOf is present. Sibling constraints are preserved and may still reject null.

  • #9199 973d599 Thanks @jayhemnani9910! - Fix OTLP integer attributes outside the signed 64-bit range causing collectors to reject the export. They are now sent as doubleValue for numbers and stringValue for bigints, and large in-range numbers keep their exact value in JSON.

  • #9198 2f066a5 Thanks @jayhemnani9910! - Fix OtlpSerialization.layerJson writing NaN and Infinity as null, which made OTLP collectors reject the whole export.

  • #9334 f0ccbb6 Thanks @effect-bot! - Make overlapping ManagedRuntime.dispose and ManagedRuntime.disposeEffect calls wait for the disposal in progress, and make the dispose function returned by HttpEffect.toWebHandlerLayerWith (and HttpRouter.toWebHandler) return the same promise on every call. Fibers started by the runtime, their child fibers and its finalizers still return immediately when they dispose it.

  • #9615 2dda6ce Thanks @Marve10s! - Fix Path.fromFileUrl throwing a URIError instead of failing with BadArgument when the URL contains a malformed percent-encoding.

  • #8676 3da7c0a Thanks @rchasman! - With SpanPropagationEnabled, statement spans record db.client.connection.wait_time_ms, and in @effect/sql-pg a statement that waited for a new session gets a db.connect child span covering the part of the connect it waited for.

  • #9222 5a67e0b Thanks @effect-bot! - Fix SqlRunnerStorage hanging on PGlite.

    SqlClient now has a driver field identifying the driver that created it, such as "pg", "pglite" or "sqlite-node". Every Effect SQL driver sets it. On PGlite, runner storage no longer reserves the only connection and uses lock table rows instead of advisory locks, so runner and application queries are no longer blocked.

    Third-party drivers must pass a driver name to SqlClient.make, and hand-written SqlClient implementations must provide a driver field:

    const make = Effect.gen(function*() {
      return yield* SqlClient.make({
        driver: "my-driver",
        acquirer,
        compiler,
        spanAttributes: []
      })
    })
  • #9498 73b3a6e Thanks @schutzelaars! - Fix unnecessary value retention in PubSub replay buffers and SubscriptionRef.

  • #9446 c6f9e4c Thanks @jayhemnani9910! - Fix PubSub.takeBetween throwing RangeError on large backlogs.

  • #9495 be02676 Thanks @Marve10s! - Fix reused PubSub.takeUpTo effects returning fewer messages after consuming replayed messages.

  • #9458 26de861 Thanks @tim-smart! - Avoid loading Node's internal undici on cold start when importing effect/Schema or starting a Node HTTP server before any web API is used. Schema.FormData resolves the global constructor during validation, and @effect/platform-node loads node:http and node:https without evaluating their lazy web API exports.

  • #9322 9313799 Thanks @effect-bot! - Stop failed Reactivity.query and SqlClient.reactiveMailbox queries from rerunning on later invalidations, and discard pending reruns when a query fails.

  • #9328 d5c1e5b Thanks @effect-bot! - Propagate all entry release defects when an RcMap owner scope closes, after attempting every release and clearing the map. This also applies to resources managed through LayerMap.

  • #9191 11bb31f Thanks @danieljvdm! - Fix Channel.fromReadableStream, Channel.fromTransformStream and Stream.fromReadableStream discarding rejected cancel hooks and leaving the reader locked after finalization. A rejected cancel hook is now a defect, and an already errored stream is not reported twice.

  • #9396 8c23e46 Thanks @effect-bot! - Fix Stream.toReadableStream to wait for Web Stream demand before pulling the next upstream chunk, avoiding premature upstream side effects.

  • #9235 9c96011 Thanks @effect-bot! - Fix the Redis PersistedQueue store dropping entries when a payload or custom id contains a lone UTF-16 surrogate.

  • #9618 0d50570 Thanks @Marve10s! - Fix Effect.repeat, repeatOrElse, schedule and scheduleFrom treating a Cause.Done failure from the repeated effect as schedule completion.

  • #9542 9ed2bf1 Thanks @Marve10s! - Fix RequestResolver.withCache to call the wrapped resolver's preCheck on cache misses, preserving hook completion and nested cache reuse.

  • #9541 76ec912 Thanks @Marve10s! - Fix RequestResolver.withSpan dropping every span option except attributes and links when the options are returned by a function.

  • #9439 af2756d Thanks @tim-smart! - Fix Effect.request failing when a resolver's batch delay completes synchronously, such as RequestResolver.setDelay(0) under TestClock, by registering the request before the delay starts.

  • #9230 3ec8100 Thanks @effect-bot! - Keep Resource.auto refreshing according to its schedule after a failed refresh, while preserving the previously cached value.

  • #9460 93abf02 Thanks @schutzelaars! - Fix RpcClient retaining request state when a request fails without a reply.

  • #9232 1e94993 Thanks @effect-bot! - Fix RPC connection defects failing new requests started synchronously by pending callers. Only requests pending when defect delivery begins are failed; new requests await their own responses. Ensure all pending calls are released even if defect delivery is interrupted.

  • #9656 99a4616 Thanks @effect-bot! - Add an opt-in batch option to RpcClient.layerProtocolHttp and RpcClient.makeProtocolHttp that sends concurrent RPC requests from the same client in one HTTP request.

  • #9297 0a7978e Thanks @tim-smart! - Fix HTTP RPC cancellation before the first response chunk and during buffered response collection so client aborts interrupt server-side requests and release their resources.

  • #9562 b4a060b Thanks @tim-smart! - Change RPC NDJSON's content type from application/ndjson to application/x-ndjson; update any exact media-type checks in custom integrations. Reject malformed non-empty lines with RpcSerialization.NdjsonDecodeError (preserving the parse error as cause) instead of silently dropping messages, while explicitly skipping empty LF and CRLF lines. Existing RPC HTTP clients and servers remain compatible across the header change.

  • #9665 274f4a4 Thanks @effect-bot! - Add the Rpc.ParseOptions annotation, so RPC payloads and responses can be decoded and encoded with schema parse options such as concurrency.

  • #9601 25f29be Thanks @effect-bot! - Fix runMain skipping finalizers when SIGINT or SIGTERM arrives during synchronous startup.

  • #9547 9036440 Thanks @effect-bot! - Prevent uncaught errors when unread HTTP responses are garbage-collected in runtimes such as Cloudflare Workers that restrict aborting request I/O outside its request context.

  • #9593 415f005 Thanks @magoz! - Fix Schema.isBase64 and Schema.isBase64Url throwing RangeError: Maximum call stack size exceeded on large inputs.

  • #9245 191308b Thanks @fubhy! - Add the unstable Schema.toCodecGoJson codec for Go JSON responses. It normalizes optional-key null values to missing keys and required array or record null values to empty collections, while preserving schemas that already accept null. Encoding is unchanged from Schema.toCodecJson.

  • #9170 4b96570 Thanks @effect-bot! - Preserve literal member inference in Schema.Enum for inline object literals without requiring as const.

  • #9409 d84ec3f Thanks @effect-bot! - Preserve filter-reported error paths when message annotations override schema check messages in Standard Schema and default error formatting. Filter message annotations now also override directly returned messages, including when the annotation is an empty string. Avoid applying struct messages to multiple filter failures.

  • #9720 392aa1c Thanks @Marve10s! - Fix Schema.toFormatter throwing on ReadonlySet, ReadonlyMap, HashSet, HashMap and Chunk values that contain symbols or null-prototype objects, and keep Chunk elements in iteration order.

    Map and set entries are now sorted by their formatted output instead of by their raw values, so they can print in a different order than before, including for primitive keys and values.

  • #9556 99e9bd9 Thanks @gcanti! - Remove the type-level uniqueness check from Schema.toTaggedUnion so generic member lists compile again. Duplicate discriminants still throw at runtime.

  • 6f6f45f Thanks @gcanti! - Fix Schema.toJsonSchemaDocument to support numeric record keys and BigInt template literals, and approximate tuples with post-rest elements.

  • #9318 13fc07e Thanks @effect-bot! - Preserve synchronous throws from schema transformations, filters, middleware, and custom declaration parsers as defects when decoding or encoding, including at the root schema. Exit, Effect, and Promise parsers now report these defects through their result instead of throwing before returning.

  • #9596 a4b38dd Thanks @magoz! - Match finite number strings in linear time. Schema.isStringFinite, Number record keys, Number template literal parts and Schema.toCodecStringTree number fields no longer take quadratic time to reject long digit runs such as "111…x". The JSON Schema pattern for these schemas changes to the same linear regular expression and accepts exactly the same strings.

  • #9724 8b18580 Thanks @Marve10s! - Fix Schema.Tuple encoding leaving an empty slot when a trailing optional element such as Schema.OptionFromOptionalKey is omitted.

  • #9391 0c477fe Thanks @effect-bot! - Propagate all release defects from ScopedCache.invalidateAll and cache owner-scope shutdown after attempting every entry release. Successful bulk invalidation now returns undefined as declared.

  • #9243 9a5331d Thanks @fubhy! - Add effect/SemVer for strict Semantic Versioning 2.0.0 parsing, formatting, comparison, and version bumps, and effect/SemVerRange for npm-style range matching and version selection. Add schemas and string codecs for both types.

  • #9272 a706d73 Thanks @Marve10s! - Fix Sink.collect and Sink.take throwing a RangeError on large input chunks.

  • #9320 c9a1e72 Thanks @effect-bot! - Fall back to client computation when atom hydration data fails schema decoding or a streamed initial result cannot be encoded, instead of throwing or leaving the atom waiting indefinitely.

  • #9487 89eaaf8 Thanks @jayhemnani9910! - Fix Socket.readerString and Socket.toChannelString corrupting characters split across binary frames. Incomplete characters are emitted as U+FFFD before string frames or on close code 1000.

  • #9292 8215811 Thanks @tim-smart! - SqlEventLogServerUnencrypted publication and Reactivity invalidations inside a SQL transaction now wait for the outermost commit and are dropped on rollback.

  • #9289 ad69018 Thanks @tim-smart! - Add SqlClient.afterCommit, which runs an effect once the outermost transaction commits, or immediately outside a transaction.

  • #9576 a733eba Thanks @effect-bot! - Add SqlClient.BeginTransaction, a reference that replaces the statement starting a top-level transaction, such as BEGIN ISOLATION LEVEL SERIALIZABLE, saving the round trip of a separate SET TRANSACTION. Nested transactions keep their savepoints. SqlClient.makeWithTransaction passes the statement to begin as a second argument.

  • #9472 7282d5f Thanks @tim-smart! - Improve SqlEventJournal uploads and query performance.

    • Checkpoint successful uploads per remote without waiting for an echo, while forwarding older entries imported later.
    • Index conflict, entry-ordering and remote-sequence queries.
    • Migrate existing databases on first open using a writable connection. The first upload after migration may resend unconfirmed entries.
    • Run write and writeMany callbacks in the journal transaction, rolling back their SQL on the same client if the write fails or is interrupted.
  • #9233 da33572 Thanks @effect-bot! - Fix SQL event journals reporting incoming remote entries as conflicts. Remote writes now report only previously stored newer entries and atomically persist entries and remote sequences after all callbacks succeed, allowing failed writes to be retried.

  • #9606 d9e2d12 Thanks @effect-bot! - Fence SQL PersistedQueue settlements and lock refreshes by acquisition, so a handler whose lock lapsed can no longer complete, fail, retry or release a row after the same store re-claims it.

  • #9517 dc923b8 Thanks @effect-bot! - Allow queued SQL transactions to be interrupted while waiting for a connection, respecting the caller's interruptibility. Interrupted or failed acquisition releases the connection scope and its permits, and a libSQL transaction interrupted during BEGIN is rolled back.

    SqlClient.makeWithTransaction (unstable) now owns the connection scope: acquireConnection receives the mask's restore function and returns a scoped connection effect instead of a [scope, connection] tuple.

  • #9599 1b74086 Thanks @effect-bot! - Preserve typed SQL errors without cleanup defects after SQLite automatically rolls back a transaction in sqlite-node, sqlite-bun and in-memory sqlite-wasm. OPFS and React Native clients are unchanged.

  • #9485 8a5507b Thanks @itisrmk! - Fix SqlMessageStorage ID precision loss on SQLite drivers that return numbers, including Cloudflare Durable Objects.

  • #9398 23460fa Thanks @effect-bot! - Treat persisted cache entries that no longer decode as cache misses, recomputing and replacing them after success or error schema changes.

  • #9264 0dbbea6 Thanks @effect-bot! - Redirect static directory index URLs without a trailing slash to their canonical form with a 301 response, preserving router prefixes and query strings so relative links resolve correctly. Clients that do not follow redirects must request the trailing-slash URL directly.

  • #9622 70aad3f Thanks @Marve10s! - Keep recursive Stream.concat chains through Stream.suspend linear in their length.

  • #9274 0909236 Thanks @Marve10s! - Fix Stream.mapAccum throwing a RangeError when its callback returns a large array.

  • #9623 a9e66d8 Thanks @Marve10s! - Keep Stream.retry and Channel.retry work constant per attempt instead of growing with every retry.

  • #9624 ee5c0d5 Thanks @Marve10s! - Fix Stream.zip and related zip operators taking quadratic time when the two streams emit chunks of different sizes.

  • #9492 631c5d6 Thanks @Marve10s! - Fix Stream.zipWithArray discarding right-side leftovers when the callback returns leftovers for both streams.

  • #9750 7e60c1a Thanks @armancharan! - Fix String.capitalize and String.uncapitalize for strings that start with an astral letter such as "𐐨".

  • #9494 4cddd3c Thanks @Marve10s! - Fix suspended Schema.Struct parsers overwriting earlier results when the same parsing Effect is rerun.

  • #9722 8727e5d Thanks @Marve10s! - Fix Stream.switchMap and Channel.switchMap not finalizing inner streams that were replaced before they started.

  • #9428 2bc97fa Thanks @jpowersdev! - Fix Tar.decode dropping a leading byte order mark from entry names, link targets and PAX keys, so a name such as "\uFEFF/etc/passwd" no longer decodes as /etc/passwd.

  • #9392 f9a7f05 Thanks @effect-bot! - Keep TestClock diagnostics visible when TestConsole captures test output, including warnings about time not advancing and busy fibers. Ordinary test console output remains captured.

  • #9434 d978cca Thanks @jpowersdev! - Add the experimental TextDiff module for array, line and Unicode code point edit scripts, replay, inversion and unified diff formatting. Use maxEdits to bound search work on large inputs, trading minimality for a valid script when the cap is exceeded.

  • #6428 b334ccf Thanks @coyaSONG! - Add FileSystem.lstat, which returns the File.Info of a path without following symbolic links. Custom FileSystem implementations, including those passed to FileSystem.make, must now provide lstat.

  • #9538 0b50cfc Thanks @jayhemnani9910! - Allow empty quoted keys such as "" = 1 in Toml.parse, as permitted by TOML 1.0.

  • #9741 5b7d2b5 Thanks @danieljvdm! - Fix Toolkit.handle dropping additional failures and their annotations when a tool handler fails in "error" failure mode.

  • #8065 6ee26b1 Thanks @danieljvdm! - Interrupt Toolkit handlers when their result stream closes, including early termination. Add Toolkit.PreliminaryBuffer so callers can opt in to bounding buffered preliminary results.

  • #9271 eab7e6a Thanks @Marve10s! - Fix Trie iterators restarting from the first entry when iterated again. They now continue from their current position.

  • #9701 e618f10 Thanks @effect-bot! - Require an explicit trusted proxy policy before applying forwarded headers.

    HttpMiddleware.xForwardedHeaders now takes { trustedProxies } and only applies X-Forwarded-* headers when the connecting peer is trusted. X-Forwarded-For is read from the right, skipping trusted proxies, and X-Forwarded-Host / X-Forwarded-Proto are only used when they line up with it.

    HttpServerRequest.toURL no longer reads x-forwarded-proto directly. It uses the new request.protocol, set by the trusted proxy middleware, before the transport scheme. The connecting peer stays available as request.peerAddress.

    import { HttpMiddleware } from "effect/http"
    import { IpNetwork } from "effect/net"
    
    // before
    HttpMiddleware.xForwardedHeaders
    
    // after
    HttpMiddleware.xForwardedHeaders({
      trustedProxies: [IpNetwork.fromStringUnsafe("10.0.0.0/8")]
    })
  • #9560 da14b1f Thanks @effect-bot! - Add opt-in typed reactivity keys. Augment Reactivity.Keys to map key names to ID types, and the public reactivity APIs (Reactivity, Atom, AtomHttpApi, AtomRpc, SqlClient.reactive and EventLog.groupReactivity) reject undeclared key names and mismatched IDs. With no keys declared, the accepted types are unchanged.

  • #9516 3314fc3 Thanks @tim-smart! - Preserve defects in mixed failure causes across Effect, Stream and Channel.

    • Typed recovery skips causes containing a defect and converts every typed error to a defect: Fail(e) + Die(d) becomes Die(e) + Die(d), preserving reason order and interrupts. Use catchCause or catchDefect to recover from these causes.
    • An interrupt alongside a typed error does not block recovery, including Effect retry and repeat error paths. Retrying or re-raising only the typed error can discard that interrupt.
    • The same rule applies to failing repeat / repeatOrElse policies. Retry-policy failures still propagate unchanged.
    • Error mapping in Effect (including eager variants), Exit, Stream and Channel now maps every typed error in place, preserving defects, interrupts and reason order instead of keeping only the first mapped failure. Mapping does not convert typed errors to defects.
  • #8351 66db624 Thanks @ArjunCodess! - Add UserDirectories to effect/persistence, a service that resolves the home, config, data, cache and state directories for an application following XDG and platform conventions.

  • #9531 4b8a50d Thanks @jayhemnani9910! - Report an initial UTF-16 BOM in Xml.decode as Unsupported instead of Syntax.

  • #9581 8d52668 Thanks @jayhemnani9910! - Fix Yaml.parse block scalars including less indented comments in their value.

  • #9608 1de1055 Thanks @jayhemnani9910! - Fix Yaml.parse rejecting tabs in block scalar content and discarding the whitespace of whitespace-only block scalar lines. Leading empty lines more indented than the block scalar content are now rejected.

  • #9652 db130e6 Thanks @okarin1511! - Fix Yaml.parse rejecting anchors defined inside flow collections, such as {a: &ref 1, b: *ref}.

  • #9700 5fa5fa5 Thanks @fubhy! - Fix Yaml.parse rejecting flow collections that span multiple lines, such as a JSON-style mapping with its entries and closing bracket on separate lines.

Don't miss a new effect release

NewReleases is sending notifications on new releases.