Minor Changes
-
#8829
631d4f4Thanks @harrysolovay! - AddSchema.isAscii, a check that accepts only ASCII strings, and the matchingSchemaRepresentation.isAsciiReviver. -
#8829
7ea1ea2Thanks @wmaurer! - Add an optionalcauseto the AINetworkError. It holds theHttpClientErrorthe request failed with, stored unchanged and not redacted, so the reason a request failed is no longer lost. The newNetworkError.fromHttpClientErrorsets it, and all AI providers now use it.NetworkError.fromRequestErroris unchanged. -
#8829
a2ccc14Thanks @fubhy! - FixAtom.Serializableto encode to and decode fromSchema.Json, matching the JSON codec used byAtom.serializable. Encoded results may now require narrowing; runtime behavior is unchanged. -
#8829
c4d298dThanks @okarin1511! - Render inherited CLI flags in a separateINHERITED FLAGSsection and add"full","summary", and"none"modes for inherited and global flags inCliOutput.defaultFormatter.HelpDocaddsinheritedFlags,commandPath, andglobalFlagsScopeprovenance so summaries can point to the appropriate help, with globals always listed on their declaring command. Custom formatters must read ancestor shared flags fromHelpDoc.inheritedFlagsinstead ofHelpDoc.flags. -
#10087
ac10e55Thanks @effect-bot! - AddrunnerJoinDebouncetoShardingConfig. When set, a runner joining the cluster is only added to shard assignments once the healthy runners have stayed unchanged for that duration, or at most four times that duration after the first pending join. A scale-up or a deployment with a large surge then hands each shard off once instead of once per join. Runners that already hold shards and leave or become unhealthy are still published immediately; a pending runner that leaves only restarts the quiet period. While joins are pending, runners take no new shards, so a shard can stay unlocked briefly until each runner publishes. Defaults to0, which keeps the current behavior. -
#8829
df8dce5Thanks @tim-smart! - AddtrimandkeepEmptyValuesoptions toSchemaGetter.splitKeyValue,SchemaTransformation.splitKeyValueandConfig.Record. Both default tofalse, so existing callers are unaffected.OtlpResource.fromConfignow trimsOTEL_RESOURCE_ATTRIBUTESkeys and values and keeps entries with an empty value as"". -
#8829
0c24a8fThanks @sledorze! - Add amaxDepthoption toContext.makeUnsafe, controlling how manyContext.addcalls are kept as overlays before the context is rebased into a flat map. Defaults to 8. -
#8829
2d1fcd4Thanks @effect-bot! - Add anonDstOverlapoption toCronandSchedule.cronthat chooses which occurrences of local times repeated when clocks fall back are included:"earlier"(default),"later"or"both". It applies to every repeated local time, including ones not caused by daylight saving time.Cron.prevnow returns the latest matching instant before its input when starting inside a repeated hour. Near a spring-forward gap it no longer throws or returns an instant at or after its input. -
#8829
8f23668Thanks @fubhy! - Replaceeffect/Cryptowith family-specificeffect/crypto/*services, opaque keys,CryptoError, a configurableWebCryptoreference and key schemas ineffect/Schema. Encoding secret or private keys through byte/format schemas requires{ allowEncode: true }.Breaking changes
- Use
SecureRandomfor randomness and UUIDs, andDigestwith algorithm values such asDigest.sha256for hashing. Replaceeffect/testing/TestCryptowithLayer.mockfor the required services. - Provide crypto explicitly; it is no longer included in the runtime
*Servicesbundles.NodeCrypto,BunCrypto,DenoCryptoandBrowserCryptooffer individual family layers and a combinedlayer, supplyingSecureRandomwhere needed. Core modules offerlayerWebCrypto. - Provide
Digest.Digestinstead ofCrypto.CryptotoSqlMessageStorageandSingleRunner, and instead ofEventLogEncryptiontoSqlEventLogServerEncrypted.makeStorageandlayerStorage. ReplaceEventLogEncryption.sha256Stringwithdigest.digestHex(Digest.sha256, bytes).
Existing workflow ID, activity idempotency key and event log table-name encodings are unchanged.
Event log encryption, identity key derivation and session authentication now run on
Aead,Digest,SignatureandSecureRandom.EventLogEncryption.makeandEventLogEncryption.layertake those services from context, so Node apps can use theNodeCryptolayers.EventLogEncryption.layerSubtleand the session auth functions use the Web Crypto layers on theWebCryptoreference instead ofglobalThis.crypto. Existing identities, derived signing keys and encrypted batches are unchanged.UUIDv7 and ULID generation is now monotonic below the maximum 48-bit timestamp, including within a millisecond and across clock rollback. Ordering is per
SecureRandominstance; the unsafe helpers and model UUIDv7 defaults share per-realm ordering. - Use
-
#8829
3f8f359Thanks @jem-computer! - Declare decision images as input fields withDecision.Image, and addDecision.locate, which answers with a bounding box around one target in an image field.-
DecideOptions.imagesis removed. AddDecision.Imagefields to the input schema and refer to each image by its path in instructions:// Before DecisionModel.decide(Triage, { input: "Checkout error", images: [screenshot] }) // After const Triage = Decision.make({ input: Schema.Struct({ report: Schema.String, screenshot: Decision.Image }), decisions }) DecisionModel.decide(Triage, { input: { report: "Checkout error", screenshot } })
-
Custom providers receive
imagesas{ reference, path, image }, with each image replaced by its reference instateand its data as a base64 string orURL. -
Decision.locate({ image: "photo", instructions })takes a path thatDecision.makechecks against the input's image fields. Providers opt in withsupportsLocate: true.Decision.AnyandDecisionModel.ProviderAnswergain locate variants, so exhaustive switches over them need aLocatecase. -
TypeSafeDecisionModelsupports images, sent as assets keyed by reference, and sends locate decisions as Box questions, which needjev-previeworjev-1.14.0. OpenAI and Cloudflare label each image with its reference.
-
-
#8829
2a03584Thanks @jayhemnani9910! - AddDuration.formatIso,Duration.fromIsoandSchema.DurationFromIsoStringfor ISO 8601 durations. Only exact units are supported: weeks, days, hours, minutes and seconds. Years and months are rejected because they have no fixed length. -
#8829
40e145eThanks @yordis! - AddDuration.toMicrosfor converting durations to microseconds. -
#8829
7217410Thanks @tim-smart! - Add encrypted remote compaction to the event log. -
#8829
cf249feThanks @tim-smart! - Detect unsupported streaming request bodies inFetchHttpClientand fail with anEncodeErrorinstead of silently sending[object ReadableStream]. SetFetchHttpClient.StreamBodyFallbackto"buffer"to buffer the body in memory on those runtimes instead. -
#8829
4f0fad1Thanks @effect-bot! - Fence Redis PersistedQueue settlements and lock refreshes on a per-acquisition lock, so a stale handler can no longer release another live claim, including one with the same custom id in another queue. The lock format is incompatible with older workers on the same prefix: stop every old worker and let its locks expire before starting upgraded workers. -
#8829
f74db37Thanks @smit153! - Accept{ self }before the generator body inEffect.fnUntracedandEffect.fnUntracedEagerto bindthis, matchingEffect.fn. -
#8829
069cf72Thanks @effect-bot! - Add opt-in RFC 9457 Problem Details support toHttpApi.ProblemDetailsineffect/httpprovides theapplication/problem+jsonmedia type, a lenient codec for problem details objects, and a response constructor.HttpApiError.Problem<Self>()(tag, { type, status, title }, fields?)declares a typed problem as a yieldable error class that endpoints render, document and decode asapplication/problem+json, discriminated bytype.HttpApiSchema.asProblemrenders a built-in error such asHttpApiError.NotFoundas a problem.HttpApiMiddleware.ProblemDetailswithHttpApiMiddleware.layerProblemDetailsrenders request decoding failures as a generic400problem (with per-fielderrorswhenincludeDetailsis enabled) and response encoding failures as a500problem.
The default behaviour is unchanged: without the opt-in, built-in errors and decoding failures still produce the same responses as before.
-
#8829
9a07ebcThanks @effect-bot! - AllowHttpApiSchema.Upgradealongside ordinary success responses, for servers that decline the upgrade, and addHttpApiClient.isUpgradedto narrow the client result.HttpApiClient.Upgradedvalues now carry a[HttpApiClient.UpgradedTypeId]brand. Code that buildsUpgradedvalues by hand, such as client mocks, must add[HttpApiClient.UpgradedTypeId]: HttpApiClient.UpgradedTypeIdto the object literal. -
#8829
f40dc4eThanks @bezff! -HttpClient.withCookiesRefnow takes aRef<ReadonlyArray<Cookie>>and sends stored response cookies only to a matching host, path and scheme, using the newCookies.mergeIntoArrayandCookies.toRequestCookieHeader. Seed the ref withCookies.mergeIntoArrayor with cookies that set adomain. -
#8829
fa516c6Thanks @Tarekkharsa! - ExportHttpClient.isTransientErrorandHttpClient.isTransientResponse, the predicatesretryTransientuses to decide what to retry. -
#8829
ffd9237Thanks @effect-bot! - Addlog: "Unhandled"toEffect.ignore,Effect.ignoreCause, and their Stream and Channel variants. This resolvesReferences.UnhandledLogLevelwhen a failure occurs and suppresses logging when that reference isundefined, while preserving each combinator's existing failure semantics. -
#8829
93895b9Thanks @tim-smart! - AddkeystoKeyValueStoreandSchemaStore. It returns a snapshot of the keys in the store, in no particular order, and is implemented by the memory, file system, SQL, Web Storage and IndexedDB stores. Custom stores built withKeyValueStore.makeorKeyValueStore.makeStringOnlymust now providekeys.KeyValueStore.prefix(...)now scopeskeys,sizeandisEmptyto keys under the prefix, with the prefix removed from the returned keys. PreviouslysizeandisEmptyreported on the whole backing store.Stores built with
KeyValueStore.makethat don't provideclearPrefixnow derive it fromkeysandremoveinstead of failing for non-empty prefixes. -
#8829
e5a1479Thanks @effect-bot! - Add the unstableMatch.literalsandMatch.literalsExhaustiveAPIs for matching string and number literal unions with a record of handlers. -
#8829
65db606Thanks @effect-bot! - Add request-level dependencies and middleware toMcpServerso handler services can be supplied per request. Breaking: pass registration layers through the transport'sregistrationsoption, and capture construction-time handler services inLayer.unwrapinstead ofLayer.provide. -
#8829
7c42335Thanks @tim-smart! - AddMcpServer.visibilityto hide tools, resources and prompts per request based on services provided by MCP middleware. Middleware that wraps a visibility now runs on list requests, once for each registration, soMiddlewareMethodincludes the list methods. Middleware provided both locally and globally now runs once. -
#8829
cb21d14Thanks @effect-bot! - Add acacheHintsoption to theMcpServerlayers to set how long clients may treatv2026_07_28discovery and list results as fresh, for examplecacheHints: { tools: { ttl: "1 minute", cacheScope: "private" } }. Results without a hint, andresources/read, keep{ ttlMs: 0, cacheScope: "private" }. -
#8829
c32eb78Thanks @effect-bot! - ExposeSqlMessageStorage.makeEncodedStorageto construct an encoded SQL message storage driver without running migrations or executing startup SQL. RunlayerMigrationsseparately with the same table prefix before using the driver;makeEncodedcontinues to run migrations by default. -
#8829
be9895bThanks @bezff! - MovefromFileSystemfromeffect/sql/Migratortoeffect/sql/MigratorFileSystem, so React Native apps can importeffect/sql/Migratorandeffect/sqlunder Metro. Theeffect/sqlbarrel and@effect/sql-sqlite-react-native/SqliteMigratorno longer exportfromFileSystem; the other SQL adapter migrators still re-export it. -
#8829
26b4bfeThanks @fubhy! - Type received and forwarded HTTP request methods asstringso methods such asPROPFINDare represented accurately, including in AI HTTP error details. Exhaustive matches on request methods now need a fallback or a guard usingHttpMethod.isHttpMethod. -
#8829
f97711fThanks @effect-bot! - IsolatePersistencestores on theKeyValueStoreand Redis backings. Clearing a store now only removes that store's entries, and different store / key pairs no longer map to the same backing key.Add
KeyValueStore.clearPrefix, implemented by the memory, file system, SQL, Web Storage and IndexedDB stores.KeyValueStore.prefix(...).clearnow only removes keys under the prefix. Stores built withKeyValueStore.makethat don't provideclearPrefixremove the matching keys one by one instead of clearing everything.Both backings now store entries under
<storeId>:<key>, with%and:in the store id percent-encoded.Key layout change. Entries written by earlier versions are not read back:
Persistence.layerKvs/layerBackingKvs: every existing entry becomes unreachable, because keys used to be<storeId><key>with no separator. Cached results are recomputed.Chat.layerPersistedon aKeyValueStorebacking loses its stored chat histories.Persistence.layerRedis/layerBackingRedis: keys are unchanged unless the store id contains%or:. Entries for those store ids become unreachable.
Old entries are not migrated or removed automatically.
-
#8829
4f16778Thanks @effect-bot! - Add the unstablePool.StatsandPool.statsAPIs for sampling how many pool items are idle or in use and how many borrowers are waiting.PgPool.statsandPgClient.poolStatsexpose the same snapshot for PostgreSQL sessions, so applications can export connection pool metrics without reaching into pool internals. -
#8829
d2b6bc7Thanks @jpowersdev! - Add experimentalGlobpath matching and a sharedFileSystem.globimplementation for Node, Bun, and Deno.- Breaking: custom
FileSystemimplementations, including inputs toFileSystem.make, must providereadDirectoryEntries; mappingreadDirectorynames to{ name, type: "Unknown" }is supported. Wrappers must apply directory-listing changes to both methods. FileSystem.makenow derivesglobinstead of accepting it. Apply custom overrides afterward withFileSystem.of({ ...fs, glob: customGlob }).- Glob patterns use
/separators and backslash escapes; Node extglobs no longer expand. Results use/separators and are relative torootunless the pattern is absolute. Deno wildcards now skip dotfiles unless explicitly named ordot: true; unreadable wildcard-reached directories are skipped, while read failures at the root or a leading literal directory propagate.
- Breaking: custom
-
#8829
3d88452Thanks @fubhy! - AddCommandLinetoeffect/processfor quoting and joining command lines, and supportRedactedarguments andenvvalues inChildProcess.Migration:
ChildProcess.maketemplates keep quoted words together and throw aCommandLineErrorfor shell syntax such as|,$HOMEor*. Quote such characters or pass them with${}.- With the
shelloption, templates cannot contain${}values and extra arguments fail withBadArgument. Pass the whole script as the command, built withCommandLine.join. StandardCommand.argsandenvvalues can beRedactedstrings.ChildProcess.TemplateExpressionandChildProcess.TemplateExpressionItemare removed. Use theCommandLinetypes of the same name.
-
#8829
3c42058Thanks @effect-bot! - RemoveAiError.HttpRequestDetailsandResponse.HttpRequestDetails, so AI errors and response metadata no longer carry request headers or query parameters.AiError.NetworkErrorrecords the request asmethodandurlfields instead ofrequest, and therequestfield is gone fromAiError.HttpContextandResponse.ResponseMetadataPart. -
#8829
2ae4045Thanks @tim-smart! - Calls made withdiscard: truenow complete when the server acknowledges them, instead of when the request is written.SchemaBinary peers must be upgraded together because the new
discardfield changes the envelope fingerprint. -
#8829
e853fa1Thanks @effect-bot! - Add anonDisconnectoption toRpcServer.makeand its layer and HTTP wrappers, so applications can observe client disconnects without taking fromProtocol.disconnectsand preventing the server from interrupting the disconnected client's requests. -
#8829
1194a4cThanks @bezff! -sql.insertandsql.updateValuesnow require a non-empty array of rows at the type level. Narrow array inputs withArray.isReadonlyArrayNonEmptybefore passing them to these helpers. -
#8829
2cb498eThanks @effect-bot! - Fix a SQLite client hanging forever after a queuedwithTransactionorreservewas interrupted just as it received the connection. The interrupted acquisition could keep the connection's only permit without registering its release.Add
Semaphore.takeScoped, which holds permits until the current scope closes. Waiting can be interrupted unless the caller is uninterruptible, and acquired permits are always returned when the scope closes. -
#8829
89e5443Thanks @jpowersdev! - AddTerminal.size, a scoped queue that starts with the current terminal dimensions and receives each resize. Custom terminals passed toTerminal.makemust now supplysize. -
#8829
2a9a425Thanks @jayhemnani9910! -Toml.parsenow returns aResultinstead of throwing, failing with anEncodingErroron invalid input. It also rejects documents that extend an inline table or a statically defined array, which TOML 1.0 forbids.
Patch Changes
-
#8829
ed20129Thanks @effect-bot! - Report unobserved release failures atUnhandledLogLevelfor RcMap and RcRef idle expiry, abandoned interrupted RcMap lookups, and ScopedCache expiry discovered by keys, values, or entries scans. Preserve failure propagation when cleanup is observed by a caller. -
#10076
20795b9Thanks @jpowersdev! -Base64Url.decodeandBase64Url.decodeStringnow reject partially padded input such asZg=. Unpadded input (Zg) and fully padded input (Zg==) still decode. -
#10083
a8e5e6cThanks @jpowersdev! - FixBigDecimal.fromStringandBigDecimal.fromStringUnsafeaccepting a sign after the decimal point. -
#10093
fb5dbeeThanks @tim-smart! - Release a frozen runner's MySQL shard locks aftershardLockExpiration.SqlRunnerStoragesetswait_timeouton its MySQL lock connection, and restores it before returning the connection to the pool, so a runner that stops refreshing loses its named locks instead of holding them until the server drops its TCP connection. Vitess ignoreswait_timeout, so runners behind Vitess keep the previous behavior. -
#10095
8309b94Thanks @tim-smart! - Restoreidle_session_timeouton the PostgreSQL shard-lock connection beforeSqlRunnerStoragereturns it to the pool, so other queries on that connection no longer have their session ended aftershardLockExpirationidle. -
#8829
af23904Thanks @devangpratap! - Reject an append assignment such asFOO+=bar cmdinCommandLine.templateandChildProcess.makewithUnsupportedSyntax, asFOO=bar cmdalready is, instead of runningFOO+=baras the program. -
#8829
468c6eeThanks @tim-smart! - Keep the source context'smaxDepthwhenContext.pickis given zero or one key, and reduce the bundle size ofContext.makeUnsafe. -
#8829
fe6b748Thanks @effect-bot! - Support duplexadditionalFdsthroughgetInputFdandgetOutputFd, preserving both directions when used withpipeTo. -
#10064
e75708cThanks @gcanti! - FixSchemaRepresentation.toCodeDocumentlosing__proto__properties or changing object prototypes in generated annotations. -
#10086
7890077Thanks @jpowersdev! -HttpTraceContext.fromHeadersnow rejects uppercase hex trace and span IDs intraceparent,b3andX-B3-*headers, matching the lowercase encodings required by W3C Trace Context and B3. Previously they were accepted and propagated unchanged, which conforming downstream receivers reject. -
#10085
c4a00fcThanks @jpowersdev! - Rejecttraceparentheaders with malformed trace flags inHttpTraceContext. Flags that are not two lowercase hexadecimal digits now returnOption.none()instead of continuing the trace. -
#8829
8938b19Thanks @effect-bot! - MakeremoveonKeyValueStore.layerFileSystemsucceed when the key does not exist, matching the other backends. -
#8829
89e1e1eThanks @tim-smart! - StopMcpServerfrom sending stateful clients list-change notifications for changes made before the server handled theirinitializerequest, over stdio, HTTP sessions and custom transports. -
#8829
eda0960Thanks @effect-bot! - LetMcpServermiddleware and visibility layers receive per-request services fromHttpRouter.middlewareunderlayerHttp. Unmet per-request services now stay asMcpRequest<"Requires", S>layer requirements, replacingMissingRequestDependencies. -
#8829
89e1e1eThanks @tim-smart! - AddMcpTest.makeClient, an in-memory MCP client for testingMcpServerregistrations over the JSON-RPC wire encoding. -
#10062
e19c611Thanks @duailibe! -Otlp.layer,Otlp.layerFromConfig,Otlp.layerJsonandOtlp.layerProtobufnow declare the sharedOtlpExporter.Flusherthey provide, instead ofLayer<never>. -
#10065
8e668feThanks @jpowersdev! - Preserve a leading UTF-8 BOM in URL-encoded body field names. -
#10067
ce9e999Thanks @jpowersdev! - Preserve a leading?in URL-encoded form field names.urlParamsBodypreviously dropped it as a query-string prefix, so?name=valuedecoded toname. -
#8829
6dc3f7cThanks @jpowersdev! - Add the unstableCsvmodule toeffect/encodingfor streaming CSV parsing and writing over text or UTF-8 bytes, with header records and schema adapters that convert cells throughSchema.toCodecStringTree. -
#10050
1513bbdThanks @gcanti! - Prevent excessive CPU use whenSchema.fromFormDataandSchema.fromURLSearchParamsdecode field names containing unmatched opening brackets. -
#10061
c065ed7Thanks @gcanti! - FixSchema.TaggedUnion.matchandmatchOrElsereturn inference and handler input types, and narrowmatchOrElsefallbacks to unhandled variants.Remove explicit output type arguments from
Schema.TaggedUnion.matchandmatchOrElsecalls; annotate handler return types when an explicit output is needed. -
#8829
e710bbbThanks @devangpratap! - FixToml.parseaccepting out of range dates and times such as1979-02-30or24:00:00, and rolling1979-02-30T07:32:00Zover to March 2 instead of rejecting it. -
#8829
b0d6e75Thanks @jayhemnani9910! - FixToml.parserejecting multiline basic and literal strings ending with one or two content quotes. -
#10068
32b3570Thanks @effect-bot! - Store the empty string key inTrieinstead of silently discarding it. Construction, lookup, replacement, modification, removal, iteration andlongestPrefixOfnow treat""like any other key. -
#10051
9f93f4fThanks @okarin1511! - Support YAML 1.1 merge keys (<<) inYaml.parse. An unquoted<<key merges a mapping, or a sequence of mappings, into the enclosing mapping. Explicit keys take precedence over merged keys, and earlier merge sources over later ones. Quote the key ("<<") to keep it as an ordinary key. -
#10069
27370c7Thanks @effect-bot! - FixYaml.parserejecting block sequence entry mappings whose first key sits more than one space after the dash. Later keys in the entry must now align with the first key, and a tab before the first key is rejected.