effect
3.22.2
Patch Changes
-
#6233
291d5a9Thanks @mvanhorn! - Fix TMap.remove and removeAll erroneously clearing entire bucket on hash collision. -
#7170
7c6e1e5Thanks @thewilkybarkid! - Fix use of Schema.NonEmptyArrayEnsure with strings
3.22.1
Patch Changes
-
#6443
7ccbd9cThanks @coyaSONG! - Clarify thatContext.GenericTagrequires a key. -
#6673
ab2af6dThanks @tim-smart! - Fix zero-capacityMailboxrendezvous behavior fortakeandtakeN. -
#6761
3cc3c6eThanks @tim-smart! - Use a linear matcher when decoding template literals containing only string spans. -
#6507
3d390f2Thanks @tim-smart! - Disable unhandled error logging for fibers spawned byEffect.timeout. -
#6762
fcabf08Thanks @tim-smart! - Redact errors from wrapped config parsers and avoid JSON key path collisions. -
#6669
735d81bThanks @tim-smart! - FixStream.asyncPushtermination with bounded dropping and sliding buffers.
3.22.0
Minor Changes
- #6286
fffdee0Thanks @effect-bot! - AddGraph.successorsandGraph.predecessors, deprecateGraph.neighborsDirected, and fix graph algorithm edge cases around reversal, undirected edge queries, shortest-path weight validation, topological sort initials, and strongly connected components.
3.21.5
Patch Changes
-
#6302
307d54aThanks @fubhy! - Allow cron fields like5/15to expand from the starting value through the field maximum. -
#6303
d95868aThanks @fubhy! - FixSchedule.cronwhen the test clock is adjusted to infinity. -
#6285
95c7d2eThanks @chatman-media! - FixCron.nextskipping earlier matching days when the upcoming day-of-month does not exist in the current month. For an expression like0 0 1,16,31 * *, advancing from a date past the 16th selected day 31; in a month without 31 days this overflowed into the following month and landed on a later matching day (e.g. the 16th), silently skipping the 1st.Cron.nextnow wraps to the first matching day of the next month in that case, matching the behaviour ofCron.prevand other cron implementations. -
#6305
d24511fThanks @fubhy! - Fix cron parsing and scheduling edge cases for whitespace, Sunday7, strict numeric tokens, explicit full day ranges, and month-constrained day-of-month / weekday matching.
3.21.4
Patch Changes
- #6267
8222963Thanks @fubhy! - Fix Graph traversal and shortest-path algorithms to traverse undirected edges independently of their stored source/target orientation.
3.21.3
Patch Changes
-
#6250
e2126bcThanks @milkyskies! - Fix $match generic type parameter inference inside arms (#6249) -
#6257
f7e836eThanks @gcanti! - EmitadditionalProperties: falsefor records with string keys andSchema.Nevervalues.
3.21.2
Patch Changes
- #6194
74f3267Thanks @mikearnaldi! - FixTestClock.unsafeCurrentTimeNanos()to floor fractional millisecond instants before converting them toBigInt.
3.21.1
Patch Changes
-
#6139
f99048eThanks @marbemac! - Fix batched request resolver defects causing consumer fibers to hang forever.When a
RequestResolver.makeBatchedresolver died with a defect, the requestDeferreds were never completed because the cleanup logic ininvokeWithInterruptusedflatMap(which only runs on success). Changed toensuringso uncompleted request entries are always resolved regardless of exit type.
3.21.0
Minor Changes
-
#5780
f7bb09bThanks @kitlangton! - AddCron.prevand reverse iteration support, aligning next/prev lookup tables, fixing DST handling symmetry, and expanding cron backward/forward test coverage. -
#5780
bd7552aThanks @mattiamanzati! - Add type-level utils to asserting layer types -
#5780
ad1a7ebThanks @schickling! - RcMap: support dynamicidleTimeToLivevalues per keyThe
idleTimeToLiveoption can now be a function that receives the key and returns a duration, allowing different TTL values for different resources.const map =yield *RcMap.make({lookup: (key: string) => acquireResource(key),idleTimeToLive: (key: string) => {if (key.startsWith("premium:")) return Duration.minutes(10)return Duration.minutes(1)}}) -
#5780
0d32048Thanks @mikearnaldi! - Fix annotateCurrentSpan, add Effect.currentPropagatedSpan
Patch Changes
-
#5780
0d32048Thanks @mikearnaldi! - Add logs to first propagated span, in the following case before this fix the log would not be added to thepspan becauseEffect.fnadds a fake span for the purpose of adding a stack frame.import { Effect } from "effect"const f = Effect.fn(function* () {yield* Effect.logWarning("FooBar")return yield* Effect.fail("Oops")})const p = f().pipe(Effect.withSpan("p"))
3.20.1
Patch Changes
-
#6133
add06f4Thanks @aniravi24! - FixEqual.equalscrash when comparingnullvalues insidestructuralRegion. Added null guard beforeObject.getPrototypeOfcalls to preventTypeError: Cannot convert undefined or null to object. -
#6093
a03b6a2Thanks @luchersou! - avoid class for PrettyError to preserve error.name
3.20.0
Minor Changes
- #6124
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.
3.19.19
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 leaked
3.19.18
Patch Changes
3.19.17
Patch Changes
- #6040
a8c436fThanks @jacobconley! - FixStream.decodeTextto correctly handle multi-byte UTF-8 characters split across chunk boundaries.
3.19.16
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
3.19.15
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 mode
3.19.14
Patch Changes
- #5924
488d6e8Thanks @mikearnaldi! - FixEffect.retryto respecttimes: 0option by using explicit undefined check instead of truthy check.
3.19.13
Patch Changes
-
#5911
77eeb86Thanks @mattiamanzati! - Add test for ensuring typeConstructor is attached -
#5910
287c32cThanks @mattiamanzati! - Add typeConstructor annotation for Schema
3.19.12
Patch Changes
3.19.11
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 #5883
3.19.10
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 object
3.19.9
Patch Changes
- #5875
3f9bbfeThanks @gcanti! - Fix the arbitrary generator for BigDecimal to allow negative scales.
3.19.8
Patch Changes
- #5815
f03b8e5Thanks @lokhmakov! - Prevent multiple iterations over the same Iterable in Array.intersectionWith and Array.differenceWith
3.19.7
Patch Changes
3.19.6
Patch Changes
3.19.5
Patch Changes
3.19.4
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 to control 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.
import { Effect, PartitionedSemaphore } from "effect"Effect.gen(function* () {const semaphore = yield* PartitionedSemaphore.make<string>({ permits: 5 })// Take the first 5 permits with key "A", then the following permits will be// equally distributed between all the keys using a round-robin strategyyield* Effect.log("A").pipe(Effect.delay(1000),semaphore.withPermits("A", 1),Effect.replicateEffect(15, { concurrency: "unbounded" }),Effect.fork)yield* Effect.log("B").pipe(Effect.delay(1000),semaphore.withPermits("B", 1),Effect.replicateEffect(10, { concurrency: "unbounded" }),Effect.fork)yield* Effect.log("C").pipe(Effect.delay(1000),semaphore.withPermits("C", 1),Effect.replicateEffect(10, { concurrency: "unbounded" }),Effect.fork)return yield* Effect.never}).pipe(Effect.runFork)
3.19.3
Patch Changes
- #5712
7d28a90Thanks @gcanti! - Use standard formatting function in Config error messages, closes #5709
3.19.2
Patch Changes
-
#5703
374f58cThanks @tim-smart! - preserve Layer.mergeAll context order -
#5703
374f58cThanks @tim-smart! - ensure FiberHandle.run state transition is atomic
3.19.1
Patch Changes
3.19.0
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 module
Patch Changes
3.18.5
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:- JSON Schema 2019-09
- OpenAPI 3.1
3.18.4
Patch Changes
-
#5617
6ae2f5dThanks @gcanti! - JSONSchema: Fix issue where invaliddefaults were included in the output.Now they are ignored, similar to invalid
examples.Before
import { JSONSchema, Schema } from "effect"const schema = Schema.NonEmptyString.annotations({default: ""})const jsonSchema = JSONSchema.make(schema)console.log(JSON.stringify(jsonSchema, null, 2))/*Output:{"$schema": "http://json-schema.org/draft-07/schema#","type": "string","description": "a non empty string","title": "nonEmptyString","default": "","minLength": 1}*/After
import { JSONSchema, Schema } from "effect"const schema = Schema.NonEmptyString.annotations({default: ""})const jsonSchema = JSONSchema.make(schema)console.log(JSON.stringify(jsonSchema, null, 2))/*Output:{"$schema": "http://json-schema.org/draft-07/schema#","type": "string","description": "a non empty string","title": "nonEmptyString","minLength": 1}*/
3.18.3
Patch Changes
-
#5612
25fab81Thanks @gcanti! - Fix JSON Schema generation withtopLevelReferenceStrategy: "skip", closes #5611This patch fixes a bug that occurred when generating JSON Schemas with nested schemas that had identifiers, while using
topLevelReferenceStrategy: "skip".Previously, the generator would still output
$refentries even though references were supposed to be skipped, leaving unresolved definitions.Before
import { JSONSchema, Schema } from "effect"const A = Schema.Struct({ value: Schema.String }).annotations({identifier: "A"})const B = Schema.Struct({ a: A }).annotations({ identifier: "B" })const definitions = {}console.log(JSON.stringify(JSONSchema.fromAST(B.ast, {definitions,topLevelReferenceStrategy: "skip"}),null,2))/*{"type": "object","required": ["a"],"properties": {"a": {"$ref": "#/$defs/A"}},"additionalProperties": false}*/console.log(definitions)/*{A: {type: "object",required: ["value"],properties: { value: [Object] },additionalProperties: false}}*/After
import { JSONSchema, Schema } from "effect"const A = Schema.Struct({ value: Schema.String }).annotations({identifier: "A"})const B = Schema.Struct({ a: A }).annotations({ identifier: "B" })const definitions = {}console.log(JSON.stringify(JSONSchema.fromAST(B.ast, {definitions,topLevelReferenceStrategy: "skip"}),null,2))/*{"type": "object","required": ["a"],"properties": {"a": {"type": "object","required": ["value"],"properties": {"value": { "type": "string" }},"additionalProperties": false}},"additionalProperties": false}*/console.log(definitions)/*{}*/Now schemas are correctly inlined, and no leftover
$refentries or unused definitions remain.
3.18.2
Patch Changes
3.18.1
Patch Changes
3.18.0
Minor Changes
-
#5302
1c6ab74Thanks @schickling! - Add experimental Graph module with comprehensive graph data structure supportThis experimental module provides:
- Directed and undirected graph support
- Immutable and mutable graph variants
- Type-safe node and edge operations
- Graph algorithms: DFS, BFS, shortest paths, cycle detection, etc.
Example usage:
import { Graph } from "effect"// Create a graph with mutationsconst graph = Graph.directed<string, number>((mutable) => {const nodeA = Graph.addNode(mutable, "Node A")const nodeB = Graph.addNode(mutable, "Node B")Graph.addEdge(mutable, nodeA, nodeB, 5)})console.log(`Nodes: ${Graph.nodeCount(graph)}, Edges: ${Graph.edgeCount(graph)}`) -
#5302
70fe803Thanks @mikearnaldi! - Automatically set otel parent when present as external span -
#5302
c296e32Thanks @tim-smart! - add Effect.Semaphore.resize -
#5302
a098ddfThanks @mikearnaldi! - Introduce ReadonlyTag as the covariant side of a tag, enables:import type { Context } from "effect"import { Effect } from "effect"export class MyRequirement extends Effect.Service<MyRequirement>()("MyRequirement",{ succeed: () => 42 }) {}export class MyUseCase extends Effect.Service<MyUseCase>()("MyUseCase", {dependencies: [MyRequirement.Default],effect: Effect.gen(function* () {const requirement = yield* MyRequirementreturn Effect.fn("MyUseCase.execute")(function* () {return requirement()})})}) {}export function effectHandler<I, Args extends Array<any>, A, E, R>(service: Context.ReadonlyTag<I, (...args: Args) => Effect.Effect<A, E, R>>) {return Effect.fn("effectHandler")(function* (...args: Args) {const execute = yield* serviceyield* execute(...args)})}export const program = effectHandler(MyUseCase)
3.17.14
Patch Changes
3.17.13
Patch Changes
3.17.12
Patch Changes
3.17.11
Patch Changes
-
#5449
fb5e414Thanks @tim-smart! - Simplify Effect.raceAll implementation, ensure children fibers are awaited -
#5451
018363bThanks @mikearnaldi! - Fix Predicate.isIterable to allow strings
3.17.10
Patch Changes
-
#5368
3b26094Thanks @gcanti! - ## Annotation BehaviorWhen you call
.annotationson a schema, any identifier annotations that were previously set will now be removed. Identifiers are now always tied to the schema’sastreference (this was the intended behavior).Example
import { JSONSchema, Schema } from "effect"const schema = Schema.URLconsole.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","$defs": {"URL": {"type": "string","description": "a string to be decoded into a URL"}},"$ref": "#/$defs/URL"}*/const annotated = Schema.URL.annotations({ description: "description" })console.log(JSON.stringify(JSONSchema.make(annotated), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "string","description": "description"}*/OpenAPI 3.1 Compatibility
OpenAPI 3.1 does not allow
nullable: true. Instead, the schema will now correctly use{ "type": "null" }inside a union.Example
import { JSONSchema, Schema } from "effect"const schema = Schema.NullOr(Schema.String)console.log(JSON.stringify(JSONSchema.fromAST(schema.ast, {definitions: {},target: "openApi3.1"}),null,2))/*{"anyOf": [{"type": "string"},{"type": "null"}]}*/Schema Description Deduplication
Previously, when a schema was reused, only the first description was kept. Now, every property keeps its own description, even if the schema is reused.
Example
import { JSONSchema, Schema } from "effect"const schemaWithAnIdentifier = Schema.String.annotations({identifier: "my-id"})const schema = Schema.Struct({a: schemaWithAnIdentifier.annotations({description: "a-description"}),b: schemaWithAnIdentifier.annotations({description: "b-description"})})console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","required": ["a","b"],"properties": {"a": {"type": "string","description": "a-description"},"b": {"type": "string","description": "b-description"}},"additionalProperties": false}*/Fragment Detection in Non-Refinement Schemas
This patch fixes the issue where fragments (e.g.
jsonSchema.format) were not detected on non-refinement schemas.Example
import { JSONSchema, Schema } from "effect"const schema = Schema.UUID.pipe(Schema.compose(Schema.String),Schema.annotations({identifier: "UUID",title: "title",description: "description",jsonSchema: {format: "uuid" // fragment}}))console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","$defs": {"UUID": {"type": "string","description": "description","format": "uuid","pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","title": "title"}},"$ref": "#/$defs/UUID"}*/Nested Unions
Nested unions are no longer flattened. Instead, they remain as nested
anyOfarrays. This is fine because JSON Schema allows nestedanyOf.Example
import { JSONSchema, Schema } from "effect"const schema = Schema.Union(Schema.NullOr(Schema.String),Schema.Literal("a", null))console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","anyOf": [{"anyOf": [{"type": "string"},{"type": "null"}]},{"anyOf": [{"type": "string","enum": ["a"]},{"type": "null"}]}]}*/Refinements without
jsonSchemaannotationRefinements that don’t provide a
jsonSchemaannotation no longer cause errors. They are simply ignored, so you can still generate a JSON Schema even when refinements can’t easily be expressed. -
#5437
a33e491Thanks @tim-smart! - ensure Effect.promise captures span on defect
3.17.9
Patch Changes
3.17.8
Patch Changes
3.17.7
Patch Changes
3.17.6
Patch Changes
- #5322
f187941Thanks @beezee! - Use non-greedy matching for Schema.String in Schema.TemplateLiteralParser
3.17.5
Patch Changes
3.17.4
Patch Changes
3.17.3
Patch Changes
-
#5275
3504555Thanks @taylornz! - fix DateTime.makeZoned handling of DST transitions -
#5282
f6c7ca7Thanks @beezee! - Improve inference on Metric.trackSuccessWith for use in Effect.pipe(…) -
#5275
3504555Thanks @taylornz! - add DateTime.Disambiguation for handling DST edge casesAdded four disambiguation strategies to
DateTime.Zonedconstructors for handling DST edge cases:'compatible'- Maintains backward compatibility'earlier'- Choose earlier time during ambiguous periods (default)'later'- Choose later time during ambiguous periods'reject'- Throw error for ambiguous times
3.17.2
Patch Changes
3.17.1
Patch Changes
3.17.0
Minor Changes
-
#4949
40c3c87Thanks @fubhy! - AddedRandom.fixedto create a version of theRandomservice with fixed values for testing. -
#4949
ed2c74aThanks @dmaretskyi! - AddStruct.entriesfunction -
#4949
073a1b8Thanks @f15u! - AddLayer.mockCreates a mock layer for testing purposes. You can provide a partial implementation of the service, and any methods not provided will throw an
UnimplementedErrordefect when called.import { Context, Effect, Layer } from "effect"class MyService extends Context.Tag("MyService")<MyService,{one: Effect.Effect<number>two(): Effect.Effect<number>}>() {}const MyServiceTest = Layer.mock(MyService, {two: () => Effect.succeed(2)}) -
#4949
f382e99Thanks @KhraksMamtsov! - Schedule output has been added intoCurrentIterationMetadata -
#4949
e8c7ba5Thanks @mikearnaldi! - Remove global state index by version, make version mismatch a warning message -
#4949
7e10415Thanks @devinjameson! - Array: add findFirstWithIndex function -
#4949
e9bdeceThanks @vinassefranche! - Add HashMap.countByimport { HashMap } from "effect"const map = HashMap.make([1, "a"], [2, "b"], [3, "c"])const result = HashMap.countBy(map, (_v, key) => key % 2 === 1)console.log(result) // 2 -
#4949
8d95eb0Thanks @tim-smart! - add Effect.ensure{Success,Error,Requirements}Type, for constraining Effect types
3.16.17
Patch Changes
-
#5246
aaa6ad0Thanks @mikearnaldi! - Copy over apply, bind, call into service proxy -
#5158
5b74ea5Thanks @cyberixae! - Clarify Tuple length requirements
3.16.16
Patch Changes
3.16.15
Patch Changes
- #5222
15df9bfThanks @gcanti! - Schema.attachPropertySignature: simplify signature and fix parameter type to use Schema instead of SchemaClass
3.16.14
Patch Changes
-
#5213
f5dfabfThanks @gcanti! - Fix incorrect schema ID annotation inSchema.lessThanOrEqualToDate, closes #5212 -
#5192
17a5ea8Thanks @nikelborm! - Updated deprecated OTel Resource attributes names and values.Many of the attributes have undergone the process of deprecation not once, but twice. Most of the constants holding attribute names have been renamed. These are minor changes.
Additionally, there were numerous changes to the attribute keys themselves. These changes can be considered major.
In the
@opentelemetry/semantic-conventionspackage, new attributes having ongoing discussion about them are going through a process called incubation, until a consensus about their necessity and form is reached. Otel team recommends devs to copy them directly into their code. Luckily, it’s not necessary because all of the new attribute names and values came out of this process (some of them were changed again) and are now considered stable.Reasoning for minor version bump
Package Major attribute changes Major value changes Clickhouse client db.system->db.system.name
db.name->db.namespaceMsSQL client db.system->db.system.name
db.name->db.namespacemssql->microsoft.sql_serverMySQL client db.system->db.system.name
db.name->db.namespacePg client db.system->db.system.name
db.name->db.namespaceBun SQLite client db.system->db.system.nameNode SQLite client db.system->db.system.nameReact.Native SQLite client db.system->db.system.nameWasm SQLite client db.system->db.system.nameSQLite Do client db.system->db.system.nameLibSQL client db.system->db.system.nameD1 client db.system->db.system.nameKysely client db.statement->db.query.text@effect/sql db.statement->db.query.text
db.operation->db.operation.name -
#5211
d25f22bThanks @mattiamanzati! - Removed some unnecessary single-arg pipe calls
3.16.13
Patch Changes
-
#5097
c1c05a8Thanks @tim-smart! - remove completion helper overload from Effect.catchTag, to fix Effect.fn inference -
#5157
81fe4a2Thanks @cyberixae! - Clarify Array rotate example
3.16.12
Patch Changes
- #5149
905da99Thanks @milkyskies! - Fix$matchto disallow invalid_tagkeys inTaggedEnumhandler objects.
3.16.11
Patch Changes
-
#5127
99590a6Thanks @tim-smart! - fix DateTime zone check to includes zones without ”:” -
#5123
6c3e24cThanks @gcanti! - Schema.equivalence: handle non-array and non-record inputs
3.16.10
Patch Changes
3.16.9
Patch Changes
-
#5081
5137c70Thanks @tim-smart! - expose Stream.provideSomeContext -
#5082
c23d25cThanks @tim-smart! - fix Effect.filterOrFail return type inference
3.16.8
Patch Changes
-
#5047
8cb98d5Thanks @tim-smart! - ensure Stream.toReadableStream ignores empty chunks -
#5046
db2dd3cThanks @tim-smart! - ignore ReadableStream defect in bun due to controller bug
3.16.7
Patch Changes
3.16.6
Patch Changes
-
#5026
a5f7595Thanks @KhraksMamtsov! - Add missing type variances -
#5031
a02470cThanks @KhraksMamtsov! - Fix Context.add & Context.make signatures -
#5003
f891d45Thanks @beezee! - Ensure binding__proto__to lexical scope in do notation is preserved bybindandlet
3.16.5
Patch Changes
- #5008
bf418efThanks @jdharrisnz! - Record.findFirst: Accept ReadonlyRecord type input and optimise the loop
3.16.4
Patch Changes
-
#4994
74ab9a0Thanks @tim-smart! - don’t inherit interruption flag in Effect.addFinalizer -
#4986
770008eThanks @tim-smart! - ensure Cause.YieldableError extends Error
3.16.3
Patch Changes
-
#4952
87722fcThanks @tim-smart! - improve Effect.catchTag auto-completion -
#4950
36217eeThanks @tim-smart! - removethistype propagation from Effect.fn
3.16.2
Patch Changes
3.16.1
Patch Changes
-
#4936
71174d0Thanks @mattiamanzati! - Escape JSON Schema $id for empty struct -
#4937
d615e6eThanks @tim-smart! - adjust ExecutionPlanprovides&requirementstypes
3.16.0
Minor Changes
-
#4891
ee0bd5dThanks @KhraksMamtsov! -Schedule.CurrentIterationMetadatahas been addedimport { Effect, Schedule } from "effect"Effect.gen(function* () {const currentIterationMetadata = yield* Schedule.CurrentIterationMetadata// ^? Schedule.IterationMetadataconsole.log(currentIterationMetadata)}).pipe(Effect.repeat(Schedule.recurs(2)))// {// elapsed: Duration.zero,// elapsedSincePrevious: Duration.zero,// input: undefined,// now: 0,// recurrence: 0,// start: 0// }// {// elapsed: Duration.zero,// elapsedSincePrevious: Duration.zero,// input: undefined,// now: 0,// recurrence: 1,// start: 0// }// {// elapsed: Duration.zero,// elapsedSincePrevious: Duration.zero,// input: undefined,// now: 0,// recurrence: 2,// start: 0// }Effect.gen(function* () {const currentIterationMetadata = yield* Schedule.CurrentIterationMetadataconsole.log(currentIterationMetadata)}).pipe(Effect.schedule(Schedule.intersect(Schedule.fibonacci("1 second"), Schedule.recurs(3))))// {// elapsed: Duration.zero,// elapsedSincePrevious: Duration.zero,// recurrence: 1,// input: undefined,// now: 0,// start: 0// },// {// elapsed: Duration.seconds(1),// elapsedSincePrevious: Duration.seconds(1),// recurrence: 2,// input: undefined,// now: 1000,// start: 0// },// {// elapsed: Duration.seconds(2),// elapsedSincePrevious: Duration.seconds(1),// recurrence: 3,// input: undefined,// now: 2000,// start: 0// } -
#4891
5189800Thanks @vinassefranche! - Add HashMap.hasBy helperimport { HashMap } from "effect"const hm = HashMap.make([1, "a"])HashMap.hasBy(hm, (value, key) => value === "a" && key === 1) // -> trueHashMap.hasBy(hm, (value) => value === "b") // -> false -
#4891
58bfeaaThanks @jrudder! - Add round and sumAll to BigDecimal -
#4891
194d748Thanks @tim-smart! - add ExecutionPlan moduleA
ExecutionPlancan be used withEffect.withExecutionPlanorStream.withExecutionPlan, allowing you to provide different resources for each step of execution until the effect succeeds or the plan is exhausted.import { type AiLanguageModel } from "@effect/ai"import type { Layer } from "effect"import { Effect, ExecutionPlan, Schedule } from "effect"declare const layerBad: Layer.Layer<AiLanguageModel.AiLanguageModel>declare const layerGood: Layer.Layer<AiLanguageModel.AiLanguageModel>const ThePlan = ExecutionPlan.make({// First try with the bad layer 2 times with a 3 second delay between attemptsprovide: layerBad,attempts: 2,schedule: Schedule.spaced(3000)},// Then try with the bad layer 3 times with a 1 second delay between attempts{provide: layerBad,attempts: 3,schedule: Schedule.spaced(1000)},// Finally try with the good layer.//// If `attempts` is omitted, the plan will only attempt once, unless a schedule is provided.{provide: layerGood})declare const effect: Effect.Effect<void,never,AiLanguageModel.AiLanguageModel>const withPlan: Effect.Effect<void> = Effect.withExecutionPlan(effect,ThePlan) -
#4891
918c9eaThanks @thewilkybarkid! - Add Array.removeOption and Chunk.removeOption -
#4891
9198e6fThanks @TylorS! - Add parameter support for Effect.ServiceThis allows you to pass parameters to the
effect&scopedEffect.Service constructors, which will also be reflected in the.Defaultlayer.import type { Layer } from "effect"import { Effect } from "effect"class NumberService extends Effect.Service<NumberService>()("NumberService", {// You can now pass a function to the `effect` and `scoped` constructorseffect: Effect.fn(function* (input: number) {return {get: Effect.succeed(`The number is: ${input}`)} as const})}) {}// Pass the arguments to the `Default` layerconst CoolNumberServiceLayer: Layer.Layer<NumberService> =NumberService.Default(6942) -
#4891
2a370bfThanks @vinassefranche! - AddIterable.countByandArray.countByimport { Array, Iterable } from "effect"const resultArray = Array.countBy([1, 2, 3, 4, 5], (n) => n % 2 === 0)console.log(resultArray) // 2const resultIterable = resultIterable.countBy([1, 2, 3, 4, 5],(n) => n % 2 === 0)console.log(resultIterable) // 2 -
#4891
58ccb91Thanks @KhraksMamtsov! - TheConfig.portandConfig.brandedfunctions have been added.import { Brand, Config } from "effect"type DbPort = Brand.Branded<number, "DbPort">const DbPort = Brand.nominal<DbPort>()const dbPort: Config.Config<DbPort> = Config.branded(Config.port("DB_PORT"),DbPort)import { Brand, Config } from "effect"type Port = Brand.Branded<number, "Port">const Port = Brand.refined<Port>((num) =>!Number.isNaN(num) && Number.isInteger(num) && num >= 1 && num <= 65535,(n) => Brand.error(`Expected ${n} to be an TCP port`))const dbPort: Config.Config<Port> = Config.number("DB_PORT").pipe(Config.branded(Port)) -
#4891
fd47834Thanks @tim-smart! - return a proxy Layer from LayerMap serviceThe new usage is:
import { NodeRuntime } from "@effect/platform-node"import { Context, Effect, FiberRef, Layer, LayerMap } from "effect"class Greeter extends Context.Tag("Greeter")<Greeter,{greet: Effect.Effect<string>}>() {}// create a service that wraps a LayerMapclass GreeterMap extends LayerMap.Service<GreeterMap>()("GreeterMap", {// define the lookup function for the layer map//// The returned Layer will be used to provide the Greeter service for the// given name.lookup: (name: string) =>Layer.succeed(Greeter, {greet: Effect.succeed(`Hello, ${name}!`)}),// If a layer is not used for a certain amount of time, it can be removedidleTimeToLive: "5 seconds",// Supply the dependencies for the layers in the LayerMapdependencies: []}) {}// usageconst program: Effect.Effect<void, never, GreeterMap> = Effect.gen(function* () {// access and use the Greeter serviceconst greeter = yield* Greeteryield* Effect.log(yield* greeter.greet)}).pipe(// use the GreeterMap service to provide a variant of the Greeter serviceEffect.provide(GreeterMap.get("John")))// run the programprogram.pipe(Effect.provide(GreeterMap.Default), NodeRuntime.runMain)
3.15.5
Patch Changes
3.15.4
Patch Changes
-
#4869
f570554Thanks @IGassmann! - Fix summary metric’s min/max values when no samples -
#4917
78047e8Thanks @KhraksMamtsov! - Fix Effect.fn inference in case of use with pipe functions
3.15.3
Patch Changes
3.15.2
Patch Changes
- #4659
b8722b8Thanks @KhraksMamtsov! - - TheHashMap.has/getfamily has become more type-safe.- Fix the related type errors in TestAnnotationsMap.ts.
3.15.1
Patch Changes
-
#4870
787ce70Thanks @tim-smart! - ensure generic refinements work with Effect.filterOr* -
#4857
1269641Thanks @tim-smart! - preserve explicitthisin Effect.fn apis -
#4857
1269641Thanks @tim-smart! - use span name as function name in Effect.fn
3.15.0
Minor Changes
-
#4641
c654595Thanks @tim-smart! - Add Layer.setRandom, for over-riding the default Random service -
#4641
d9f5deaThanks @KhraksMamtsov! -Brand.unbrandedgetter has been added -
#4641
49aa723Thanks @titouancreach! - Add Either.transposeMapOption -
#4641
74c14d0Thanks @vinassefranche! - Add Record.findFirst -
#4641
e4f49b6Thanks @KhraksMamtsov! - Defaultnevertype has been added toMutableHasMap.empty&MutableList.emptyctors -
#4641
6f02224Thanks @tim-smart! - add Stream.toAsyncIterable* apisimport { Stream } from "effect"// Will print:// 1// 2// 3const stream = Stream.make(1, 2, 3)for await (const result of Stream.toAsyncIterable(stream)) {console.log(result)} -
#4641
1dcfd41Thanks @tim-smart! - improve Effect.filter* types to exclude candidates in fallback functions -
#4641
b21ab16Thanks @KhraksMamtsov! - Simplified the creation of pipeable classes.class MyClass extends Pipeable.Class() {constructor(public a: number) {super()}methodA() {return this.a}}console.log(new MyClass(2).pipe((x) => x.methodA())) // 2class A {constructor(public a: number) {}methodA() {return this.a}}class B extends Pipeable.Class(A) {constructor(private b: string) {super(b.length)}methodB() {return [this.b, this.methodA()]}}console.log(new B("pipe").pipe((x) => x.methodB())) // ['pipe', 4] -
#4641
fcf1822Thanks @KhraksMamtsov! - propertymessage: stringhas been added toConfigError.And&Ormembers -
#4641
0061dd1Thanks @tim-smart! - allow catching multiple different tags in Effect.catchTag -
#4641
8421e6eThanks @mlegenhausen! - ExposeCause.isTimeoutException -
#4641
fa10f56Thanks @thewilkybarkid! - Support multiple values in Function.apply
3.14.22
Patch Changes
-
#4847
24a9ebbThanks @gcanti! - Schema: TaggedError no longer crashes when themessagefield is explicitly defined.If you define a
messagefield in your schema,TaggedErrorwill no longer add its ownmessagegetter. This avoids a stack overflow caused by infinite recursion.Before
import { Schema } from "effect"class Todo extends Schema.TaggedError<Todo>()("Todo", {message: Schema.optional(Schema.String)}) {}// ❌ Throws "Maximum call stack size exceeded"console.log(Todo.make({}))After
// ✅ Works correctlyconsole.log(Todo.make({}))
3.14.21
Patch Changes
3.14.20
Patch Changes
-
#4832
17e2f30Thanks @gcanti! - JSONSchema: respect annotations on declarations.Previously, annotations added with
.annotations(...)onSchema.declare(...)were not included in the generated JSON Schema output.Before
import { JSONSchema, Schema } from "effect"class MyType {}const schema = Schema.declare<MyType>((x) => x instanceof MyType, {jsonSchema: {type: "my-type"}}).annotations({title: "My Title",description: "My Description"})console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "my-type"}*/After
import { JSONSchema, Schema } from "effect"class MyType {}const schema = Schema.declare<MyType>((x) => x instanceof MyType, {jsonSchema: {type: "my-type"}}).annotations({title: "My Title",description: "My Description"})console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","description": "My Description","title": "My Title","type": "my-type"}*/
3.14.19
Patch Changes
-
#4822
056a910Thanks @KhraksMamtsov! - fixLayer.discardjsdoc -
#4816
3273d57Thanks @mikearnaldi! - Fix captureStackTrace for bun
3.14.18
Patch Changes
3.14.17
Patch Changes
-
#4806
0b54681Thanks @thewilkybarkid! - Match the JS API for locale arguments -
#4805
41a59d5Thanks @mikearnaldi! - Implement stack cleaning for Bun
3.14.16
Patch Changes
3.14.15
Patch Changes
-
#4798
239cc99Thanks @gcanti! - Schema: respect custom constructors inmakeforSchema.Class, closes #4797Previously, the
makemethod did not support custom constructors defined usingSchema.ClassorSchema.TaggedError, resulting in type errors when passing custom constructor arguments.This update ensures that
makenow correctly uses the class constructor, allowing custom parameters and initialization logic.Before
import { Schema } from "effect"class MyError extends Schema.TaggedError<MyError>()("MyError", {message: Schema.String}) {constructor({ a, b }: { a: string; b: string }) {super({ message: `${a}:${b}` })}}// @ts-expect-error: Object literal may only specify known properties, and 'a' does not exist in type '{ readonly message: string; }'.ts(2353)MyError.make({ a: "1", b: "2" })After
import { Schema } from "effect"class MyError extends Schema.TaggedError<MyError>()("MyError", {message: Schema.String}) {constructor({ a, b }: { a: string; b: string }) {super({ message: `${a}:${b}` })}}console.log(MyError.make({ a: "1", b: "2" }).message)// Output: "1:2" -
#4687
8b6c947Thanks @KhraksMamtsov! - Modify the signatures ofEither.liftPredicateandEffect.predicateto make them reusable. -
#4794
c50a63bThanks @IGassmann! - Fix summary metric’s quantile value calculation
3.14.14
Patch Changes
3.14.13
Patch Changes
-
#4777
ee77788Thanks @gcanti! - JSONSchema: applyencodeOptionto each example and retain successful results.Example
import { JSONSchema, Schema } from "effect"const schema = Schema.Struct({a: Schema.propertySignature(Schema.BigInt).annotations({examples: [1n, 2n]})})console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","$defs": {"BigInt": {"type": "string","description": "a string to be decoded into a bigint"}},"type": "object","required": ["a"],"properties": {"a": {"$ref": "#/$defs/BigInt","examples": ["1","2"]}},"additionalProperties": false}*/ -
#4701
5fce6baThanks @gcanti! - FixJSONSchema.makeforExitschemas.Before
import { JSONSchema, Schema } from "effect"const schema = Schema.Exit({failure: Schema.String,success: Schema.Number,defect: Schema.Defect})console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*throwsError: Missing annotationat path: ["cause"]["left"]details: Generating a JSON Schema for this schema requires an "identifier" annotationschema (Suspend): CauseEncoded<string>*/After
import { JSONSchema, Schema } from "effect"const schema = Schema.Exit({failure: Schema.String,success: Schema.Number,defect: Schema.Defect})console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*Output:{"$schema": "http://json-schema.org/draft-07/schema#","$defs": {"CauseEncoded0": {"anyOf": [{"type": "object","required": ["_tag"],"properties": {"_tag": {"type": "string","enum": ["Empty"]}},"additionalProperties": false},{"type": "object","required": ["_tag","error"],"properties": {"_tag": {"type": "string","enum": ["Fail"]},"error": {"type": "string"}},"additionalProperties": false},{"type": "object","required": ["_tag","defect"],"properties": {"_tag": {"type": "string","enum": ["Die"]},"defect": {"$ref": "#/$defs/Defect"}},"additionalProperties": false},{"type": "object","required": ["_tag","fiberId"],"properties": {"_tag": {"type": "string","enum": ["Interrupt"]},"fiberId": {"$ref": "#/$defs/FiberIdEncoded"}},"additionalProperties": false},{"type": "object","required": ["_tag","left","right"],"properties": {"_tag": {"type": "string","enum": ["Sequential"]},"left": {"$ref": "#/$defs/CauseEncoded0"},"right": {"$ref": "#/$defs/CauseEncoded0"}},"additionalProperties": false},{"type": "object","required": ["_tag","left","right"],"properties": {"_tag": {"type": "string","enum": ["Parallel"]},"left": {"$ref": "#/$defs/CauseEncoded0"},"right": {"$ref": "#/$defs/CauseEncoded0"}},"additionalProperties": false}],"title": "CauseEncoded<string>"},"Defect": {"$id": "/schemas/unknown","title": "unknown"},"FiberIdEncoded": {"anyOf": [{"$ref": "#/$defs/FiberIdNoneEncoded"},{"$ref": "#/$defs/FiberIdRuntimeEncoded"},{"$ref": "#/$defs/FiberIdCompositeEncoded"}]},"FiberIdNoneEncoded": {"type": "object","required": ["_tag"],"properties": {"_tag": {"type": "string","enum": ["None"]}},"additionalProperties": false},"FiberIdRuntimeEncoded": {"type": "object","required": ["_tag","id","startTimeMillis"],"properties": {"_tag": {"type": "string","enum": ["Runtime"]},"id": {"$ref": "#/$defs/Int"},"startTimeMillis": {"$ref": "#/$defs/Int"}},"additionalProperties": false},"Int": {"type": "integer","description": "an integer","title": "int"},"FiberIdCompositeEncoded": {"type": "object","required": ["_tag","left","right"],"properties": {"_tag": {"type": "string","enum": ["Composite"]},"left": {"$ref": "#/$defs/FiberIdEncoded"},"right": {"$ref": "#/$defs/FiberIdEncoded"}},"additionalProperties": false}},"anyOf": [{"type": "object","required": ["_tag","cause"],"properties": {"_tag": {"type": "string","enum": ["Failure"]},"cause": {"$ref": "#/$defs/CauseEncoded0"}},"additionalProperties": false},{"type": "object","required": ["_tag","value"],"properties": {"_tag": {"type": "string","enum": ["Success"]},"value": {"type": "number"}},"additionalProperties": false}],"title": "ExitEncoded<number, string, Defect>"}*/ -
#4775
570e45fThanks @gcanti! - JSONSchema: preserve original key name when usingfromKeyfollowed byannotations, closes #4774.Before:
import { JSONSchema, Schema } from "effect"const schema = Schema.Struct({a: Schema.propertySignature(Schema.String).pipe(Schema.fromKey("b")).annotations({})})console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","required": ["a"],"properties": {"a": {"type": "string"}},"additionalProperties": false}*/After:
import { JSONSchema, Schema } from "effect"const schema = Schema.Struct({a: Schema.propertySignature(Schema.String).pipe(Schema.fromKey("b")).annotations({})})console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","required": ["b"],"properties": {"b": {"type": "string"}},"additionalProperties": false}*/
3.14.12
Patch Changes
-
#4770
c2ad9eeThanks @gcanti! - Fixes a bug where non existing properties were allowed in themakeconstructor of aSchema.Class, closes #4767.Example
import { Schema } from "effect"class A extends Schema.Class<A>("A")({a: Schema.String}) {}A.make({a: "a",// @ts-expect-error: Object literal may only specify known properties, and 'b' does not exist in type '{ readonly a: string; }'.ts(2353)b: "b"}) -
#4735
9c68654Thanks @suddenlyGiovanni! - ImproveNumbermodule with comprehensive TsDocs and type-level tests
3.14.11
Patch Changes
3.14.10
Patch Changes
3.14.9
Patch Changes
3.14.8
Patch Changes
3.14.7
Patch Changes
3.14.6
Patch Changes
-
#4674
47618c1Thanks @suddenlyGiovanni! - Improved TsDoc documentation forMutableHashSetmodule. -
#4699
6077882Thanks @gcanti! - Fix JSONSchema generation for record values that includeundefined, closes #4697.Before
import { JSONSchema, Schema } from "effect"const schema = Schema.partial(Schema.Struct({ foo: Schema.Number },{key: Schema.String,value: Schema.Number}))console.log(JSON.stringify(JSONSchema.make(schema), null, 2))// throwsAfter
import { JSONSchema, Schema } from "effect"const schema = Schema.partial(Schema.Struct({ foo: Schema.Number },{key: Schema.String,value: Schema.Number}))console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*Output:{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","required": [],"properties": {"foo": {"type": "number"}},"additionalProperties": {"type": "number"}}*/
3.14.5
Patch Changes
-
#4676
40dbfefThanks @tim-smart! - allow Effect.fnUntraced to return non-effects -
#4682
5a5ebddThanks @thewilkybarkid! - ensure Equal considers URL by value
3.14.4
Patch Changes
- #4667
e4ba2c6Thanks @suddenlyGiovanni! - Fix:HashSet.mdapi docs; previously broken by issue with Docgen JsDoc parser.
3.14.3
Patch Changes
-
#4664
37aa8e1Thanks @suddenlyGiovanni! - Improved TsDoc documentation forHashSetmodule. -
#4670
34f03d6Thanks @tim-smart! - fix Data.TaggedEnum with generics regression
3.14.2
Patch Changes
-
#4646
f87991bThanks @gcanti! - SchemaAST: add missinggetSchemaIdAnnotationAPI -
#4646
f87991bThanks @gcanti! - Arbitrary: fix bug where annotations were ignored.Before
import { Arbitrary, Schema } from "effect"const schema = Schema.Int.annotations({arbitrary: (_, ctx) => (fc) => {console.log("context: ", ctx)return fc.integer()}}).pipe(Schema.greaterThan(0), Schema.lessThan(10))Arbitrary.make(schema)// No output ❌After
import { Arbitrary, Schema } from "effect"const schema = Schema.Int.annotations({arbitrary: (_, ctx) => (fc) => {console.log("context: ", ctx)return fc.integer()}}).pipe(Schema.greaterThan(0), Schema.lessThan(10))Arbitrary.make(schema)/*context: {maxDepth: 2,constraints: {_tag: 'NumberConstraints',constraints: { min: 0, minExcluded: true, max: 10, maxExcluded: true },isInteger: true}}*/ -
#4648
0a3e3e1Thanks @gcanti! - Schema:standardSchemaV1now includes the schema, closes #4494.This update fixes an issue where passing
Schema.standardSchemaV1(...)directly toJSONSchema.makewould throw aTypeError. The schema was missing from the returned object, causing the JSON schema generation to fail.Now
standardSchemaV1includes the schema itself, so it can be used withJSONSchema.makewithout issues.Example
import { JSONSchema, Schema } from "effect"const Person = Schema.Struct({name: Schema.optionalWith(Schema.NonEmptyString, { exact: true })})const standardSchema = Schema.standardSchemaV1(Person)console.log(JSONSchema.make(standardSchema))/*{'$schema': 'http://json-schema.org/draft-07/schema#','$defs': {NonEmptyString: {type: 'string',description: 'a non empty string',title: 'nonEmptyString',minLength: 1}},type: 'object',required: [],properties: { name: { '$ref': '#/$defs/NonEmptyString' } },additionalProperties: false}*/
3.14.1
Patch Changes
3.14.0
Minor Changes
-
#4469
1f47e4eThanks @vinassefranche! - Add DateTime.nowAsDate creator -
#4469
26dd75fThanks @tim-smart! - expose the Layer.MemoMap via Layer.CurrentMemoMap to the layers being built -
#4469
04dff2dThanks @tim-smart! - add Tracer Span.addLinks, for dynamically linking spans -
#4469
ffaa3f3Thanks @vinassefranche! - Add Either.transposeOption -
#4469
ab957c1Thanks @vinassefranche! - Make TestClock.setTime accept a DateTime.Input -
#4469
35db9ceThanks @LaureRC! - Add Effect.transposeMapOption -
#4469
26dd75fThanks @tim-smart! - add LayerMap moduleA
LayerMapallows you to create a map of Layer’s that can be used to dynamically access resources based on a key.Here is an example of how you can use a
LayerMapto create a service that provides access to multiple OpenAI completions services.import { Completions } from "@effect/ai"import { OpenAiClient, OpenAiCompletions } from "@effect/ai-openai"import { FetchHttpClient } from "@effect/platform"import { NodeRuntime } from "@effect/platform-node"import { Config, Effect, Layer, LayerMap } from "effect"// create the openai client layerconst OpenAiLayer = OpenAiClient.layerConfig({apiKey: Config.redacted("OPENAI_API_KEY")}).pipe(Layer.provide(FetchHttpClient.layer))// create a service that wraps a LayerMapclass AiClients extends LayerMap.Service<AiClients>()("AiClients", {// this LayerMap will provide the ai Completions serviceprovides: Completions.Completions,// define the lookup function for the layer map//// The returned Layer will be used to provide the Completions service for the// given model.lookup: (model: OpenAiCompletions.Model) =>OpenAiCompletions.layer({ model }),// If a layer is not used for a certain amount of time, it can be removedidleTimeToLive: "5 seconds",// Supply the dependencies for the layers in the LayerMapdependencies: [OpenAiLayer]}) {}// usageEffect.gen(function* () {// access and use the generic Completions serviceconst ai = yield* Completions.Completionsconst response = yield* ai.create("Hello, world!")console.log(response.text)}).pipe(// use the AiClients service to provide a variant of the Completions serviceAiClients.provide("gpt-4o"),// provide the LayerMap serviceEffect.provide(AiClients.Default),NodeRuntime.runMain) -
#4469
baaab60Thanks @vinassefranche! - Make Runtime.run* apis dual
Patch Changes
3.13.12
Patch Changes
-
#4610
0c4803fThanks @gcanti! - Preserve specific annotations (e.g.,arbitrary) when usingSchema.typeSchema, closes #4609.Previously, annotations such as
arbitrarywere lost when callingSchema.typeSchemaon a transformation. This update ensures that certain annotations, which depend only on the “to” side of the transformation, are preserved.Annotations that are now retained:
examplesdefaultjsonSchemaarbitraryprettyequivalence
Example
Before
import { Arbitrary, FastCheck, Schema } from "effect"const schema = Schema.NumberFromString.annotations({arbitrary: () => (fc) => fc.constant(1)})const to = Schema.typeSchema(schema) // ❌ Annotation is lostconsole.log(FastCheck.sample(Arbitrary.make(to), 5))/*[2.5223372357846707e-44,-2.145443957806771e+25,-3.4028179901346956e+38,5.278086259208735e+29,1.8216880036222622e-44]*/After
import { Arbitrary, FastCheck, Schema } from "effect"const schema = Schema.NumberFromString.annotations({arbitrary: () => (fc) => fc.constant(1)})const to = Schema.typeSchema(schema) // ✅ Annotation is now preservedconsole.log(FastCheck.sample(Arbitrary.make(to), 5))/*[ 1, 1, 1, 1, 1 ]*/ -
#4607
6f65ac4Thanks @gcanti! - Add support forjsonSchemaannotations onSymbolFromSelfindex signatures.Before
import { JSONSchema, Schema } from "effect"const schema = Schema.Record({key: Schema.SymbolFromSelf.annotations({ jsonSchema: { type: "string" } }),value: Schema.Number})JSONSchema.make(schema)/*throws:Error: Unsupported index signature parameterschema (SymbolKeyword): symbol*/After
import { JSONSchema, Schema } from "effect"const schema = Schema.Record({key: Schema.SymbolFromSelf.annotations({ jsonSchema: { type: "string" } }),value: Schema.Number})console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*Output:{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","required": [],"properties": {},"additionalProperties": {"type": "number"},"propertyNames": {"type": "string"}}*/
3.13.11
Patch Changes
-
#4601
fad8ccaThanks @gcanti! - Schema: enhance the internalformatUnknownfunction to handle various types including iterables, classes, and additional edge cases.Before
import { Schema } from "effect"const schema = Schema.Array(Schema.Number)Schema.decodeUnknownSync(schema)(new Set([1, 2]))// throws Expected ReadonlyArray<number>, actual {}class A {constructor(readonly a: number) {}}Schema.decodeUnknownSync(schema)(new A(1))// throws Expected ReadonlyArray<number>, actual {"a":1}After
import { Schema } from "effect"const schema = Schema.Array(Schema.Number)Schema.decodeUnknownSync(schema)(new Set([1, 2]))// throws Expected ReadonlyArray<number>, actual Set([1,2])class A {constructor(readonly a: number) {}}Schema.decodeUnknownSync(schema)(new A(1))// throws Expected ReadonlyArray<number>, actual A({"a":1}) -
#4606
4296293Thanks @gcanti! - Fix issue with generic filters when generating arbitraries, closes #4605.Previously, applying a
filterto a schema when generating arbitraries could cause aTypeErrordue to missing properties. This fix ensures that arbitraries are generated correctly when filters are used.Before
import { Arbitrary, Schema } from "effect"const schema = Schema.BigIntFromSelf.pipe(Schema.filter(() => true))Arbitrary.make(schema)// TypeError: Cannot read properties of undefined (reading 'min')After
import { Arbitrary, Schema } from "effect"const schema = Schema.BigIntFromSelf.pipe(Schema.filter(() => true))const result = Arbitrary.make(schema) // Works correctly -
#4587
9c241abThanks @gcanti! - Schema: simplifyStructandRecordreturn types. -
#4591
082b0c1Thanks @IMax153! - Improve clarity of theTimeoutExceptionerror message -
#4604
be12983Thanks @gcanti! - Add support for refinements toSchema.omit, closes #4603.Before
import { Schema } from "effect"const schema = Schema.Struct({a: Schema.String,b: Schema.String})const omitted = schema.pipe(Schema.filter(() => true),Schema.omit("a"))console.log(String(omitted.ast))// {} ❌After
import { Schema } from "effect"const schema = Schema.Struct({a: Schema.String,b: Schema.String})const omitted = schema.pipe(Schema.filter(() => true),Schema.omit("a"))console.log(String(omitted.ast))// { readonly b: string } -
#4593
de88127Thanks @gcanti! - Schema: exportFieldtype.Useful for creating a type that can be used to add custom constraints to the fields of a struct.
import { Schema } from "effect"const f = <Fields extends Record<"a" | "b", Schema.Struct.Field>>(schema: Schema.Struct<Fields>) => {return schema.omit("a")}// ┌─── Schema.Struct<{ b: typeof Schema.Number; }>// ▼const result = f(Schema.Struct({ a: Schema.String, b: Schema.Number }))
3.13.10
Patch Changes
-
#4578
527c964Thanks @gcanti! - AllowtoStringMethod to Be Overridden in Schema Classes, closes #4577.Previously, attempting to override the
toStringmethod in schema classes caused aTypeErrorin the browser because the property was set as read-only (writable: false). This fix makestoStringwritable, allowing developers to override it when needed.
3.13.9
Patch Changes
3.13.8
Patch Changes
-
#4567
c65d336Thanks @rehos! - Schema:standardSchemaV1now returns all errors by default and supports custom options.The
standardSchemaV1now returns all validation errors by default (ParseOptions = { errors: "all" }). Additionally, it now accepts an optionaloverrideOptionsparameter, allowing you to customize the default parsing behavior as needed. -
#4565
22d2ebbThanks @gcanti! - ParseResult.ArrayFormatter: correct_tagfields forRefinementandTransformationissues, closes #4564.This update fixes an issue where
ParseResult.ArrayFormatterincorrectly labeled Refinement and Transformation errors asTypein the output.Before
import { Effect, ParseResult, Schema } from "effect"const schema = Schema.Struct({a: Schema.NonEmptyString,b: Schema.NumberFromString})const input = { a: "", b: "" }const program = Schema.decodeUnknown(schema, { errors: "all" })(input).pipe(Effect.catchTag("ParseError", (err) =>ParseResult.ArrayFormatter.formatError(err).pipe(Effect.map((err) => JSON.stringify(err, null, 2)))))program.pipe(Effect.runPromise).then(console.log)/*[{"_tag": "Type", ❌"path": ["a"],"message": "Expected a non empty string, actual \"\""},{"_tag": "Type", ❌"path": ["b"],"message": "Unable to decode \"\" into a number"}]*/After
import { Effect, ParseResult, Schema } from "effect"const schema = Schema.Struct({a: Schema.NonEmptyString,b: Schema.NumberFromString})const input = { a: "", b: "" }const program = Schema.decodeUnknown(schema, { errors: "all" })(input).pipe(Effect.catchTag("ParseError", (err) =>ParseResult.ArrayFormatter.formatError(err).pipe(Effect.map((err) => JSON.stringify(err, null, 2)))))program.pipe(Effect.runPromise).then(console.log)/*[{"_tag": "Refinement", ✅"path": ["a"],"message": "Expected a non empty string, actual \"\""},{"_tag": "Transformation", ✅"path": ["b"],"message": "Unable to decode \"\" into a number"}]*/
3.13.7
Patch Changes
-
#4540
840cc73Thanks @gcanti! - AddadditionalPropertiesStrategyoption toOpenApi.fromApi, closes #4531.This update introduces the
additionalPropertiesStrategyoption inOpenApi.fromApi, allowing control over how additional properties are handled in the generated OpenAPI schema.- When
"strict"(default), additional properties are disallowed ("additionalProperties": false). - When
"allow", additional properties are allowed ("additionalProperties": true), making APIs more flexible.
The
additionalPropertiesStrategyoption has also been added to:JSONSchema.fromASTOpenApiJsonSchema.makeWithDefs
Example
import {HttpApi,HttpApiEndpoint,HttpApiGroup,OpenApi} from "@effect/platform"import { Schema } from "effect"const api = HttpApi.make("api").add(HttpApiGroup.make("group").add(HttpApiEndpoint.get("get", "/").addSuccess(Schema.Struct({ a: Schema.String }))))const schema = OpenApi.fromApi(api, {additionalPropertiesStrategy: "allow"})console.log(JSON.stringify(schema, null, 2))/*{"openapi": "3.1.0","info": {"title": "Api","version": "0.0.1"},"paths": {"/": {"get": {"tags": ["group"],"operationId": "group.get","parameters": [],"security": [],"responses": {"200": {"description": "Success","content": {"application/json": {"schema": {"type": "object","required": ["a"],"properties": {"a": {"type": "string"}},"additionalProperties": true}}}},"400": {"description": "The request did not match the expected schema","content": {"application/json": {"schema": {"$ref": "#/components/schemas/HttpApiDecodeError"}}}}}}}},"components": {"schemas": {"HttpApiDecodeError": {"type": "object","required": ["issues","message","_tag"],"properties": {"issues": {"type": "array","items": {"$ref": "#/components/schemas/Issue"}},"message": {"type": "string"},"_tag": {"type": "string","enum": ["HttpApiDecodeError"]}},"additionalProperties": true,"description": "The request did not match the expected schema"},"Issue": {"type": "object","required": ["_tag","path","message"],"properties": {"_tag": {"type": "string","enum": ["Pointer","Unexpected","Missing","Composite","Refinement","Transformation","Type","Forbidden"],"description": "The tag identifying the type of parse issue"},"path": {"type": "array","items": {"$ref": "#/components/schemas/PropertyKey"},"description": "The path to the property where the issue occurred"},"message": {"type": "string","description": "A descriptive message explaining the issue"}},"additionalProperties": true,"description": "Represents an error encountered while parsing a value to match the schema"},"PropertyKey": {"anyOf": [{"type": "string"},{"type": "number"},{"type": "object","required": ["_tag","key"],"properties": {"_tag": {"type": "string","enum": ["symbol"]},"key": {"type": "string"}},"additionalProperties": true,"description": "an object to be decoded into a globally shared symbol"}]}},"securitySchemes": {}},"security": [],"tags": [{"name": "group"}]}*/ - When
-
#4541
9bf8a74Thanks @fubhy! - Disallowed excess properties for various function options -
#4554
87ba23cThanks @gcanti! - ConfigProvider:fromEnv: add missingPartialmodifier.
3.13.6
Patch Changes
-
#4551
3154ce4Thanks @gcanti! - Arbitrary:makecalled onSchema.Classnow respects property annotations, closes #4550.Previously, when calling
Arbitrary.makeon aSchema.Class, property-specific annotations (such asarbitrary) were ignored, leading to unexpected values in generated instances.Before
Even though
ahad anarbitraryannotation, the generated values were random:import { Arbitrary, FastCheck, Schema } from "effect"class Class extends Schema.Class<Class>("Class")({a: Schema.NumberFromString.annotations({arbitrary: () => (fc) => fc.constant(1)})}) {}console.log(FastCheck.sample(Arbitrary.make(Class), 5))/*Example Output:[Class { a: 2.6624670822171524e-44 },Class { a: 3.4028177873105996e+38 },Class { a: 3.402820626847944e+38 },Class { a: 3.783505853677006e-44 },Class { a: 3243685 }]*/After
Now, the values respect the
arbitraryannotation and return the expected constant:import { Arbitrary, FastCheck, Schema } from "effect"class Class extends Schema.Class<Class>("Class")({a: Schema.NumberFromString.annotations({arbitrary: () => (fc) => fc.constant(1)})}) {}console.log(FastCheck.sample(Arbitrary.make(Class), 5))/*[Class { a: 1 },Class { a: 1 },Class { a: 1 },Class { a: 1 },Class { a: 1 }]*/
3.13.5
Patch Changes
-
#4530
367bb35Thanks @tim-smart! - Match.tag + Match.withReturnType can use literals without as const -
#4543
6cf11c3Thanks @gcanti! - Preserve branded primitive types inDeepMutabletransformation, closes #4542.Previously, applying
DeepMutableto branded primitive types (e.g.,string & Brand.Brand<"mybrand">) caused unexpected behavior, whereStringprototype methods were incorrectly inherited.This fix ensures that branded types remain unchanged during transformation, preventing type inconsistencies.
Example
Before
import type { Brand, Types } from "effect"type T = string & Brand.Brand<"mybrand">/*type Result = {[x: number]: string;toString: () => string;charAt: (pos: number) => string;charCodeAt: (index: number) => number;concat: (...strings: string[]) => string;indexOf: (searchString: string, position?: number) => number;... 47 more ...;[BrandTypeId]: {...;};}*/type Result = Types.DeepMutable<T>After
import type { Brand, Types } from "effect"type T = string & Brand.Brand<"mybrand">// type Result = string & Brand.Brand<"mybrand">type Result = Types.DeepMutable<T> -
#4546
a0acec8Thanks @gcanti! - Schema.extend: add support for Transformation + Struct, closes #4536.Example
Before
import { Schema } from "effect"const A = Schema.Struct({a: Schema.String})const B = Schema.Struct({b: Schema.String})const C = Schema.Struct({c: Schema.String})const AB = Schema.transform(A, B, {strict: true,decode: (a) => ({ b: a.a }),encode: (b) => ({ a: b.b })})// Transformation + Structconst schema = Schema.extend(AB, C)/*throws:Error: Unsupported schema or overlapping typesdetails: cannot extend ({ readonly a: string } <-> { readonly b: string }) with { readonly c: string }*/After
import { Schema } from "effect"const A = Schema.Struct({a: Schema.String})const B = Schema.Struct({b: Schema.String})const C = Schema.Struct({c: Schema.String})const AB = Schema.transform(A, B, {strict: true,decode: (a) => ({ b: a.a }),encode: (b) => ({ a: b.b })})// Transformation + Structconst schema = Schema.extend(AB, C)console.log(Schema.decodeUnknownSync(schema)({ a: "a", c: "c" }))// Output: { b: 'a', c: 'c' }console.log(Schema.encodeSync(schema)({ b: "b", c: "c" }))// Output: { a: 'b', c: 'c' }
3.13.4
Patch Changes
3.13.3
Patch Changes
-
#4502
cc5588dThanks @gcanti! - Schema: More Accurate Return Types forDataFromSelfandData.This update refines the return types of
DataFromSelfandData, making them clearer and more specific, especially when working with structured schemas.Before
The return types were more generic, making it harder to see the underlying structure:
import { Schema } from "effect"const struct = Schema.Struct({ a: Schema.NumberFromString })// ┌─── Schema.DataFromSelf<Schema<{ readonly a: number; }, { readonly a: string; }>>// ▼const schema1 = Schema.DataFromSelf(struct)// ┌─── Schema.Data<Schema<{ readonly a: number; }, { readonly a: string; }>>// ▼const schema2 = Schema.Data(struct)After
Now, the return types clearly reflect the original schema structure:
import { Schema } from "effect"const struct = Schema.Struct({ a: Schema.NumberFromString })// ┌─── Schema.DataFromSelf<Schema.Struct<{ a: typeof Schema.NumberFromString; }>>// ▼const schema1 = Schema.DataFromSelf(struct)// ┌─── Schema.Data<Schema.Struct<{ a: typeof Schema.NumberFromString; }>>// ▼const schema2 = Schema.Data(struct) -
#4510
623c8cdThanks @gcanti! - Schema: More Accurate Return Type forcompose.Before
import { Schema } from "effect"// ┌─── SchemaClass<number | null, string>// ▼const schema = Schema.compose(Schema.NumberFromString,Schema.NullOr(Schema.Number))// @ts-expect-error: Property 'from' does not existschema.from// @ts-expect-error: Property 'to' does not existschema.toAfter
import { Schema } from "effect"// ┌─── transform<typeof Schema.NumberFromString, Schema.NullOr<typeof Schema.Number>>// ▼const schema = Schema.compose(Schema.NumberFromString,Schema.NullOr(Schema.Number))// ┌─── typeof Schema.NumberFromString// ▼schema.from// ┌─── Schema.NullOr<typeof Schema.Number>// ▼schema.to -
#4488
00b4eb1Thanks @gcanti! - Schema: more precise return types when filters are involved.Example (with
Schema.maxLength)Before
import { Schema } from "effect"// ┌─── Schema.filter<Schema.Schema<string, string, never>>// ▼const schema = Schema.String.pipe(Schema.maxLength(10))// Schema<string, string, never>schema.fromAfter
import { Schema } from "effect"// ┌─── Schema.filter<typeof Schema.String>// ▼const schema = Schema.String.pipe(Schema.maxLength(10))// typeof Schema.Stringschema.fromString filters:
maxLengthminLengthlengthpatternstartsWithendsWithincludeslowercasedcapitalizeduncapitalizeduppercasednonEmptyStringtrimmed
Number filters:
finitegreaterThangreaterThanOrEqualTolessThanlessThanOrEqualTointmultipleOfbetweennonNaNpositivenegativenonPositivenonNegative
BigInt filters:
greaterThanBigIntgreaterThanOrEqualToBigIntlessThanBigIntlessThanOrEqualToBigIntbetweenBigIntpositiveBigIntnegativeBigIntnonNegativeBigIntnonPositiveBigInt
Duration filters:
lessThanDurationlessThanOrEqualToDurationgreaterThanDurationgreaterThanOrEqualToDurationbetweenDuration
Array filters:
minItemsmaxItemsitemsCount
Date filters:
validDatelessThanDatelessThanOrEqualToDategreaterThanDategreaterThanOrEqualToDatebetweenDate
BigDecimal filters:
greaterThanBigDecimalgreaterThanOrEqualToBigDecimallessThanBigDecimallessThanOrEqualToBigDecimalpositiveBigDecimalnonNegativeBigDecimalnegativeBigDecimalnonPositiveBigDecimalbetweenBigDecimal
-
#4508
f2aee98Thanks @gcanti! - Schema: More Accurate Return Types forArrayEnsureandNonEmptyArrayEnsure.Before
import { Schema } from "effect"const schema1 = Schema.ArrayEnsure(Schema.String)// @ts-expect-error: Property 'from' does not existschema1.fromconst schema2 = Schema.NonEmptyArrayEnsure(Schema.String)// @ts-expect-error: Property 'from' does not existschema2.fromAfter
import { Schema } from "effect"const schema1 = Schema.ArrayEnsure(Schema.String)// ┌─── Schema.Union<[typeof Schema.String, Schema.Array$<typeof Schema.String>]>// ▼schema1.fromconst schema2 = Schema.NonEmptyArrayEnsure(Schema.String)// ┌─── Schema.Union<[typeof Schema.String, Schema.NonEmptyArray<typeof Schema.String>]>// ▼schema2.from -
#4509
fb798ebThanks @gcanti! - Schema: More Accurate Return Types for:transformLiteralclampclampBigIntclampDurationclampBigDecimalheadheadNonEmptyheadOrElse
-
#4524
2251b15Thanks @gcanti! - Schema: More Accurate Return Type forparseNumber.Before
import { Schema } from "effect"const schema = Schema.parseNumber(Schema.String)// ┌─── Schema<string>// ▼schema.fromAfter
import { Schema } from "effect"const schema = Schema.parseNumber(Schema.String)// ┌─── typeof Schema.String// ▼schema.from -
#4514
a4979dbThanks @gcanti! - Schema: add missingfromproperty tobrandinterface.Before
import { Schema } from "effect"const schema = Schema.String.pipe(Schema.brand("my-brand"))// @ts-expect-error: Property 'from' does not existschema.fromAfter
import { Schema } from "effect"const schema = Schema.String.pipe(Schema.brand("my-brand"))// ┌─── typeof Schema.String// ▼schema.from -
#4496
b74255aThanks @tim-smart! - ensure fibers can’t be added to Fiber{Handle,Set,Map} during closing -
#4419
d7f6a5cThanks @KhraksMamtsov! - Fix Context.Tag unification -
#4495
9dd8979Thanks @KhraksMamtsov! - SimplifysortWith,sort,reverse,sortBy,unzip,dedupesignatures in Array module -
#4507
477b488Thanks @gcanti! - Schema: More Accurate Return Type forparseJson(schema).Before
import { Schema } from "effect"// ┌─── Schema.SchemaClass<{ readonly a: number; }, string>// ▼const schema = Schema.parseJson(Schema.Struct({a: Schema.NumberFromString}))// @ts-expect-error: Property 'to' does not existschema.toAfter
import { Schema } from "effect"// ┌─── Schema.transform<Schema.SchemaClass<unknown, string, never>, Schema.Struct<{ a: typeof Schema.NumberFromString; }>>// ▼const schema = Schema.parseJson(Schema.Struct({a: Schema.NumberFromString}))// ┌─── Schema.Struct<{ a: typeof Schema.NumberFromString; }>// ▼schema.to -
#4519
10932cbThanks @gcanti! - RefactorJSONSchemato useadditionalPropertiesinstead ofpatternPropertiesfor simple records, closes #4518.This update improves how records are represented in JSON Schema by replacing
patternPropertieswithadditionalProperties, resolving issues in OpenAPI schema generation.Why the change?
- Fixes OpenAPI issues – Previously, records were represented using
patternProperties, which caused problems with OpenAPI tools. - Better schema compatibility – Some tools, like
openapi-ts, struggled withpatternProperties, generatingRecord<string, never>instead of the correct type. - Fixes missing example values – When using
patternProperties, OpenAPI failed to generate proper response examples, displaying only{}. - Simplifies schema modification – Users previously had to manually fix schemas with
OpenApi.Transform, which was messy and lacked type safety.
Before
import { JSONSchema, Schema } from "effect"const schema = Schema.Record({ key: Schema.String, value: Schema.Number })console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","required": [],"properties": {},"patternProperties": {"": { // ❌ Empty string pattern"type": "number"}}}*/After
Now,
additionalPropertiesis used instead, which properly represents an open-ended record:import { JSONSchema, Schema } from "effect"const schema = Schema.Record({ key: Schema.String, value: Schema.Number })console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","required": [],"properties": {},"additionalProperties": { // ✅ Represents unrestricted record keys"type": "number"}}*/ - Fixes OpenAPI issues – Previously, records were represented using
-
#4501
9f6c784Thanks @gcanti! - Schema: Add MissingdeclareAPI Interface to Expose Type Parameters.Example
import { Schema } from "effect"const schema = Schema.OptionFromSelf(Schema.String)// ┌─── readonly [typeof Schema.String]// ▼schema.typeParameters -
#4487
2c639ecThanks @gcanti! - Schema: more precise return types when transformations are involved.ChunkNonEmptyChunkRedactedOptionOptionFromNullOrOptionFromUndefinedOrOptionFromNullishOrEitherEitherFromUnionReadonlyMapMapHashMapReadonlySetSetHashSetListCauseExitSortedSetheadheadNonEmptyheadOrElse
Example (with
Schema.Chunk)Before
import { Schema } from "effect"const schema = Schema.Chunk(Schema.Number)// Property 'from' does not exist on type 'Chunk<typeof Number$>'schema.fromAfter
import { Schema } from "effect"const schema = Schema.Chunk(Schema.Number)// Schema.Array$<typeof Schema.Number>schema.from -
#4492
886aaa8Thanks @gcanti! - Schema: ImproveLiteralreturn type — now returnsSchemaClassinstead ofSchema
3.13.2
Patch Changes
-
#4472
31be72aThanks @gcanti! - FixSchema.EnumstoString()method to display correct enum values.Now,
toString()correctly displays the actual enum values instead of internal numeric indices.Before
import { Schema } from "effect"enum Fruits {Apple = "apple",Banana = "banana",Cantaloupe = 0}const schema = Schema.Enums(Fruits)console.log(String(schema))// Output: <enum 3 value(s): 0 | 1 | 2> ❌ (incorrect)After
import { Schema } from "effect"enum Fruits {Apple = "apple",Banana = "banana",Cantaloupe = 0}const schema = Schema.Enums(Fruits)console.log(String(schema))// Output: <enum 3 value(s): "apple" | "banana" | 0> ✅ (correct)
3.13.1
Patch Changes
3.13.0
Minor Changes
-
#4280
8baef83Thanks @tim-smart! - add Promise based apis to Fiber{Handle,Set,Map} modules -
#4280
655bfe2Thanks @gcanti! - AddEffect.transposeOption, closes #3142.Converts an
Optionof anEffectinto anEffectof anOption.Details
This function transforms an
Option<Effect<A, E, R>>into anEffect<Option<A>, E, R>. If theOptionisNone, the resultingEffectwill immediately succeed with aNonevalue. If theOptionisSome, the innerEffectwill be executed, and its result wrapped in aSome.Example
import { Effect, Option } from "effect"// ┌─── Option<Effect<number, never, never>>// ▼const maybe = Option.some(Effect.succeed(42))// ┌─── Effect<Option<number>, never, never>// ▼const result = Effect.transposeOption(maybe)console.log(Effect.runSync(result))// Output: { _id: 'Option', _tag: 'Some', value: 42 } -
#4280
d90cbc2Thanks @indietyp! - AddEffect.whenLogLevel, which conditionally executes an effect if the specified log level is enabled -
#4280
75632bdThanks @tim-smart! - add RcMap.touch, for reseting the idle timeout for an item -
#4280
bf865e5Thanks @tim-smart! - allow accessing args in Effect.fn pipe -
#4280
f98b2b7Thanks @tim-smart! - add RcMap.invalidate api, for removing a resource from an RcMap -
#4280
de8ce92Thanks @mikearnaldi! - Add Layer.updateService mirroring Effect.updateService -
#4280
db426a5Thanks @KhraksMamtsov! -DifferimplementsPipeable -
#4280
6862444Thanks @thewilkybarkid! - Make it easy to convert a DateTime.Zoned to a DateTime.Utc -
#4280
5fc8a90Thanks @gcanti! - Add missingEither.voidconstructor. -
#4280
546a492Thanks @vinassefranche! - AddHashMap.toValuesandHashSet.toValuesgetters -
#4280
65c4796Thanks @tim-smart! - add {FiberHandle,FiberSet,FiberMap}.awaitEmpty apis -
#4280
9760fdcThanks @gcanti! - Schema: AddstandardSchemaV1API to Generate a Standard Schema v1.Example
import { Schema } from "effect"const schema = Schema.Struct({name: Schema.String})// ┌─── StandardSchemaV1<{ readonly name: string; }>// ▼const standardSchema = Schema.standardSchemaV1(schema) -
#4280
5b471e7Thanks @fubhy! - AddedDuration.formatIsoandDuration.fromIsofor formatting and parsing ISO8601 durations. -
#4280
4f810ccThanks @tim-smart! - add Effect.filterEffect* apisEffect.filterEffectOrElse
Filters an effect with an effectful predicate, falling back to an alternative effect if the predicate fails.
import { Effect, pipe } from "effect"// Define a user interfaceinterface User {readonly name: string}// Simulate an asynchronous authentication functiondeclare const auth: () => Promise<User | null>const program = pipe(Effect.promise(() => auth()),// Use filterEffectOrElse with an effectful predicateEffect.filterEffectOrElse({predicate: (user) => Effect.succeed(user !== null),orElse: (user) => Effect.fail(new Error(`Unauthorized user: ${user}`))}))Effect.filterEffectOrFail
Filters an effect with an effectful predicate, failing with a custom error if the predicate fails.
import { Effect, pipe } from "effect"// Define a user interfaceinterface User {readonly name: string}// Simulate an asynchronous authentication functiondeclare const auth: () => Promise<User | null>const program = pipe(Effect.promise(() => auth()),// Use filterEffectOrFail with an effectful predicateEffect.filterEffectOrFail({predicate: (user) => Effect.succeed(user !== null),orFailWith: (user) => Effect.fail(new Error(`Unauthorized user: ${user}`))}))
Patch Changes
- #4280
cf8b2ddThanks @KhraksMamtsov! -Trie<out A>type annotations have been aligned. The type parameter was made covariant because the structure is immutable.
3.12.12
Patch Changes
-
#4440
4018eaeThanks @gcanti! - Schema: add missing support for tuple annotations inTaggedRequest. -
#4439
543d36dThanks @gcanti! - Schedule: fix unsafetapOutputsignature.Previously,
tapOutputallowed using an output type that wasn’t properly inferred, leading to potential runtime errors. Now, TypeScript correctly detects mismatches at compile time, preventing unexpected crashes.Before (Unsafe, Causes Runtime Error)
import { Effect, Schedule, Console } from "effect"const schedule = Schedule.once.pipe(Schedule.as<number | string>(1),Schedule.tapOutput((s: string) => Console.log(s.trim())) // ❌ Runtime error)Effect.runPromise(Effect.void.pipe(Effect.schedule(schedule)))// throws: TypeError: s.trim is not a functionAfter (Safe, Catches Type Error at Compile Time)
import { Console, Schedule } from "effect"const schedule = Schedule.once.pipe(Schedule.as<number | string>(1),// ✅ Type Error: Type 'number' is not assignable to type 'string'Schedule.tapOutput((s: string) => Console.log(s.trim()))) -
#4447
f70a65aThanks @gcanti! - Preserve functionlengthproperty inEffect.fn/Effect.fnUntraced, closes #4435Previously, functions created with
Effect.fnandEffect.fnUntracedalways had a.lengthof0, regardless of their actual number of parameters. This has been fixed so that thelengthproperty correctly reflects the expected number of arguments.Before
import { Effect } from "effect"const fn1 = Effect.fn("fn1")(function* (n: number) {return n})console.log(fn1.length)// Output: 0 ❌ (incorrect)const fn2 = Effect.fnUntraced(function* (n: number) {return n})console.log(fn2.length)// Output: 0 ❌ (incorrect)After
import { Effect } from "effect"const fn1 = Effect.fn("fn1")(function* (n: number) {return n})console.log(fn1.length)// Output: 1 ✅ (correct)const fn2 = Effect.fnUntraced(function* (n: number) {return n})console.log(fn2.length)// Output: 1 ✅ (correct) -
#4422
ba409f6Thanks @mikearnaldi! - Fix Context.Tag inference using explicit generics -
#4432
3d2e356Thanks @tim-smart! - use Map for Scope finalizers, to ensure they are always added
3.12.11
Patch Changes
-
#4430
b6a032fThanks @tim-smart! - ensure Channel executor catches defects in doneHalt -
#4426
42ddd5fThanks @gcanti! - Schema: add missingdescriptionannotation toBooleanFromString. -
#4404
2fe447cThanks @gcanti! - UpdateforEachfunction inChunkto include missing index parameter.
3.12.10
Patch Changes
-
#4403
33fa667Thanks @gcanti! - Duration: fixformatoutput when the input is zero.Before
import { Duration } from "effect"console.log(Duration.format(Duration.zero))// Output: ""After
import { Duration } from "effect"console.log(Duration.format(Duration.zero))// Output: "0" -
#4411
87f5f28Thanks @gcanti! - EnhanceTagClassandReferenceClassto enforcekeytype narrowing, closes #4409.The
keyproperty inTagClassandReferenceClassnow correctly retains its specific string value, just like inEffect.Serviceimport { Context, Effect } from "effect"// -------------------------------------------------------------------------------------// `key` field// -------------------------------------------------------------------------------------class A extends Effect.Service<A>()("A", { succeed: { a: "value" } }) {}// $ExpectType "A"A.keyclass B extends Context.Tag("B")<B, { a: "value" }>() {}// $ExpectType "B"B.keyclass C extends Context.Reference<C>()("C", { defaultValue: () => 0 }) {}// $ExpectType "C"C.key -
#4397
4dbd170Thanks @thewilkybarkid! - Make Array.makeBy dual
3.12.9
Patch Changes
3.12.8
Patch Changes
-
#4341
766113cThanks @fubhy! - ImproveDuration.decodeHandling of High-Resolution Time- Ensured Immutability: Added the
readonlymodifier to[seconds: number, nanos: number]inDurationInputto prevent accidental modifications. - Better Edge Case Handling: Now correctly processes special values like
-InfinityandNaNwhen they appear in the tuple representation of duration.
- Ensured Immutability: Added the
-
#4333
712277fThanks @gcanti! - Cron:unsafeParsenow throws a more informative error instead of a generic one -
#4387
f269122Thanks @KhraksMamtsov! - A more precise signature has been applied forEffect.schedule -
#4351
430c846Thanks @tim-smart! - fix Layer.scope types to correctly use the Scope tag identifier -
#4313
a9c94c8Thanks @gcanti! - Schema: UpdateDurationEncoding to a Tagged Union Format.This changeset fixes the
Durationschema to support all possible duration types, including finite, infinite, and nanosecond durations. The encoding format has been updated from a tuple (readonly [seconds: number, nanos: number]) to a tagged union.This update introduces a change to the encoding format. The previous tuple representation is replaced with a more expressive tagged union, which accommodates all duration types:
type DurationEncoded =| {readonly _tag: "Millis"readonly millis: number}| {readonly _tag: "Nanos"readonly nanos: string}| {readonly _tag: "Infinity"}Rationale
The
Durationschema is primarily used to encode durations for transmission. The new tagged union format ensures clear and precise encoding for:- Finite durations, such as milliseconds.
- Infinite durations, such as
Duration.infinity. - Nanosecond durations.
Example
import { Duration, Schema } from "effect"// Encoding a finite duration in millisecondsconsole.log(Schema.encodeSync(Schema.Duration)(Duration.millis(1000)))// Output: { _tag: 'Millis', millis: 1000 }// Encoding an infinite durationconsole.log(Schema.encodeSync(Schema.Duration)(Duration.infinity))// Output: { _tag: 'Infinity' }// Encoding a duration in nanosecondsconsole.log(Schema.encodeSync(Schema.Duration)(Duration.nanos(1000n)))// Output: { _tag: 'Nanos', nanos: '1000' } -
#4331
107e6f0Thanks @gcanti! - Schema: Improve encoding inDefectand add test for array-based defects. -
#4329
65c11b9Thanks @gcanti! - Schema: UpdateitemsCountto allow0as a valid argument, closes #4328. -
#4330
e386d2fThanks @gcanti! - Add missing overload forOption.as. -
#4352
9172efbThanks @tim-smart! - optimize Stream.toReadableStream
3.12.7
Patch Changes
3.12.6
Patch Changes
-
#4307
289c13bThanks @gcanti! - Schema: Enhance error messages for discriminated unions.Before
import { Schema } from "effect"const schema = Schema.Union(Schema.Tuple(Schema.Literal(-1), Schema.Literal(0)).annotations({identifier: "A"}),Schema.Tuple(Schema.NonNegativeInt, Schema.NonNegativeInt).annotations({identifier: "B"})).annotations({ identifier: "AB" })Schema.decodeUnknownSync(schema)([-500, 0])/*throws:ParseError: AB├─ { readonly 0: -1 }│ └─ ["0"]│ └─ Expected -1, actual -500└─ B└─ [0]└─ NonNegativeInt└─ From side refinement failure└─ NonNegative└─ Predicate refinement failure└─ Expected a non-negative number, actual -500*/After
import { Schema } from "effect"const schema = Schema.Union(Schema.Tuple(Schema.Literal(-1), Schema.Literal(0)).annotations({identifier: "A"}),Schema.Tuple(Schema.NonNegativeInt, Schema.NonNegativeInt).annotations({identifier: "B"})).annotations({ identifier: "AB" })Schema.decodeUnknownSync(schema)([-500, 0])/*throws:ParseError: AB├─ { readonly 0: -1 }├─ A│ └─ ["0"]│ └─ Expected -1, actual -500└─ B└─ [0]└─ NonNegativeInt└─ From side refinement failure└─ NonNegative└─ Predicate refinement failure└─ Expected a non-negative number, actual -500*/ -
#4298
8b4e75dThanks @KhraksMamtsov! - Added type-level validation for theEffect.Servicefunction to ensure theSelfgeneric parameter is provided. If the generic is missing, theMissingSelfGenerictype will be returned, indicating that the generic parameter must be specified. This improves type safety and prevents misuse of theEffect.Servicefunction.type MissingSelfGeneric =`Missing \`Self\` generic - use \`class Self extends Service<Self>()...\`` -
#4292
fc5e0f0Thanks @gcanti! - ImproveUnknownExceptionerror messagesUnknownExceptionerror messages now include the name of the Effect api that created the error.import { Effect } from "effect"Effect.tryPromise(() =>Promise.reject(new Error("The operation failed"))).pipe(Effect.catchAllCause(Effect.logError), Effect.runFork)// timestamp=2025-01-21T00:41:03.403Z level=ERROR fiber=#0 cause="UnknownException: An unknown error occurred in Effect.tryPromise// at fail (.../effect/packages/effect/src/internal/core-effect.ts:1654:19)// at <anonymous> (.../effect/packages/effect/src/internal/core-effect.ts:1674:26) {// [cause]: Error: The operation failed// at <anonymous> (.../effect/scratchpad/error.ts:4:24)// at .../effect/packages/effect/src/internal/core-effect.ts:1671:7// }" -
#4309
004fd2bThanks @gcanti! - Schema: Enforce Finite Durations inDurationFromNanos.This update ensures that
DurationFromNanosonly accepts finite durations. Previously, the schema did not explicitly enforce this constraint.A filter has been added to validate that the duration is finite.
DurationFromSelf.pipe(filter((duration) => duration_.isFinite(duration), {description: "a finite duration"})) -
#4314
b2a31beThanks @gcanti! - Duration: makeDurationValueproperties readonly. -
#4287
5514d05Thanks @gcanti! - Array: FixEitherimport and correctpartitionexample. -
#4301
bf5f0aeThanks @gcanti! - Schema: FixBigIntFromNumberto enforce upper and lower bounds.This update ensures the
BigIntFromNumberschema adheres to safe integer limits by applying the following bounds:BigIntFromSelf.pipe(betweenBigInt(BigInt(Number.MIN_SAFE_INTEGER),BigInt(Number.MAX_SAFE_INTEGER))) -
#4228
3b19bcfThanks @fubhy! - Fixed conflictingParseErrortags betweenCronandSchema -
#4294
b064b3bThanks @tim-smart! - ensure cause is rendered in FiberFailure -
#4307
289c13bThanks @gcanti! - Schema: Add Support for Infinity inDuration.This update adds support for encoding
Duration.infinityinSchema.Duration.Before
Attempting to encode
Duration.infinityresulted in aParseErrordue to the lack of support forInfinityinSchema.Duration:import { Duration, Schema } from "effect"console.log(Schema.encodeUnknownSync(Schema.Duration)(Duration.infinity))/*throws:ParseError: Duration└─ Encoded side transformation failure└─ HRTime└─ [0]└─ NonNegativeInt└─ Predicate refinement failure└─ Expected an integer, actual Infinity*/After
The updated behavior successfully encodes
Duration.infinityas[ -1, 0 ]:import { Duration, Schema } from "effect"console.log(Schema.encodeUnknownSync(Schema.Duration)(Duration.infinity))// Output: [ -1, 0 ] -
#4300
f474678Thanks @gcanti! - Schema: updateplucktype signature to respect optional fields.Before
import { Schema } from "effect"const schema1 = Schema.Struct({ a: Schema.optional(Schema.String) })/*const schema2: Schema.Schema<string | undefined, {readonly a: string | undefined;}, never>*/const schema2 = Schema.pluck(schema1, "a")After
import { Schema } from "effect"const schema1 = Schema.Struct({ a: Schema.optional(Schema.String) })/*const schema2: Schema.Schema<string | undefined, {readonly a?: string | undefined;}, never>*/const schema2 = Schema.pluck(schema1, "a") -
#4296
ee187d0Thanks @gcanti! - fix: updateCause.isCausetype from ‘never’ to ‘unknown’
3.12.5
Patch Changes
-
#4273
a8b0ddbThanks @gcanti! - Arbitrary: Fix bug adjusting array constraints for schemas with fixed and rest elementsThis fix ensures that when a schema includes both fixed elements and a rest element, the constraints for the array are correctly adjusted. The adjustment now subtracts the number of values generated by the fixed elements from the overall constraints.
-
#4259
507d546Thanks @gcanti! - Schema: improve error messages for invalid transformationsBefore
import { Schema } from "effect"Schema.decodeUnknownSync(Schema.NumberFromString)("a")/*throws:ParseError: NumberFromString└─ Transformation process failure└─ Expected NumberFromString, actual "a"*/After
import { Schema } from "effect"Schema.decodeUnknownSync(Schema.NumberFromString)("a")/*throws:ParseError: NumberFromString└─ Transformation process failure└─ Unable to decode "a" into a number*/ -
#4273
a8b0ddbThanks @gcanti! - Schema: Extend Support for Array filters, closes #4269.Added support for
minItems,maxItems, anditemsCountto all schemas whereAextendsReadonlyArray, includingNonEmptyArray.Example
import { Schema } from "effect"// Previously, this would have caused an errorconst schema = Schema.NonEmptyArray(Schema.String).pipe(Schema.maxItems(2)) -
#4257
8db239bThanks @gcanti! - Schema: CorrectBigIntandBigIntFromNumberidentifier annotations to follow naming conventions -
#4276
84a0911Thanks @tim-smart! - fix formatting of time zone offsets that round to 60 minutes -
#4276
84a0911Thanks @tim-smart! - ensure DateTimeZonedFromSelf arbitrary generates in the range supported by the time zone database -
#4267
3179a9fThanks @tim-smart! - ensure DateTime.Zoned produces valid dates -
#4264
6cb9b76Thanks @gcanti! - Relocate theIssuedefinition fromplatform/HttpApiErrortoSchema(renamed asArrayFormatterIssue). -
#4266
1fcbe55Thanks @gcanti! - Schema: Replace theTimeZoneFromSelfinterface with a class definition and fix the arbitraries forDateTimeUtcFromSelfandDateTimeZonedFromSelf(fc.date({ noInvalidDate: true })). -
#4279
d9a63d9Thanks @tim-smart! - improve performance of Effect.forkIn
3.12.4
Patch Changes
-
#4231
5b50ea4Thanks @KhraksMamtsov! - fixLayer.retryandMetricPolling.retrysignatures -
#4253
c170a68Thanks @sukovanej! - Use non-enumerable properties for mutable fields ofDateTimeobjects. -
#4255
a66c2ebThanks @sukovanej! - Improve DateTime type preservation
3.12.3
Patch Changes
-
#4244
d7dac48Thanks @gcanti! - Improve pattern handling by merging multiple patterns into a union, closes #4243.Previously, the algorithm always prioritized the first pattern when multiple patterns were encountered.
This fix introduces a merging strategy that combines patterns into a union (e.g.,
(?:${pattern1})|(?:${pattern2})). By doing so, all patterns have an equal chance to generate values when usingFastCheck.stringMatching.Example
import { Arbitrary, FastCheck, Schema } from "effect"// /^[^A-Z]*$/ (given by Lowercase) + /^0x[0-9a-f]{40}$/const schema = Schema.Lowercase.pipe(Schema.pattern(/^0x[0-9a-f]{40}$/))const arb = Arbitrary.make(schema)// Before this fix, the first pattern would always dominate,// making it impossible to generate valuesconst sample = FastCheck.sample(arb, { numRuns: 100 })console.log(sample) -
#4252
1d7fd2bThanks @gcanti! - Fix: CorrectArbitrary.maketo support nestedTemplateLiterals.Previously,
Arbitrary.makedid not properly handle nestedTemplateLiteralschemas, resulting in incorrect or empty outputs. This fix ensures that nested template literals are processed correctly, producing valid arbitrary values.Before
import { Arbitrary, FastCheck, Schema as S } from "effect"const schema = S.TemplateLiteral("<",S.TemplateLiteral("h", S.Literal(1, 2)),">")const arb = Arbitrary.make(schema)console.log(FastCheck.sample(arb, { numRuns: 10 }))/*Output:['<>', '<>', '<>','<>', '<>', '<>','<>', '<>', '<>','<>']*/After
import { Arbitrary, FastCheck, Schema as S } from "effect"const schema = S.TemplateLiteral("<",S.TemplateLiteral("h", S.Literal(1, 2)),">")const arb = Arbitrary.make(schema)console.log(FastCheck.sample(arb, { numRuns: 10 }))/*Output:['<h2>', '<h2>','<h2>', '<h2>','<h2>', '<h1>','<h2>', '<h1>','<h1>', '<h1>']*/ -
#4252
1d7fd2bThanks @gcanti! - Fix: AllowSchema.TemplateLiteralto handle strings with linebreaks, closes #4251.Before
import { Schema } from "effect"const schema = Schema.TemplateLiteral("a: ", Schema.String)console.log(Schema.decodeSync(schema)("a: b \n c"))// throws: ParseError: Expected `a: ${string}`, actual "a: b \n c"After
import { Schema } from "effect"const schema = Schema.TemplateLiteral("a: ", Schema.String)console.log(Schema.decodeSync(schema)("a: b \n c"))/*Output:a: bc*/
3.12.2
Patch Changes
-
#4220
734af82Thanks @KhraksMamtsov! - fix inference for contravariant type-parameters -
#4212
b63c780Thanks @KhraksMamtsov! - RefineEffect.validateAllreturn type to useNonEmptyArrayfor errors.This refinement is possible because
Effect.validateAllguarantees that when the input iterable is non-empty, any validation failure will produce at least one error. In such cases, the errors are inherently non-empty, making it safe and accurate to represent them using aNonEmptyArraytype. This change aligns the return type with the function’s actual behavior, improving type safety and making the API more predictable for developers. -
#4219
c640d77Thanks @whoisandy! - fix: ManagedRuntime.Context to work when Context is of type never -
#4236
0def088Thanks @tim-smart! - fix color option for Logger.prettyLogger
3.12.1
Patch Changes
-
#4194
302b57dThanks @KhraksMamtsov! - take concurrentFinalizers option in account inEffect.allcombinator -
#4202
0988083Thanks @mikearnaldi! - Remove internal EffectError make sure errors are raised with Effect.fail in Effect.try -
#4185
8b46be6Thanks @jessekelly881! - fixed incorrect type declaration in LibsqlClient.layer -
#4189
bfe8027Thanks @tim-smart! - ensure Effect.timeoutTo sleep is interrupted -
#4190
16dd657Thanks @IMax153! - extendIterableIteratorinstead ofGeneratorinSingleShotGen -
#4196
39db211Thanks @mikearnaldi! - Avoid putting symbols in global to fix incompatibility with Temporal Sandbox.After speaking with James Watkins-Harvey we realized current Effect escapes the Temporal Worker sandbox that doesn’t look for symbols when restoring global context in the isolate they create leading to memory leaks.
3.12.0
Minor Changes
-
#4068
abb22a4Thanks @titouancreach! - Added encodeUriComponent/decodeUriComponent for both Encoding and Schema -
#4068
f369a89Thanks @vinassefranche! - Add Runtime.Runtime.Context type extractor -
#4068
642376cThanks @tim-smart! - add non-traced overload to Effect.fn -
#4068
3d2b7a7Thanks @mikearnaldi! - Update fast-check to latest version -
#4068
73f9c6fThanks @wewelll! - add DateTimeUtcFromDate schema -
#4068
17cb451Thanks @fubhy! - Added support forsecondgranularity toCron. -
#4068
d801820Thanks @fubhy! - AddedCron.unsafeParseand allow passing theCron.parsetime zone parameter asstring. -
#4068
e1eeb2dThanks @mikearnaldi! - add Effect.fnUntraced - an untraced version of Effect.fn -
#4068
c11f3a6Thanks @QuentinJanuel! - Add Context.mergeAll to combine multiple Contexts into one. -
#4068
618f7e0Thanks @tim-smart! - add span annotation to disable propagation to the tracer -
#4068
c0ba834Thanks @titouancreach! - Add Schema.headNonEmpty for Schema.NonEmptyArray
Patch Changes
- #4068
e1eeb2dThanks @mikearnaldi! - Carry both call-site and definition site in Effect.fn, auto-trace to anon
3.11.10
Patch Changes
-
#4176
39457d4Thanks @mikearnaldi! - Fix Stream.scoped example -
#4181
a475cc2Thanks @gcanti! - Schema: FixwithDecodingDefaultimplementation to align with its signature (now removesundefinedfrom the AST).Additionally, a new constraint has been added to the signature to prevent calling
withDecodingDefaultafterwithConstructorDefault, which previously led to the following issue:import { Schema } from "effect"const schema = Schema.Struct({a: Schema.optional(Schema.String).pipe(Schema.withConstructorDefault(() => undefined), // this is invalidated by the following call to `withDecodingDefault`Schema.withDecodingDefault(() => ""))}) -
#4175
199214eThanks @gcanti! - Schema: refactor annotations:-
Export internal
Uint8schema -
Export internal
NonNegativeIntschema -
Remove title annotations that are identical to identifiers
-
Avoid setting a title annotation when applying branding
-
Add more title annotations to refinements
-
Improve
toStringoutput and provide more precise error messages for refinements:Before
import { Schema } from "effect"const schema = Schema.Number.pipe(Schema.int({ identifier: "MyInt" }),Schema.positive())console.log(String(schema))// Output: a positive numberSchema.decodeUnknownSync(schema)(1.1)/*throws:ParseError: a positive number└─ From side refinement failure└─ MyInt└─ Predicate refinement failure└─ Expected MyInt, actual 1.1*/After
toStringnow combines all refinements with" & "instead of showing only the last one.- The last message (
"Expected ...") now uses the extended description to make the error message clearer.
import { Schema } from "effect"const schema = Schema.Number.pipe(Schema.int({ identifier: "MyInt" }),Schema.positive())console.log(String(schema))// Output: MyInt & positive // <= all the refinementsSchema.decodeUnknownSync(schema)(1.1)/*throws:ParseError: MyInt & positive└─ From side refinement failure└─ MyInt└─ Predicate refinement failure└─ Expected an integer, actual 1.1 // <= extended description*/
-
-
#4182
b3c160dThanks @mikearnaldi! - Replace absolute imports with relative ones
3.11.9
Patch Changes
-
#4113
1c08a0bThanks @thewilkybarkid! - Schema: Support template literals inSchema.Config.Example
import { Schema } from "effect"// const config: Config<`a${string}`>const config = Schema.Config("A",Schema.TemplateLiteral(Schema.Literal("a"), Schema.String)) -
#4174
1ce703bThanks @gcanti! - Schema: Add support forTemplateLiteralparameters inTemplateLiteral, closes #4166.This update also adds support for
TemplateLiteralandTemplateLiteralParserparameters inTemplateLiteralParser.Before
import { Schema } from "effect"const schema = Schema.TemplateLiteralParser("<",Schema.TemplateLiteralParser("h", Schema.Literal(1, 2)),">")/*throws:Error: Unsupported template literal spanschema (TemplateLiteral): `h${"1" | "2"}`*/After
import { Schema } from "effect"// Schema<readonly ["<", readonly ["h", 2 | 1], ">"], "<h2>" | "<h1>", never>const schema = Schema.TemplateLiteralParser("<",Schema.TemplateLiteralParser("h", Schema.Literal(1, 2)),">")console.log(Schema.decodeUnknownSync(schema)("<h1>"))// Output: [ '<', [ 'h', 1 ], '>' ] -
#4174
1ce703bThanks @gcanti! - Schema: Fix bug inTemplateLiteralParserwhere unions of numeric literals were not coerced correctly.Before
import { Schema } from "effect"const schema = Schema.TemplateLiteralParser("a", Schema.Literal(1, 2))console.log(Schema.decodeUnknownSync(schema)("a1"))/*throws:ParseError: (`a${"1" | "2"}` <-> readonly ["a", 1 | 2])└─ Type side transformation failure└─ readonly ["a", 1 | 2]└─ [1]└─ 1 | 2├─ Expected 1, actual "1"└─ Expected 2, actual "1"*/After
import { Schema } from "effect"const schema = Schema.TemplateLiteralParser("a", Schema.Literal(1, 2))console.log(Schema.decodeUnknownSync(schema)("a1"))// Output: [ 'a', 1 ]console.log(Schema.decodeUnknownSync(schema)("a2"))// Output: [ 'a', 2 ]console.log(Schema.decodeUnknownSync(schema)("a3"))/*throws:ParseError: (`a${"1" | "2"}` <-> readonly ["a", 1 | 2])└─ Encoded side transformation failure└─ Expected `a${"1" | "2"}`, actual "a3"*/
3.11.8
Patch Changes
3.11.7
Patch Changes
-
#4137
2408616Thanks @gcanti! - Arbitrary: fix bug where refinements in declarations raised an incorrect missing annotation error, closes #4136 -
#4138
cec0b4dThanks @gcanti! - JSONSchema: ignore never members in unions.Before
import { JSONSchema, Schema } from "effect"const schema = Schema.Union(Schema.String, Schema.Never)console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","anyOf": [{"type": "string"},{"$id": "/schemas/never","not": {},"title": "never"}]}*/After
import { JSONSchema, Schema } from "effect"const schema = Schema.Union(Schema.String, Schema.Never)console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "string"}*/ -
#4138
cec0b4dThanks @gcanti! - JSONSchema: handle thenullablekeyword for OpenAPI target, closes #4075.Before
import { OpenApiJsonSchema } from "@effect/platform"import { Schema } from "effect"const schema = Schema.NullOr(Schema.String)console.log(JSON.stringify(OpenApiJsonSchema.make(schema), null, 2))/*{"anyOf": [{"type": "string"},{"enum": [null]}]}*/After
import { OpenApiJsonSchema } from "@effect/platform"import { Schema } from "effect"const schema = Schema.NullOr(Schema.String)console.log(JSON.stringify(OpenApiJsonSchema.make(schema), null, 2))/*{"type": "string","nullable": true}*/ -
#4128
8d978c5Thanks @gcanti! - JSONSchema: addtypefor homogeneous enum schemas, closes #4127Before
import { JSONSchema, Schema } from "effect"const schema = Schema.Literal("a", "b")console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","enum": ["a","b"]}*/After
import { JSONSchema, Schema } from "effect"const schema = Schema.Literal("a", "b")console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "string","enum": ["a","b"]}*/ -
#4138
cec0b4dThanks @gcanti! - JSONSchema: use{ "type": "null" }to represent thenullliteralBefore
import { JSONSchema, Schema } from "effect"const schema = Schema.NullOr(Schema.String)console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","anyOf": [{"type": "string"},{"enum": [null]}]}*/After
import { JSONSchema, Schema } from "effect"const schema = Schema.NullOr(Schema.String)console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","anyOf": [{"type": "string"},{"type": "null"}]}*/ -
#4138
cec0b4dThanks @gcanti! - JSONSchema: handle empty native enums.Before
import { JSONSchema, Schema } from "effect"enum Empty {}const schema = Schema.Enums(Empty)console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","$comment": "/schemas/enums","anyOf": [] // <= invalid schema!}*/After
import { JSONSchema, Schema } from "effect"enum Empty {}const schema = Schema.Enums(Empty)console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","$id": "/schemas/never","not": {}}*/
3.11.6
Patch Changes
-
#4118
662d1ceThanks @gcanti! - Allow the transformation created by the Class API to be annotated on all its components: the type side, the transformation itself, and the encoded side.Example
import { Schema, SchemaAST } from "effect"class A extends Schema.Class<A>("A")({a: Schema.NonEmptyString},[{ identifier: "TypeID" }, // annotations for the type side{ identifier: "TransformationID" }, // annotations for the the transformation itself{ identifier: "EncodedID" } // annotations for the the encoded side]) {}console.log(SchemaAST.getIdentifierAnnotation(A.ast.to)) // Some("TypeID")console.log(SchemaAST.getIdentifierAnnotation(A.ast)) // Some("TransformationID")console.log(SchemaAST.getIdentifierAnnotation(A.ast.from)) // Some("EncodedID")A.make({ a: "" })/*ParseError: TypeID└─ ["a"]└─ NonEmptyString└─ Predicate refinement failure└─ Expected NonEmptyString, actual ""*/Schema.encodeSync(A)({ a: "" })/*ParseError: TransformationID└─ Type side transformation failure└─ TypeID└─ ["a"]└─ NonEmptyString└─ Predicate refinement failure└─ Expected NonEmptyString, actual ""*/ -
#4126
31c62d8Thanks @gcanti! - Rewrite the Arbitrary compiler from scratch, closes #2312
3.11.5
Patch Changes
-
#4019
9f5a6f7Thanks @gcanti! - Add missingjsonSchemaannotations to the following filters:lowercasedcapitalizeduncapitalizeduppercased
Before
import { JSONSchema, Schema } from "effect"const schema = Schema.Struct({a: Schema.Uppercased})console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*throws:Error: Missing annotationdetails: Generating a JSON Schema for this schema requires a "jsonSchema" annotationschema (Refinement): Uppercased*/After
import { JSONSchema, Schema } from "effect"const schema = Schema.Uppercasedconsole.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*Output:{"$ref": "#/$defs/Uppercased","$schema": "http://json-schema.org/draft-07/schema#","$defs": {"Uppercased": {"type": "string","description": "an uppercase string","title": "Uppercased","pattern": "^[^a-z]*$"}}}*/ -
#4111
22905cfThanks @gcanti! - JSONSchema: merge refinement fragments instead of just overwriting them.Before
import { JSONSchema, Schema } from "effect"export const schema = Schema.String.pipe(Schema.startsWith("a"), // <= overwritten!Schema.endsWith("c"))console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "string","description": "a string ending with \"c\"","pattern": "^.*c$" // <= overwritten!}*/After
import { JSONSchema, Schema } from "effect"export const schema = Schema.String.pipe(Schema.startsWith("a"), // <= preserved!Schema.endsWith("c"))console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"type": "string","description": "a string ending with \"c\"","pattern": "^.*c$","allOf": [{"pattern": "^a" // <= preserved!}],"$schema": "http://json-schema.org/draft-07/schema#"}*/ -
#4019
9f5a6f7Thanks @gcanti! - JSONSchema: Correct the output order when generating a JSON Schema from a Union that includes literals and primitive schemas.Before
import { JSONSchema, Schema } from "effect"const schema = Schema.Union(Schema.Literal(1, 2), Schema.String)console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","anyOf": [{"type": "string"},{"enum": [1,2]}]}*/After
import { JSONSchema, Schema } from "effect"const schema = Schema.Union(Schema.Literal(1, 2), Schema.String)console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","anyOf": [{"enum": [1,2]},{"type": "string"}]}*/ -
#4107
1e59e4fThanks @tim-smart! - remove FnEffect type to improve return type of Effect.fn -
#4108
8d914e5Thanks @gcanti! - JSONSchema: representneveras{"not":{}}Before
import { JSONSchema, Schema } from "effect"const schema = Schema.Neverconsole.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*throws:Error: Missing annotationdetails: Generating a JSON Schema for this schema requires a "jsonSchema" annotationschema (NeverKeyword): never*/After
import { JSONSchema, Schema } from "effect"const schema = Schema.Neverconsole.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$id": "/schemas/never","not": {},"title": "never","$schema": "http://json-schema.org/draft-07/schema#"}*/ -
#4115
03bb00fThanks @tim-smart! - avoid using non-namespaced “async” internally -
#4019
9f5a6f7Thanks @gcanti! - JSONSchema: fix special case inparseJsonhandling to target the “to” side of the transformation only at the top level.Before
import { JSONSchema, Schema } from "effect"const schema = Schema.parseJson(Schema.Struct({a: Schema.parseJson(Schema.Struct({b: Schema.String}))}))console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","required": ["a"],"properties": {"a": {"type": "object","required": ["b"],"properties": {"b": {"type": "string"}},"additionalProperties": false}},"additionalProperties": false}*/After
import { JSONSchema, Schema } from "effect"const schema = Schema.parseJson(Schema.Struct({a: Schema.parseJson(Schema.Struct({b: Schema.String}))}))console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"type": "object","required": ["a"],"properties": {"a": {"type": "string","contentMediaType": "application/json"}},"additionalProperties": false,"$schema": "http://json-schema.org/draft-07/schema#"}*/ -
#4101
14e1149Thanks @gcanti! - Schema: align themakeconstructor of structs with the behavior of the Class API constructors when all fields have a default.Before
import { Schema } from "effect"const schema = Schema.Struct({a: Schema.propertySignature(Schema.Number).pipe(Schema.withConstructorDefault(() => 0))})// TypeScript error: Expected 1-2 arguments, but got 0.ts(2554)console.log(schema.make())After
import { Schema } from "effect"const schema = Schema.Struct({a: Schema.propertySignature(Schema.Number).pipe(Schema.withConstructorDefault(() => 0))})console.log(schema.make())// Output: { a: 0 } -
#4019
9f5a6f7Thanks @gcanti! - JSONSchema: Fix issue whereidentifieris ignored when a refinement is applied to a schema, closes #4012Before
import { JSONSchema, Schema } from "effect"const schema = Schema.NonEmptyStringconsole.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "string","description": "a non empty string","title": "NonEmptyString","minLength": 1}*/After
import { JSONSchema, Schema } from "effect"const schema = Schema.NonEmptyStringconsole.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","$ref": "#/$defs/NonEmptyString","$defs": {"NonEmptyString": {"type": "string","description": "a non empty string","title": "NonEmptyString","minLength": 1}}}*/ -
#4019
9f5a6f7Thanks @gcanti! - JSONSchema: Use identifier with Class APIs to create a$refinstead of inlining the schema.Before
import { JSONSchema, Schema } from "effect"class A extends Schema.Class<A>("A")({a: Schema.String}) {}console.log(JSON.stringify(JSONSchema.make(A), null, 2))/*{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","required": ["a"],"properties": {"a": {"type": "string"}},"additionalProperties": false}*/After
import { JSONSchema, Schema } from "effect"class A extends Schema.Class<A>("A")({a: Schema.String}) {}console.log(JSON.stringify(JSONSchema.make(A), null, 2))/*{"$ref": "#/$defs/A","$schema": "http://json-schema.org/draft-07/schema#","$defs": {"A": {"type": "object","required": ["a"],"properties": {"a": {"type": "string"}},"additionalProperties": false}}}*/
3.11.4
Patch Changes
-
#4087
518b258Thanks @tim-smart! - remove use of .unsafeAsync in non-suspended contexts -
#4010
6e323a3Thanks @fubhy! - Add support for daylight savings time transitions -
#4010
6e323a3Thanks @fubhy! - Improved efficiency ofCron.nextlookup
3.11.3
Patch Changes
-
#4080
90906f7Thanks @gcanti! - Fix theSchema.TemplateLiteraloutput type when the arguments include a branded type.Before
import { Schema } from "effect"const schema = Schema.TemplateLiteral("a ",Schema.String.pipe(Schema.brand("MyBrand")))// type Type = `a ${Schema.brand<typeof Schema.String, "MyBrand"> & string}`// | `a ${Schema.brand<typeof Schema.String, "MyBrand"> & number}`// | `a ${Schema.brand<typeof Schema.String, "MyBrand"> & bigint}`// | `a ${Schema.brand<...> & false}`// | `a ${Schema.brand<...> & true}`type Type = typeof schema.TypeAfter
import { Schema } from "effect"const schema = Schema.TemplateLiteral("a ",Schema.String.pipe(Schema.brand("MyBrand")))// type Type = `a ${string & Brand<"MyBrand">}`type Type = typeof schema.Type -
#4076
3862cd3Thanks @gcanti! - Schema: fix bug inSchema.TemplateLiteralParserresulting in a runtime error.Before
import { Schema } from "effect"const schema = Schema.TemplateLiteralParser("a", "b")// throws TypeError: Cannot read properties of undefined (reading 'replace')After
import { Schema } from "effect"const schema = Schema.TemplateLiteralParser("a", "b")console.log(Schema.decodeUnknownSync(schema)("ab"))// Output: [ 'a', 'b' ] -
#4076
3862cd3Thanks @gcanti! - SchemaAST: fixTemplateLiteralmodel.Added
LiteralandUnionas valid types. -
#4083
343b6aaThanks @gcanti! - PreserveMissingMessageAnnotations on property signature declarations when another field is a property signature transformation.Before
import { Console, Effect, ParseResult, Schema } from "effect"const schema = Schema.Struct({a: Schema.propertySignature(Schema.String).annotations({missingMessage: () => "message1"}),b: Schema.propertySignature(Schema.String).annotations({ missingMessage: () => "message2" }).pipe(Schema.fromKey("c")), // <= transformationd: Schema.propertySignature(Schema.String).annotations({missingMessage: () => "message3"})})Effect.runPromiseExit(Schema.decodeUnknown(schema, { errors: "all" })({}).pipe(Effect.tapError((error) =>Console.log(ParseResult.ArrayFormatter.formatErrorSync(error)))))/*Output:[{ _tag: 'Missing', path: [ 'a' ], message: 'is missing' }, // <= wrong{ _tag: 'Missing', path: [ 'c' ], message: 'message2' },{ _tag: 'Missing', path: [ 'd' ], message: 'is missing' } // <= wrong]*/After
import { Console, Effect, ParseResult, Schema } from "effect"const schema = Schema.Struct({a: Schema.propertySignature(Schema.String).annotations({missingMessage: () => "message1"}),b: Schema.propertySignature(Schema.String).annotations({ missingMessage: () => "message2" }).pipe(Schema.fromKey("c")), // <= transformationd: Schema.propertySignature(Schema.String).annotations({missingMessage: () => "message3"})})Effect.runPromiseExit(Schema.decodeUnknown(schema, { errors: "all" })({}).pipe(Effect.tapError((error) =>Console.log(ParseResult.ArrayFormatter.formatErrorSync(error)))))/*Output:[{ _tag: 'Missing', path: [ 'a' ], message: 'message1' },{ _tag: 'Missing', path: [ 'c' ], message: 'message2' },{ _tag: 'Missing', path: [ 'd' ], message: 'message3' }]*/ -
#4081
afba339Thanks @gcanti! - Fix the behavior ofSchema.TemplateLiteralParserwhen the arguments include literals other than string literals.Before
import { Schema } from "effect"const schema = Schema.TemplateLiteralParser(Schema.String, 1)console.log(Schema.decodeUnknownSync(schema)("a1"))/*throwsParseError: (`${string}1` <-> readonly [string, 1])└─ Type side transformation failure└─ readonly [string, 1]└─ [1]└─ Expected 1, actual "1"*/After
import { Schema } from "effect"const schema = Schema.TemplateLiteralParser(Schema.String, 1)console.log(Schema.decodeUnknownSync(schema)("a1"))// Output: [ 'a', 1 ]
3.11.2
Patch Changes
- #4063
01cee56Thanks @tim-smart! - Micro adjustments- rename Fiber to MicroFiber
- add Micro.fiberJoin api
- adjust output when inspecting Micro data types
3.11.1
Patch Changes
-
#4052
dd8a2d8Thanks @tim-smart! - ensure pool.get is interrupted on shutdown -
#4059
a71bfefThanks @IMax153! - Ensure that the current time zone context tag type is properly exported
3.11.0
Minor Changes
-
#3835
147434bThanks @IMax153! - Ensure scopes are preserved by stream / sink / channel operationsNOTE: This change does modify the public signature of several
Stream/Sink/Channelmethods. Namely, certain run methods that previously removed aScopefrom the environment will no longer do so. This was a bug with the previous implementation of how scopes were propagated, and is why this change is being made in a minor release. -
#3835
6e69493Thanks @tim-smart! - add Context.Reference - a Tag with a default value -
#3835
147434bThanks @IMax153! - AddEffect.scopedWithto run an effect that depends on aScope, and then closes theScopeafter the effect has completedimport { Effect, Scope } from "effect"const program: Effect.Effect<void> = Effect.scopedWith((scope) =>Effect.acquireRelease(Effect.log("Acquiring..."), () =>Effect.log("Releasing...")).pipe(Scope.extend(scope)))Effect.runPromise(program)// Output:// timestamp=2024-11-26T16:44:54.158Z level=INFO fiber=#0 message=Acquiring...// timestamp=2024-11-26T16:44:54.165Z level=INFO fiber=#0 message=Releasing... -
#3835
d9fe79bThanks @tim-smart! - remove Env, EnvRef & FiberFlags from Micro -
#3835
251d189Thanks @KhraksMamtsov! -Config.urlconstructor has been added, which parses a string usingnew URL() -
#3835
5a259f3Thanks @tim-smart! - use fiber based runtime for Micro module- Improved performance
- Improved interruption model
- Consistency with the Effect data type
-
#3835
b4ce4eaThanks @SandroMaglione! - New methodsextractAllandextractSchematoUrlParams(addedSchema.BooleanFromString). -
#3835
15fcc5aThanks @fubhy! - IntegratedDateTimewithCronto add timezone support for cron expressions. -
#3835
9bc9a47Thanks @KhraksMamtsov! -URLandURLFromSelfschemas have been added -
#3835
aadb8a4Thanks @fubhy! - AddedBigDecimal.toExponentialfor scientific notation formatting ofBigDecimalvalues.The implementation of
BigDecimal.formatnow uses scientific notation for values with at least 16 decimal places or trailing zeroes. Previously, extremely large or small values could causeOutOfMemoryerrors when formatting. -
#3835
1e2747cThanks @KhraksMamtsov! - - JSONSchema module- add
format?: stringoptional field toJsonSchema7Stringinterface - Schema module
- add custom json schema annotation to
UUIDschema includingformat: "uuid"
- add custom json schema annotation to
- OpenApiJsonSchema module
- add
format?: stringoptional field toStringandNumericinterfaces
- add
- add
-
#3835
e0b9b09Thanks @mikearnaldi! - Implement Effect.fn to define traced functions.import { Effect } from "effect"const logExample = Effect.fn("example")(function* <N extends number>(n: N) {yield* Effect.annotateCurrentSpan("n", n)yield* Effect.logInfo(`got: ${n}`)yield* Effect.fail(new Error())}, Effect.delay("1 second"))Effect.runFork(logExample(100).pipe(Effect.catchAllCause(Effect.logError))) -
#3835
c36f3b9Thanks @KhraksMamtsov! -Config.redactedhas been made more flexible and can now wrap any other config. This allows to transform or validate config values before it’s hidden.import { Config } from "effect"Effect.gen(function* () {// can be any string including emptyconst pass1 = yield* Config.redacted("PASSWORD")// ^? Redacted<string>// can't be empty stringconst pass2 = yield* Config.redacted(Config.nonEmptyString("PASSWORD"))// ^? Redacted<string>const pass2 = yield* Config.redacted(Config.number("SECRET_NUMBER"))// ^? Redacted<number>}) -
#3835
aadb8a4Thanks @fubhy! - AddedBigDecimal.unsafeFromNumberandBigDecimal.safeFromNumber.Deprecated
BigDecimal.fromNumberin favour ofBigDecimal.unsafeFromNumber.The current implementation of
BigDecimal.fromNumberandBigDecimal.unsafeFromNumbernow throws aRangeErrorfor numbers that are not finite such asNaN,+Infinityor-Infinity.
Patch Changes
-
#3835
5eff3f6Thanks @tim-smart! - fix multipart support for bun http server -
#3835
9264162Thanks @IMax153! - inherit child fibers created by merged streams
3.10.20
Patch Changes
-
#4042
3069614Thanks @tim-smart! - catch logger defects from calling .toJSON on data types -
#4041
09a5e52Thanks @tim-smart! - fix docs for Stream.partition
3.10.19
Patch Changes
-
#4007
944025bThanks @gcanti! - Wrap JSDoc @example tags with a TypeScript fence, closes #4002 -
#4013
54addeeThanks @thewilkybarkid! - Remove reference to non-existent function
3.10.18
Patch Changes
3.10.17
Patch Changes
- #3998
42c4ce6Thanks @tim-smart! - ensure fiber observers are cleared after exit to prevent memory leaks
3.10.16
Patch Changes
-
#3918
4dca30cThanks @gcanti! - Use a specific annotation (AutoTitleAnnotationId) to add automatic titles (added byStructandClassAPIs), instead ofTitleAnnotationId, to avoid interfering with user-defined titles. -
#3981
1d99867Thanks @gcanti! - Stable filters such asminItems,maxItems, anditemsCountshould be applied only if the from part fails with aCompositeissue, closes #3980Before
import { Schema } from "effect"const schema = Schema.Struct({a: Schema.Array(Schema.String).pipe(Schema.minItems(1))})Schema.decodeUnknownSync(schema)({}, { errors: "all" })// throws: TypeError: Cannot read properties of undefined (reading 'length')After
import { Schema } from "effect"const schema = Schema.Struct({a: Schema.Array(Schema.String).pipe(Schema.minItems(1))})Schema.decodeUnknownSync(schema)({}, { errors: "all" })/*throws:ParseError: { readonly a: an array of at least 1 items }└─ ["a"]└─ is missing*/ -
#3972
6dae414Thanks @tim-smart! - add support for 0 capacity to Mailbox -
#3959
6b0d737Thanks @gcanti! - RemoveOmitfrom theClassinterface definition to align type signatures with runtime behavior. This fix addresses the issue of being unable to override base class methods in extended classes without encountering type errors, closes #3958Before
import { Schema } from "effect"class Base extends Schema.Class<Base>("Base")({a: Schema.String}) {f() {console.log("base")}}class Extended extends Base.extend<Extended>("Extended")({}) {// Class '{ readonly a: string; } & Omit<Base, "a">' defines instance member property 'f',// but extended class 'Extended' defines it as instance member function.ts(2425)// @ts-expect-erroroverride f() {console.log("extended")}}After
import { Schema } from "effect"class Base extends Schema.Class<Base>("Base")({a: Schema.String}) {f() {console.log("base")}}class Extended extends Base.extend<Extended>("Extended")({}) {// okoverride f() {console.log("extended")}} -
#3971
d8356aaThanks @gcanti! - Refactor JSON Schema Generation to Include Transformation Annotations, closes #3016When generating a JSON Schema, treat
TypeLiteralTransformations(such as whenSchema.optionalWithis used) as a special case. Annotations from the transformation itself will now be applied, unless there are user-defined annotations on the form side. This change ensures that the user’s intended annotations are properly included in the schema.Before
Annotations set on the transformation are ignored. However while using
Schema.optionalWithinternally generates a transformation schema, this is considered a technical detail. The user’s intention is to add annotations to the “struct” schema, not to the transformation.import { JSONSchema, Schema } from "effect"const schema = Schema.Struct({a: Schema.optionalWith(Schema.String, { default: () => "" })}).annotations({identifier: "MyID",description: "My description",title: "My title"})console.log(JSONSchema.make(schema))/*Output:{'$schema': 'http://json-schema.org/draft-07/schema#',type: 'object',required: [],properties: { a: { type: 'string' } },additionalProperties: false}*/After
Annotations set on the transformation are now considered during JSON Schema generation:
import { JSONSchema, Schema } from "effect"const schema = Schema.Struct({a: Schema.optionalWith(Schema.String, { default: () => "" })}).annotations({identifier: "MyID",description: "My description",title: "My title"})console.log(JSONSchema.make(schema))/*Output:{'$schema': 'http://json-schema.org/draft-07/schema#','$ref': '#/$defs/MyID','$defs': {MyID: {type: 'object',required: [],properties: [Object],additionalProperties: false,description: 'My description',title: 'My title'}}}*/
3.10.15
Patch Changes
-
#3936
8398b32Thanks @tim-smart! - allow DateTime.makeZoned to default to the local time zone -
#3917
72e55b7Thanks @SuttonKyle! - Allow Stream.split to use refinement for better type inference
3.10.14
Patch Changes
-
#3920
f983946Thanks @gcanti! - remove redundant check inJSONNumberdeclaration -
#3924
2d8a750Thanks @tim-smart! - ensure a ManagedRuntime can be built synchronously
3.10.13
Patch Changes
3.10.12
Patch Changes
3.10.11
Patch Changes
3.10.10
Patch Changes
-
#3893
cd720aeThanks @tim-smart! - support “dropping” & “sliding” strategies in Mailbox -
#3893
cd720aeThanks @tim-smart! - add Mailbox.fromStream api -
#3886
b631f40Thanks @fubhy! - OptimizedBase64.decodeby not capturing the padding characters in the underlying array buffer.Previously, the implementation first captured the padding characters in the underlying array buffer and then returned a new subarray view of the buffer with the padding characters removed.
By not capturing the padding characters, we avoid the creation of another typed array instance for the subarray view.
3.10.9
Patch Changes
-
#3883
a123e80Thanks @tim-smart! - add FromIterator primitive to improve Effect.gen performance -
#3880
bd5fcd3Thanks @tim-smart! - refactor Effect.gen to improve performance -
#3881
0289d3bThanks @tim-smart! - implement Effect.suspend using OP_COMMIT -
#3862
7386b71Thanks @furrycatherder! - fix the type signature ofusein Effect.Service -
#3879
4211a23Thanks @IMax153! - Return a sequential cause when both theuseandreleasefail inEffect.acquireUseRelease
3.10.8
Patch Changes
-
#3868
68b5c9eThanks @tim-smart! - move _op check out of the fiber hot path -
#3849
9c9928dThanks @patroza! - improve: use literalkeyon Service -
#3872
6306e66Thanks @KhraksMamtsov! - FixConfig.integer&Config.number -
#3869
361c7f3Thanks @KhraksMamtsov! - jsdoc-examples for class-based APIs have been added, e.g.Schema.TaggedError,Effect.Serviceand others
3.10.7
Patch Changes
-
#3867
33f5b9fThanks @tim-smart! - ensure Channel.mergeWith fibers can be interrupted -
#3865
50f0281Thanks @tim-smart! - fix memory leak in Stream.retry
3.10.6
Patch Changes
3.10.5
Patch Changes
-
#3841
3a6d757Thanks @KhraksMamtsov! - Support union of parameters in functions inEffect.Tag.Proxytype -
#3845
59d813aThanks @tim-smart! - ensure fiber refs are not inherited by ManagedRuntime
3.10.4
Patch Changes
-
#3842
2367708Thanks @gcanti! - add support forSchema.OptionFromUndefinedOrin JSON Schema generation, closes #3839Before
import { JSONSchema, Schema } from "effect"const schema = Schema.Struct({a: Schema.OptionFromUndefinedOr(Schema.Number)})console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*throws:Error: Missing annotationat path: ["a"]details: Generating a JSON Schema for this schema requires a "jsonSchema" annotationschema (UndefinedKeyword): undefined*/After
import { JSONSchema, Schema } from "effect"const schema = Schema.Struct({a: Schema.OptionFromUndefinedOr(Schema.Number)})console.log(JSON.stringify(JSONSchema.make(schema), null, 2))/*Output:{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","required": [],"properties": {"a": {"type": "number"}},"additionalProperties": false}*/
3.10.3
Patch Changes
3.10.2
Patch Changes
-
#3820
714e119Thanks @tim-smart! - simplify Match fail keys types -
#3825
c1afd55Thanks @KhraksMamtsov! - - MakeMergeRight,MergeLeftandMergeRecordinTypesmodule homomorphic (preserve originalreadonlyand optionality modifiers)MergeRecordnow is alias forMergeLeft
3.10.1
Patch Changes
3.10.0
Minor Changes
-
#3764
4a01828Thanks @evelant! - add Stream.fromTQueue & Stream.fromTPubSub -
#3764
c79c4c1Thanks @gcanti! - Merge Schema into Effect.Modules
Before
import {Arbitrary,AST,FastCheck,JSONSchema,ParseResult,Pretty,Schema} from "@effect/schema"After
import {Arbitrary,SchemaAST, // changedFastCheck,JSONSchema,ParseResult,Pretty,Schema} from "effect"Formatters
ArrayFormatter/TreeFormattermerged intoParseResultmodule.Before
import { ArrayFormatter, TreeFormatter } from "@effect/schema"After
import { ArrayFormatter, TreeFormatter } from "effect/ParseResult"Serializable
Merged into
Schemamodule.Equivalence
Merged into
Schemamodule.Before
import { Equivalence } from "@effect/schema"Equivalence.make(myschema)After
import { Schema } from "@effect/schema"Schema.equivalence(myschema) -
#3764
38d30f0Thanks @tim-smart! - add option to .releaseLock a ReadableStream on finalization -
#3764
5821ce3Thanks @patroza! - feat: implement Redactable. Used by Headers to not log sensitive information
3.9.2
Patch Changes
3.9.1
Patch Changes
3.9.0
Minor Changes
-
#3620
ff3d1aaThanks @vinassefranche! - Adds HashMap.HashMap.Entry type helper -
#3620
0ba66f2Thanks @tim-smart! - add deno support to Inspectable -
#3620
bf77f51Thanks @KhraksMamtsov! -LatchimplementsEffect<void>with.awaitsemantic -
#3620
0779681Thanks @KhraksMamtsov! - Effect.mapAccum & Array.mapAccum preserve non-emptiness -
#3620
534129fThanks @KhraksMamtsov! -Poolis now a subtype ofEffect, equivalent toPool.get -
#3620
d75140cThanks @mikearnaldi! - Support providing an array of layers via Effect.provide and Layer.provide -
#3620
be0451cThanks @leonitousconforti! - support ManagedRuntime in Effect.provide -
#3620
be0451cThanks @leonitousconforti! -ManagedRuntime<R, E>is subtype ofEffect<Runtime<R>, E, never> -
#3620
5b36494Thanks @KhraksMamtsov! -Tuple.maptransforms each element of tuple using the given function, treating tuple homomorphicallyimport { pipe, Tuple } from "effect"const result = pipe(// ^? [string, string, string]["a", 1, false] as const,T.map((el) => {//^? "a" | 1 | falsereturn el.toString().toUppercase()}))assert.deepStrictEqual(result, ["A", "1", "FALSE"]) -
#3620
4986391Thanks @ianbollinger! - Add anisRegExptype guard -
#3620
d75140cThanks @mikearnaldi! - Implement Effect.Service as a Tag and Layer with Opaque Type.Namely the following is now possible:
class Prefix extends Effect.Service<Prefix>()("Prefix", {sync: () => ({prefix: "PRE"})}) {}class Postfix extends Effect.Service<Postfix>()("Postfix", {sync: () => ({postfix: "POST"})}) {}const messages: Array<string> = []class Logger extends Effect.Service<Logger>()("Logger", {accessors: true,effect: Effect.gen(function* () {const { prefix } = yield* Prefixconst { postfix } = yield* Postfixreturn {info: (message: string) =>Effect.sync(() => {messages.push(`[${prefix}][${message}][${postfix}]`)})}}),dependencies: [Prefix.Default, Postfix.Default]}) {}describe("Effect", () => {it.effect("Service correctly wires dependencies", () =>Effect.gen(function* () {const { _tag } = yield* Loggerexpect(_tag).toEqual("Logger")yield* Logger.info("Ok")expect(messages).toEqual(["[PRE][Ok][POST]"])const { prefix } = yield* Prefixexpect(prefix).toEqual("PRE")const { postfix } = yield* Postfixexpect(postfix).toEqual("POST")}).pipe(Effect.provide([Logger.Default, Prefix.Default, Postfix.Default])))}) -
#3620
d1387aeThanks @KhraksMamtsov! -Resource<A, E>is subtype ofEffect<A, E>.ScopedRed<A>is subtype ofEffect<A>.
Patch Changes
3.8.5
Patch Changes
-
#3734
88e85dbThanks @mikearnaldi! - Ensure random numbers are correctly distributed -
#3717
83887caThanks @mikearnaldi! - Consider async operation in runSync as a defect, add span based stack -
#3731
5266b6cThanks @patroza! - Improve DX of type errors from insidepipeandflow -
#3699
cdead5cThanks @jessekelly881! - added Stream.mergeWithTagCombines a struct of streams into a single stream of tagged values where the tag is the key of the struct.
import { Stream } from "effect"// Stream.Stream<{ _tag: "a"; value: number; } | { _tag: "b"; value: string; }>const stream = Stream.mergeWithTag({a: Stream.make(0),b: Stream.make("")},{ concurrency: 1 })
3.8.4
Patch Changes
3.8.3
Patch Changes
3.8.2
Patch Changes
3.8.1
Patch Changes
-
#3624
10bf621Thanks @fubhy! - Fixed double firing of cron schedules in cases where the current time matched the initial interval. -
#3623
ae36fa6Thanks @fubhy! - Allow CRLF characters in base64 encoded strings.
3.8.0
Minor Changes
-
#3541
fcfa6eeThanks @Schniz! - addLogger.withLeveledConsoleIn browsers and different platforms,
console.errorrenders differently thanconsole.info. This helps to distinguish between different levels of logging.Logger.withLeveledConsoletakes any logger and calls the respectiveConsolemethod based on the log level. For instance,Effect.logErrorwill callConsole.errorandEffect.logInfowill callConsole.info.To use it, you can replace the default logger with a
Logger.withLeveledConsolelogger:import { Logger, Effect } from "effect"const loggerLayer = Logger.withLeveledConsole(Logger.stringLogger)Effect.gen(function* () {yield* Effect.logError("an error")yield* Effect.logInfo("an info")}).pipe(Effect.provide(loggerLayer)) -
#3541
bb9931bThanks @KhraksMamtsov! - MadeRef,SynchronizedRedandSubscriptionRefa subtype ofEffect -
#3541
5798f76Thanks @tim-smart! - add Semaphore.withPermitsIfAvailableYou can now use
Semaphore.withPermitsIfAvailableto run an Effect only if the Semaphore has enough permits available. This is useful when you want to run an Effect only if you can acquire a permit without blocking.It will return an
Option.Somewith the result of the Effect if the permits were available, orNoneif they were not.import { Effect } from "effect"Effect.gen(function* () {const semaphore = yield* Effect.makeSemaphore(1)semaphore.withPermitsIfAvailable(1)(Effect.void)}) -
#3541
5f0bfa1Thanks @KhraksMamtsov! - TheDeferred<A>is now a subtype ofEffect<A>. This change simplifies handling of deferred values, removing the need for explicit callDeffer.await.import { Effect, Deferred } from "effect"Effect.gen(function* () {const deferred = yield* Deferred.make<string>()const before = yield* Deferred.await(deferred)const after = yield* deferred}) -
#3541
812a4e8Thanks @tim-smart! - add Logger.prettyLoggerDefault, to prevent duplicate pretty loggers -
#3541
273565eThanks @tim-smart! - add Effect.makeLatch, for creating a simple async latchimport { Effect } from "effect"Effect.gen(function* () {// Create a latch, starting in the closed stateconst latch = yield* Effect.makeLatch(false)// Fork a fiber that logs "open sesame" when the latch is openedconst fiber = yield* Effect.log("open sesame").pipe(latch.whenOpen,Effect.fork)// Open the latchyield* latch.openyield* fiber.await}) -
#3541
569a801Thanks @KhraksMamtsov! -Dequeue<A>andQueue<A>is subtype ofEffect<A>. This means that now it can be used as anEffect, and when called, it will automatically extract and return an item from the queue, without having to explicitly use theQueue.takefunction.Effect.gen(function* () {const queue = yield* Queue.unbounded<number>()yield* Queue.offer(queue, 1)yield* Queue.offer(queue, 2)const oldWay = yield* Queue.take(queue)const newWay = yield* queue}) -
#3541
02f6b06Thanks @fubhy! - Add additionalDurationconversion apisDuration.toMinutesDuration.toHoursDuration.toDaysDuration.toWeeks
-
#3541
12b893eThanks @KhraksMamtsov! - TheFiber<A, E>is now a subtype ofEffect<A, E>. This change removes the need for explicit callFiber.join.import { Effect, Fiber } from "effect"Effect.gen(function*() {const fiber = yield* Effect.fork(Effect.succeed(1))const oldWay = yield* Fiber.join(fiber)const now = yield* fiber})) -
#3541
bbad27eThanks @dilame! - addStream.shareapiThe
Stream.shareapi is a ref counted variant of the broadcast apis.It allows you to share a stream between multiple consumers, and will close the upstream when the last consumer ends.
-
#3541
adf7d7aThanks @tim-smart! - add Mailbox module, a queue which can have done or failure signalsimport { Chunk, Effect, Mailbox } from "effect"import * as assert from "node:assert"Effect.gen(function* () {const mailbox = yield* Mailbox.make<number, string>()// add messages to the mailboxyield* mailbox.offer(1)yield* mailbox.offer(2)yield* mailbox.offerAll([3, 4, 5])// take messages from the mailboxconst [messages, done] = yield* mailbox.takeAllassert.deepStrictEqual(Chunk.toReadonlyArray(messages), [1, 2, 3, 4, 5])assert.strictEqual(done, false)// signal that the mailbox is doneyield* mailbox.endconst [messages2, done2] = yield* mailbox.takeAllassert.deepStrictEqual(messages2, Chunk.empty())assert.strictEqual(done2, true)// signal that the mailbox is failedyield* mailbox.fail("boom")}) -
#3541
007289aThanks @mikearnaldi! - Cache some fiber references in the runtime to optimize reading in hot-paths -
#3541
42a8f99Thanks @fubhy! - AddedRcMap.keysandMutableHashMap.keys.These functions allow you to get a list of keys currently stored in the underlying hash map.
const map = MutableHashMap.make([["a", "a"],["b", "b"],["c", "c"]])const keys = MutableHashMap.keys(map) // ["a", "b", "c"]Effect.gen(function* () {const map = yield* RcMap.make({lookup: (key) => Effect.succeed(key)})yield* RcMap.get(map, "a")yield* RcMap.get(map, "b")yield* RcMap.get(map, "c")const keys = yield* RcMap.keys(map) // ["a", "b", "c"]}) -
#3541
eebfd29Thanks @fubhy! - AddDuration.partsapiconst parts = Duration.parts(Duration.sum("5 minutes", "20 seconds"))assert.equal(parts.minutes, 5)assert.equal(parts.seconds, 20) -
#3541
040703dThanks @KhraksMamtsov! - TheFiberRef<A>is now a subtype ofEffect<A>. This change simplifies handling of deferred values, removing the need for explicit callFiberRef.get.import { Effect, FiberRef } from "effect"Effect.gen(function* () {const fiberRef = yield* FiberRef.make("value")const before = yield* FiberRef.get(fiberRef)const after = yield* fiberRef})
3.7.3
Patch Changes
3.7.2
Patch Changes
-
#3548
8a601d7Thanks @tim-smart! - remove console.log statements from Micro -
#3546
353ba19Thanks @tim-smart! - fix exported Stream types forbroadcast*andtoPubSub
3.7.1
Patch Changes
-
#3536
79859e7Thanks @mikearnaldi! - Optimize Array.sortWith to avoid calling the map function excesively -
#3516
f6a469cThanks @KhraksMamtsov! - support tacit usage forEffect.tapErrorTagandEffect.catchTag -
#3543
dcb9ec0Thanks @datner! - Align behavior ofStream.emptyto act likeStream.make()to fix behavior withNodeStream.toReadable -
#3545
79aa6b1Thanks @tim-smart! - fix Micro.forEach for empty iterables
3.7.0
Minor Changes
-
#3410
2f456ccThanks @vinassefranche! - preserveArray.modifyArray.modifyOptionnon emptiness -
#3410
8745e41Thanks @patroza! - improve: type Fiber.awaitAll as Exit<A, E>[]. -
#3410
e557838Thanks @titouancreach! - New constructor Config.nonEmptyString -
#3410
d6e7e40Thanks @KhraksMamtsov! - preserveArray.replaceArray.replaceOptionnon emptiness -
#3410
8356321Thanks @KhraksMamtsov! - addEffect.bindAllapiThis api allows you to combine
Effect.allwithEffect.bind. It is useful when you want to concurrently run multiple effects and then combine their results in a Do notation pipeline.import { Effect } from "effect"const result = Effect.Do.pipe(Effect.bind("x", () => Effect.succeed(2)),Effect.bindAll(({ x }) => ({a: Effect.succeed(x + 1),b: Effect.succeed("foo")}),{ concurrency: 2 }))assert.deepStrictEqual(Effect.runSync(result), {x: 2,a: 3,b: "foo"}) -
#3410
192f2ebThanks @tim-smart! - addpropagateInterruptionoption to Fiber{Handle,Set,Map}This option will send any external interrupts to the .join result.
-
#3410
718cb70Thanks @dilame! - feat(Stream): implementraceoperator, which accepts two upstreams and returns a stream that mirrors the first upstream to emit an item and interrupts the other upstream.import { Stream, Schedule, Console, Effect } from "effect"const stream = Stream.fromSchedule(Schedule.spaced("2 millis")).pipe(Stream.race(Stream.fromSchedule(Schedule.spaced("1 millis"))),Stream.take(6),Stream.tap((n) => Console.log(n)))Effect.runPromise(Stream.runDrain(stream))// Output each millisecond from the first stream, the rest streams are interrupted// 0// 1// 2// 3// 4// 5 -
#3410
e9d0310Thanks @mikearnaldi! - Avoid automatic propagation of finalizer concurrency, closes #3440 -
#3410
6bf28f7Thanks @tim-smart! - add Context.getOrElse api, for gettings a Tag’s value with a fallback
Patch Changes
3.6.8
Patch Changes
3.6.7
Patch Changes
3.6.6
Patch Changes
-
#3306
f960bf4Thanks @dilame! - Introduce left / right naming for Stream apis -
#3499
46a575fThanks @tim-smart! - fix nested Config.array, by ensuring path patches aren’t applied twice in sequences
3.6.5
Patch Changes
-
#3474
14a47a8Thanks @IMax153! - Add support for incrementing and decrementing a gauge based on its prior value -
#3490
0c09841Thanks @tim-smart! - fix type error when .pipe() has no arguments
3.6.4
Patch Changes
-
#3404
8295281Thanks @KhraksMamtsov! - FixCache<_, Value, _>type parameter variance (covariant -> invariant) -
#3452
c940df6Thanks @tim-smart! - ensure Scheduler tasks are added to a matching priority bucket -
#3459
00b6c6dThanks @tim-smart! - ensure defects are caught in Effect.tryPromise -
#3458
f8d95a6Thanks @thomasvargiu! - fixDateTime.makeZonedFromStringfor 0 offset
3.6.3
Patch Changes
3.6.2
Patch Changes
3.6.1
Patch Changes
-
#3405
510a34dThanks @KhraksMamtsov! - FixEffect.repeatwith times option returns wrong value -
#3398
45dbb9fThanks @sukovanej! - FixStream.asyncPushtype signature - allow theregistereffect to fail.
3.6.0
Minor Changes
-
#3380
1e0fe80Thanks @tim-smart! - make List.Cons extend NonEmptyIterable -
#3380
8135294Thanks @tim-smart! - add DateTime moduleThe
DateTimemodule provides functionality for working with time, including support for time zones and daylight saving time.It has two main data types:
DateTime.UtcandDateTime.Zoned.A
DateTime.Utcrepresents a time in Coordinated Universal Time (UTC), and aDateTime.Zonedcontains both a UTC timestamp and a time zone.There is also a
CurrentTimeZoneservice, for setting a time zone contextually.import { DateTime, Effect } from "effect"Effect.gen(function* () {// Get the current time in the current time zoneconst now = yield* DateTime.nowInCurrentZone// Math functions are includedconst tomorrow = DateTime.add(now, 1, "day")// Convert to a different time zone// The UTC portion of the `DateTime` is preserved and only the time zone is// changedconst sydneyTime = tomorrow.pipe(DateTime.unsafeSetZoneNamed("Australia/Sydney"))}).pipe(DateTime.withCurrentZoneNamed("America/New_York")) -
#3380
cd255a4Thanks @tim-smart! - add Stream.asyncPush apiThis api creates a stream from an external push-based resource.
You can use the
emithelper to emit values to the stream. You can also use theemithelper to signal the end of the stream by using apis such asemit.endoremit.fail.By default it uses an “unbounded” buffer size. You can customize the buffer size and strategy by passing an object as the second argument with the
bufferSizeandstrategyfields.import { Effect, Stream } from "effect"Stream.asyncPush<string>((emit) =>Effect.acquireRelease(Effect.gen(function* () {yield* Effect.log("subscribing")return setInterval(() => emit.single("tick"), 1000)}),(handle) =>Effect.gen(function* () {yield* Effect.log("unsubscribing")clearInterval(handle)})),{ bufferSize: 16, strategy: "dropping" }) -
#3380
3845646Thanks @mikearnaldi! - Implement Struct.keys as a typed alternative to Object.keysimport { Struct } from "effect"const symbol: unique symbol = Symbol()const value = {a: 1,b: 2,[symbol]: 3}const keys: Array<"a" | "b"> = Struct.keys(value) -
#3380
2d09078Thanks @sukovanej! - AddRandom.choice.import { Random } from "effect"Effect.gen(function* () {const randomItem = yield* Random.choice([1, 2, 3])console.log(randomItem)}) -
#3380
4bce5a0Thanks @vinassefranche! - Add onlyEffect option to Effect.tap -
#3380
4ddbff0Thanks @KhraksMamtsov! - SupportRefinementinPredicate.tupleandPredicate.struct -
#3380
e74cc38Thanks @dilame! - ImplementStream.onEndthat adds an effect to be executed at the end of the stream.import { Console, Effect, Stream } from "effect"const stream = Stream.make(1, 2, 3).pipe(Stream.map((n) => n * 2),Stream.tap((n) => Console.log(`after mapping: ${n}`)),Stream.onEnd(Console.log("Stream ended")))Effect.runPromise(Stream.runCollect(stream)).then(console.log)// after mapping: 2// after mapping: 4// after mapping: 6// Stream ended// { _id: 'Chunk', values: [ 2, 4, 6 ] } -
#3380
bb069b4Thanks @dilame! - ImplementStream.onStartthat adds an effect to be executed at the start of the stream.import { Console, Effect, Stream } from "effect"const stream = Stream.make(1, 2, 3).pipe(Stream.onStart(Console.log("Stream started")),Stream.map((n) => n * 2),Stream.tap((n) => Console.log(`after mapping: ${n}`)))Effect.runPromise(Stream.runCollect(stream)).then(console.log)// Stream started// after mapping: 2// after mapping: 4// after mapping: 6// { _id: 'Chunk', values: [ 2, 4, 6 ] } -
#3380
cd255a4Thanks @tim-smart! - addbufferSizeoption to Stream.fromEventListener -
#3380
7d02174Thanks @fubhy! - Changed various function signatures to returnArrayinstead ofReadonlyArray
3.5.9
Patch Changes
-
#3377
6359644Thanks @tim-smart! - add MicroScheduler to Micro module -
#3362
7f41e42Thanks @IMax153! - AddServiceandIdentifiertoContext.Tag.These helpers can be used, for example, to extract the service shape from a tag:
import * as Context from "effect/Context"export class Foo extends Context.Tag("Foo")<Foo,{readonly foo: Effect.Effect<void>}>() {}type ServiceShape = typeof Foo.Service -
#3373
f566fd1Thanks @KhraksMamtsov! - Add test for Hash.number(0.1) !== Has.number(0)
3.5.8
Patch Changes
-
#3345
1ba640cThanks @mikearnaldi! - Fix typo propety to property -
#3349
c8c71bdThanks @tim-smart! - ensure all Data.Error arguments are preserved in .toJSON -
#3355
a26ce58Thanks @tim-smart! - fix Hash.number not returning unique values
3.5.7
Patch Changes
-
#3288
3afcc93Thanks @mikearnaldi! - Forbid usage of property “name” in Effect.Tag -
#3310
99bddcfThanks @fubhy! - Added additional pure annotations to improve tree-shakeability
3.5.6
Patch Changes
-
#3294
cc327a1Thanks @tim-smart! - correctly exclude symbols from Record.keys -
#3289
4bfe4fbThanks @dilame! - ChangedStream.groupByKey/Stream.grouped/Stream.groupedWithinJSDoc category fromutilstogrouping -
#3295
2b14d18Thanks @tim-smart! - fix YieldableError rendering on bun
3.5.5
Patch Changes
3.5.4
Patch Changes
-
#3247
ca775ceThanks @tim-smart! - if performance.timeOrigin is 0, use performance.now() directly in ClockThis is a workaround for cloudflare, where performance.now() cannot be used in the global scope to calculate the origin.
-
#3250
203658fThanks @gcanti! - add support forRefinements toPredicate.or, closes #3243import { Predicate } from "effect"// Refinement<unknown, string | number>const isStringOrNumber = Predicate.or(Predicate.isString, Predicate.isNumber) -
#3246
eb1c4d4Thanks @tim-smart! - render nested causes in Cause.pretty
3.5.3
Patch Changes
-
#3234
edb0da3Thanks @tim-smart! - do not add a error “cause” if the upstream error does not contain one -
#3236
c8d3fb0Thanks @tim-smart! - set Logger.pretty message color to deepskyblue on browsers -
#3240
dabd028Thanks @tim-smart! - fix process .isTTY detection -
#3230
786b2abThanks @KhraksMamtsov! - support heterogenous argument inOption.firstSomeOf -
#3238
fc57354Thanks @leonitousconforti! - Align Stream.run public function signatures
3.5.2
Patch Changes
-
#3228
639208eThanks @IMax153! - Render a more helpful error message when timing out an effect -
#3235
6684b4cThanks @tim-smart! - improve safari support for Logger.pretty -
#3235
6684b4cThanks @tim-smart! - fix span stack rendering when stack function returns undefined -
#3235
6684b4cThanks @tim-smart! - align UnsafeConsole group types with web apis
3.5.1
Patch Changes
3.5.0
Minor Changes
-
#3048
a1f5b83Thanks @tim-smart! - add renderErrorCause option to Cause.pretty -
#3048
60bc3d0Thanks @tim-smart! - add RcRef moduleAn
RcRefwraps a reference counted resource that can be acquired and released multiple times.The resource is lazily acquired on the first call to
getand released when the last reference is released.import { Effect, RcRef } from "effect"Effect.gen(function* () {const ref = yield* RcRef.make({acquire: Effect.acquireRelease(Effect.succeed("foo"), () =>Effect.log("release foo"))})// will only acquire the resource once, and release it// when the scope is closedyield* RcRef.get(ref).pipe(Effect.andThen(RcRef.get(ref)), Effect.scoped)}) -
#3048
5ab348fThanks @tim-smart! - allowing customizing Stream pubsub strategyimport { Schedule, Stream } from "effect"// toPubSubStream.fromSchedule(Schedule.spaced(1000)).pipe(Stream.toPubSub({capacity: 16, // or "unbounded"strategy: "dropping" // or "sliding" / "suspend"}))// also for the broadcast apisStream.fromSchedule(Schedule.spaced(1000)).pipe(Stream.broadcastDynamic({capacity: 16,strategy: "dropping"})) -
#3048
60bc3d0Thanks @tim-smart! - add Duration.isZero, for checking if a Duration is zero -
#3048
3e04bf8Thanks @sukovanej! - AddSuccesstype util forConfig. -
#3048
e7fc45fThanks @tim-smart! - add Logger.prettyLogger and Logger.prettyLogger.prettyis a new logger that leverages the features of theconsoleAPIs to provide a more visually appealing output.To try it out, provide it to your program:
import { Effect, Logger } from "effect"Effect.log("Hello, World!").pipe(Effect.provide(Logger.pretty)) -
#3048
a1f5b83Thanks @tim-smart! - add .groupCollapsed to UnsafeConsole -
#3048
4626de5Thanks @giacomoran! - export Random.make taking hashable values as seed -
#3048
f01e7dbThanks @tim-smart! - addreplayoption to PubSub constructorsThis option adds a replay buffer in front of the given PubSub. The buffer will replay the last
nmessages to any new subscriber.Effect.gen(function*() {const messages = [1, 2, 3, 4, 5]const pubsub = yield* PubSub.bounded<number>({ capacity: 16, replay: 3 })yield* PubSub.publishAll(pubsub, messages)const sub = yield* PubSub.subscribe(pubsub)assert.deepStrictEqual(Chunk.toReadonlyArray(yield* Queue.takeAll(sub)), [3, 4, 5])})) -
#3048
60bc3d0Thanks @tim-smart! - add RcMap moduleAn
RcMapcan contain multiple reference counted resources that can be indexed by a key. The resources are lazily acquired on the first call togetand released when the last reference is released.Complex keys can extend
EqualandHashto allow lookups by value.import { Effect, RcMap } from "effect"Effect.gen(function* () {const map = yield* RcMap.make({lookup: (key: string) =>Effect.acquireRelease(Effect.succeed(`acquired ${key}`), () =>Effect.log(`releasing ${key}`))})// Get "foo" from the map twice, which will only acquire it once// It will then be released once the scope closes.yield* RcMap.get(map, "foo").pipe(Effect.andThen(RcMap.get(map, "foo")),Effect.scoped)}) -
#3048
ac71f37Thanks @dilame! - EnsureScopeis excluded fromRin theChannel/Streamrun*functions.This fix ensures that
Scopeis now properly excluded from the resulting effect environment. The affected functions includerun,runCollect,runCount,runDrainand other non-scopedrun*in bothStreamandChannelmodules. This fix brings the type declaration in line with the runtime implementation. -
#3048
8432360Thanks @dilame! - refactor(Stream/mergeLeft): renameself/thatargument names toleft/rightfor clarityrefactor(Stream/mergeRight): rename
self/thatargument names toleft/rightfor clarity -
#3048
e4bf1bfThanks @dilame! - feat(Stream): implement “raceAll” operator, which returns a stream that mirrors the first source stream to emit an item.import { Stream, Schedule, Console, Effect } from "effect"const stream = Stream.raceAll(Stream.fromSchedule(Schedule.spaced("1 millis")),Stream.fromSchedule(Schedule.spaced("2 millis")),Stream.fromSchedule(Schedule.spaced("4 millis"))).pipe(Stream.take(6), Stream.tap(Console.log))Effect.runPromise(Stream.runDrain(stream))// Output only from the first stream, the rest streams are interrupted// 0// 1// 2// 3// 4// 5 -
#3048
13cb861Thanks @dilame! - refactor(Stream): use new built-inTypes.TupleOfinstead ofStream.DynamicTupleand deprecate it -
#3048
79d2d91Thanks @tim-smart! - support ErrorOptions in YieldableError constructor -
#3048
9f66825Thanks @tim-smart! - allow customizing the output buffer for the Stream.async* apisimport { Stream } from "effect"Stream.async<string>((emit) => {// ...},{bufferSize: 16,strategy: "dropping" // you can also use "sliding" or "suspend"})
Patch Changes
-
#3048
a1f5b83Thanks @tim-smart! - include Error.cause stack in log output -
#3048
a1f5b83Thanks @tim-smart! - set stackTraceLimit to 1 in PrettyError to address performance issues -
#3048
79d2d91Thanks @tim-smart! - ensure “cause” is rendered in Data.Error output -
#3048
e7fc45fThanks @tim-smart! - fix types of UnsafeConsole.group
3.4.9
Patch Changes
-
#3210
7af137cThanks @tim-smart! - prevent reclaim of manually invalidated pool items -
#3204
ee4b3dcThanks @gcanti! - Updated the JSDocs for theStreammodule by adding examples to key functions. -
#3202
097d25cThanks @tim-smart! - allow invalidated Pool items to be reclaimed with usage strategy
3.4.8
Patch Changes
-
#3181
a435e0fThanks @KhraksMamtsov! - refactorTrimEnd&TrimStart -
#3176
b5554dbThanks @tim-smart! - allow Stream run fiber to close before trying to interrupt it -
#3175
a9c4fb3Thanks @tim-smart! - ensure fibers are interrupted in Stream.mergeWith
3.4.7
Patch Changes
- #3161
a5737d6Thanks @tim-smart! - ensure PubSub.publishAll does not increase size while there are no subscribers
3.4.6
Patch Changes
-
#3096
5c0ceb0Thanks @gcanti! - Micro: align withEffectmodule (renamings and new combinators).General naming convention rule:
<reference module (start with lowercase)><api (start with Uppercase)>.Failure->MicroCauseFailure.Expected<E>->MicroCause.Fail<E>Failure.Unexpected->MicroCause.DieFailure.Aborted->MicroCause.InterruptFailureExpected->causeFailFailureUnexpected->causeDieFailureAborted->causeInterruptfailureIsExpected->causeIsFailfailureIsExpected->causeIsFailfailureIsUnexpected->causeIsDiefailureIsAborted->causeIsInterruptfailureSquash->causeSquashfailureWithTrace->causeWithTrace
Result->MicroExitResultAborted->exitInterruptResultSuccess->exitSucceedResultFail->exitFailResultFailUnexpected->exitDieResultFailWith->exitFailCauseresultIsSuccess->exitIsSuccessresultIsFailure->exitIsFailureresultIsAborted->exitIsInterruptresultIsFailureExpected->exitIsFailresultIsFailureUnexpected->exitIsDieresultVoid->exitVoid
DelayFn->MicroScheduledelayExponential->scheduleExponentialdelaySpaced->scheduleSpaceddelayWithMax->scheduleWithMaxDelaydelayWithMaxElapsed->scheduleWithMaxElapseddelayWithRecurs->scheduleRecursand make it a constructor- add
scheduleAddDelaycombinator - add
scheduleUnioncombinator - add
scheduleIntersectcombinator
Handleabort->interruptunsafeAbort->unsafeInterrupt
provideServiceMicro->provideServiceEffectfromResult->fromExitfromResultSync->fromExitSyncfailWith->failCausefailWithSync->failCauseSyncasResult->exitfilterOrFailWith->filterOrFailCauserepeatResult->repeatExitcatchFailure->catchAllCausecatchFailureIf->catchCauseIfcatchExpected->catchAllcatchUnexpected->catchAllDefecttapFailure->tapErrorCausetapFailureIf->tapErrorCauseIftapExpected->tapErrortapUnexpected->tapDefectmapFailure->mapErrorCausematchFailureMicro->matchCauseEffectmatchFailure->matchCausematchMicro->matchEffectonResult->onExitonResultIf->onExitIfonFailure->onErroronAbort->onInterruptabort->interruptrunPromiseResult->runPromiseExitrunSyncResult->runSyncExit- rename
delayoption toschedule
-
#3096
5c0ceb0Thanks @gcanti! - Micro: renametimeouttotimeoutOption, and add atimeoutthat fails with aTimeoutException -
#3121
33735b1Thanks @KhraksMamtsov! - Support for the tacit usage of external handlers forMatch.tagandMatch.tagStartsWithfunctionstype Value = { _tag: "A"; a: string } | { _tag: "B"; b: number }const handlerA = (_: { _tag: "A"; a: number }) => _.a// $ExpectType string | numberpipe(M.type<Value>(),M.tag("A", handlerA), // <-- no type issueM.orElse((_) => _.b))(value) -
#3096
5c0ceb0Thanks @gcanti! - Micro: move MicroExit types to a namespace -
#3134
139d4b3Thanks @tim-smart! - use Channel.acquireUseRelease for Channel.withSpan
3.4.5
Patch Changes
3.4.4
Patch Changes
-
#3083
72638e3Thanks @gcanti! - Micro: addNoSuchElementExceptionerror and updatefromOptionto change the failure type fromOption.None<never>toNoSuchElementException -
#3095
d7dde2bThanks @tim-smart! - remove global AbortController from Micro
3.4.3
Patch Changes
-
#3065
c342739Thanks @KhraksMamtsov! - Supportthisargument forMicro.gen -
#3067
8898e5eThanks @KhraksMamtsov! - Cleanup signal “abort” event handler inMicro.runFork -
#3082
ff78636Thanks @gcanti! - Align theMicro.catchIfsignature withEffect.catchIf -
#3078
c86bd4eThanks @KhraksMamtsov! - Support unification for Micro module
3.4.2
Patch Changes
3.4.1
Patch Changes
3.4.0
Minor Changes
-
#2938
c0ce180Thanks @LaureRC! - Make Option.liftPredicate dual -
#2938
61707b6Thanks @LaureRC! - Add Effect.liftPredicateEffect.liftPredicatetransforms aPredicatefunction into anEffectreturning the input value if the predicate returnstrueor failing with specified error if the predicate fails.import { Effect } from "effect"const isPositive = (n: number): boolean => n > 0// succeeds with `1`Effect.liftPredicate(1, isPositive, (n) => `${n} is not positive`)// fails with `"0 is not positive"`Effect.liftPredicate(0, isPositive, (n) => `${n} is not positive`) -
#2938
9c1b5b3Thanks @tim-smart! - add EventListener type to Stream to avoid use of dom lib -
#2938
a35faf8Thanks @gcanti! - AddlastNonEmptyfunction toChunkmodule, closes #2946 -
#2938
ff73c0cThanks @dilame! - feat(Stream): implement Success, Error, Context type accessors -
#2938
984d516Thanks @tim-smart! - add Micro moduleA lightweight alternative to Effect, for when bundle size really matters.
At a minimum, Micro adds 5kb gzipped to your bundle, and scales with the amount of features you use.
-
#2938
8c3b8a2Thanks @gcanti! - addManagedRuntimetype utils (Context, andError) -
#2938
91bf8a2Thanks @msensys! - AddTuple.atapi, to retrieve an element at a specified index from a tuple.import { Tuple } from "effect"assert.deepStrictEqual(Tuple.at([1, "hello", true], 1), "hello") -
#2938
c6a4a26Thanks @datner! - addensureutil for Array, used to normalizeA | ReadonlyArray<A>import { ensure } from "effect/Array"// lets say you are not 100% sure if it's a member or a collectiondeclare const someValue: { foo: string } | Array<{ foo: string }>// $ExpectType ({ foo: string })[]const normalized = ensure(someValue)
3.3.5
Patch Changes
3.3.4
Patch Changes
3.3.3
Patch Changes
-
#2999
06ede85Thanks @KhraksMamtsov! - Added tests forChunk.toArrayandChunk.toReadonlyArraywith use cases in thepipe -
#3000
7204ca5Thanks @tim-smart! - fix support for Predicates in Predicate.compose
3.3.2
Patch Changes
-
#2981
3572646Thanks @tim-smart! - ensure multiline error messages are preserved in cause rendering -
#2970
1aed347Thanks @gcanti! - UpdatedChunk.toArrayandChunk.toReadonlyArray. Improved function signatures to preserve non-empty status of chunks during conversion. -
#2977
df4bf4bThanks @tim-smart! - fix discard option in Effect.all
3.3.1
Patch Changes
-
#2952
eb98c5bThanks @KhraksMamtsov! - ChangeConfig.arrayto returnArray<A>instead ofReadonlyArray<A> -
#2950
184fed8Thanks @gcanti! - EnsureChunk.reversepreservesNonEmptystatus, closes #2947 -
#2954
6068e07Thanks @jessekelly881! - Fix runtime error inStruct.evolveby enhancing compile-time checks, closes #2953 -
#2948
3a77e20Thanks @gcanti! - Remove unnecessary===comparison ingetEquivalencefunctionsIn some
getEquivalencefunctions that usemake, there is an unnecessary===comparison. Themakefunction already handles this comparison.
3.3.0
Minor Changes
-
#2837
9305b76Thanks @mattrossman! - Add queuing strategy option for Stream.toReadableStream -
#2837
0f40d98Thanks @tim-smart! - addtimeToLiveStrategytoPooloptionsThe
timeToLiveStrategydetermines how items are invalidated. If set to “creation”, then items are invalidated based on their creation time. If set to “usage”, then items are invalidated based on pool usage.By default, the
timeToLiveStrategyis set to “usage”. -
#2837
b761ef0Thanks @tim-smart! - add Layer.annotateLogs & Layer.annotateSpansThis allows you to add log & span annotation to a Layer.
import { Effect, Layer } from "effect"Layer.effectDiscard(Effect.log("hello")).pipe(Layer.annotateLogs({service: "my-service"})) -
#2837
b53f69bThanks @dilame! - Types: implementTupleOfandTupleOfAtLeasttypesPredicate: implement
isTupleOfandisTupleOfAtLeasttype guards -
#2837
0f40d98Thanks @tim-smart! - addconcurrency&targetUtilizationoption toPool.make&Pool.makeWithTTLThis option allows you to specify the level of concurrent access per pool item. I.e. setting
concurrency: 2will allow each pool item to be in use by 2 concurrent tasks.targetUtilizationdetermines when to create new pool items. It is a value between 0 and 1, where 1 means only create new pool items when all the existing items are fully utilized.A
targetUtilizationof 0.5 will create new pool items when the existing items are 50% utilized. -
#2837
5bd549eThanks @KhraksMamtsov! - Supportthisargument for{STM, Either, Option}.gen -
#2837
67f160aThanks @KhraksMamtsov! - IntroducedRedacted<out T = string>module -SecretgeneralizationSecret extends RedactedThe use of theRedactedhas been replaced by the use of theRedactedin packages with version0.*.*
3.2.9
Patch Changes
-
#2921
8c5d280Thanks @tim-smart! - remove usage of performance.timeOrigin -
#2912
6ba6d26Thanks @mikearnaldi! - Remove toJSON from PrettyError and fix message generation -
#2923
3f28bf2Thanks @tim-smart! - only wrap objects with string keys in Config.Wrap -
#2914
5817820Thanks @mikearnaldi! - Fix id extraction in Context.Tag.Identifier
3.2.8
Patch Changes
3.2.7
Patch Changes
3.2.6
Patch Changes
3.2.5
Patch Changes
-
#2823
608b01fThanks @gcanti! - Array: simplify signatures (ReadonlyArray<any> | Iterable<any> = Iterable<any>) -
#2834
031c712Thanks @tim-smart! - attach Stream.toReadableStream fibers to scope -
#2744
a44e532Thanks @KhraksMamtsov! - makeArray.separate,Array.getRights,Array.getLefts,Array.getSomesheterogeneous
3.2.4
Patch Changes
-
#2801
1af94dfThanks @tim-smart! - ensure pool calls finalizer for failed acquisitions -
#2808
e313a01Thanks @gcanti! - Array: fixflatMapNullableimplementation and add descriptions / examples
3.2.3
Patch Changes
3.2.2
Patch Changes
-
#2787
5d9266eThanks @mikearnaldi! - Prohibit name clashes in Effect.TagThe following now correctly flags a type error given that the property
contextexists already inTag:import { Effect } from "effect"class LoaderArgs extends Effect.Tag("@services/LoaderContext")<LoaderArgs,{ context: number }>() {} -
#2797
9f8122eThanks @mikearnaldi! - Improve internalization of functions to clean stack traces -
#2798
6a6f670Thanks @mikearnaldi! - Avoid eager read of the stack when captured by a span
3.2.1
Patch Changes
- #2779
c1e991dThanks @tim-smart! - fix Config.Wrap for optional properties
3.2.0
Minor Changes
-
#2778
146caddThanks @tim-smart! - Add Stream.toReadableStreamEffect / .toReadableStreamRuntime -
#2778
7135748Thanks @tim-smart! - add Cause.prettyErrors apiYou can use this to extract
Errorinstances from aCause, that have clean stack traces and have had span information added to them. -
#2778
963b4e7Thanks @tim-smart! - add Chunk.difference & Chunk.differenceWith -
#2778
64c9414Thanks @tim-smart! - Improve causal rendering in vitest by rethrowing pretty errors -
#2778
7135748Thanks @tim-smart! - add Effect.functionWithSpanAllows you to define an effectful function that is wrapped with a span.
import { Effect } from "effect"const getTodo = Effect.functionWithSpan({body: (id: number) => Effect.succeed(`Got todo ${id}!`),options: (id) => ({name: `getTodo-${id}`,attributes: { id }})}) -
#2778
2cbb76bThanks @tim-smart! - Add do notation for Array -
#2778
870c5faThanks @tim-smart! - support $is & $match for Data.TaggedEnum with generics -
#2778
7135748Thanks @tim-smart! - capture stack trace for tracing spans
Patch Changes
-
#2778
7135748Thanks @tim-smart! - add span stack trace to rendered causes -
#2778
64c9414Thanks @tim-smart! - Consider Generator.next a cutpoint
3.1.6
Patch Changes
-
#2761
17fc22eThanks @KhraksMamtsov! - Add{ once: true }to all"abort"event listeners forAbortControllerto automatically remove handlers after execution -
#2762
810f222Thanks @tim-smart! - fix Config.Wrap incorrectly wrapping functions & arrays -
#2773
596aaeaThanks @tim-smart! - fix for Infinity delays in Schedule
3.1.5
Patch Changes
- #2750
6ac4847Thanks @tim-smart! - ensure exponential schedules don’t reach Infinity
3.1.4
Patch Changes
- #2732
e41e911Thanks @mikearnaldi! - Call Equal.equals internally in order inputs were passed.
3.1.3
Patch Changes
- #2706
1f6dc96Thanks @sukovanej! - rebuild packages
3.1.2
Patch Changes
- #2679
2e1cdf6Thanks @tim-smart! - ensure all type ids are annotated withunique symbol
3.1.1
Patch Changes
- #2670
e5e56d1Thanks @tim-smart! - Allow structural regions in equality for testing
3.1.0
Minor Changes
-
#2543
c3c12c6Thanks @github-actions! - add SortedMap.lastOption & partition apis -
#2543
ba64ea6Thanks @github-actions! - addTypes.DeepMutable, an alternative toTypes.Mutablethat makes all properties recursively mutable -
#2543
b5de2d2Thanks @github-actions! - add Effect.annotateLogsScopedThis api allows you to annotate logs until the Scope has been closed.
import { Effect } from "effect"Effect.gen(function* () {yield* Effect.log("no annotations")yield* Effect.annotateLogsScoped({ foo: "bar" })yield* Effect.log("annotated with foo=bar")}).pipe(Effect.scoped, Effect.andThen(Effect.log("no annotations again"))) -
#2543
a1c7ab8Thanks @github-actions! - added Stream.fromEventListener, and BrowserStream.{fromEventListenerWindow, fromEventListenerDocument} for constructing a stream from addEventListener -
#2543
a023f28Thanks @github-actions! - addkindproperty toTracer.SpanThis can be used to specify what kind of service created the span.
-
#2543
1c9454dThanks @github-actions! - add Effect.timeoutOptionReturns an effect that will return
Noneif the effect times out, otherwise it will returnSomeof the produced value.import { Effect } from "effect"// will return `None` after 500 millisEffect.succeed("hello").pipe(Effect.delay(1000),Effect.timeoutOption("500 millis")) -
#2543
92d56dbThanks @github-actions! - add $is & $match helpers to Data.TaggedEnum constructorsimport { Data } from "effect"type HttpError = Data.TaggedEnum<{NotFound: {}InternalServerError: { reason: string }}>const { $is, $match, InternalServerError, NotFound } =Data.taggedEnum<HttpError>()// create a matcherconst matcher = $match({NotFound: () => 0,InternalServerError: () => 1})// true$is("NotFound")(NotFound())// false$is("NotFound")(InternalServerError({ reason: "fail" }))
3.0.8
Patch Changes
-
#2656
557707bThanks @tim-smart! - update dependencies -
#2654
f4ed306Thanks @mikearnaldi! - Actually fix Cause equality -
#2640
661004fThanks @patroza! - fix: forEach NonEmpty overload causing inference issues for Iterables -
#2653
e79cb83Thanks @mikearnaldi! - Consider type of failure in Cause equality
3.0.7
Patch Changes
- #2637
18de56bThanks @mikearnaldi! - Avoid treating completed requests as interrupted when race conditions occur
3.0.6
Patch Changes
-
#2625
ffe4f4eThanks @mikearnaldi! - Avoid circularity on generators -
#2626
027418eThanks @fubhy! - Reintroduce customNoInfertype -
#2609
ac1898eThanks @patroza! - change: BatchedRequestResolver works with NonEmptyArray -
#2625
ffe4f4eThanks @mikearnaldi! - Make sure GenKind utilities are backward compatible
3.0.5
Patch Changes
-
#2611
6222404Thanks @tim-smart! - simplify EffectGenerator type to improve inference -
#2608
868ed2aThanks @patroza! - feat: foreach preserve non emptyness.
3.0.4
Patch Changes
-
#2602
9a24667Thanks @mikearnaldi! - allow use of generators (Effect.gen) without the adapterEffect’s data types now implement a Iterable that can be
yield*’ed directly.Effect.gen(function* () {const a = yield* Effect.success(1)const b = yield* Effect.success(2)return a + b})
3.0.3
Patch Changes
-
#2568
a7b4b84Thanks @tim-smart! - add Match.withReturnType apiWhich can be used to constrain the return type of a match expression.
import { Match } from "effect"Match.type<string>().pipe(Match.withReturnType<string>(),Match.when("foo", () => "foo"), // validMatch.when("bar", () => 123), // type errorMatch.else(() => "baz"))
3.0.2
Patch Changes
3.0.1
Patch Changes
-
#2539
3da0cfaThanks @tim-smart! - skip running effects in FiberHandle/Map if not required -
#2552
570e8d8Thanks @TylorS! - Improve typings of Array.isArray -
#2555
8edaccaThanks @tim-smart! - prevent use ofArrayas import name to solve bundler issues
3.0.0
Major Changes
- #2207
2fb7d9cThanks @github-actions! - Release Effect 3.0 🎉
Minor Changes
-
#2207
1b5f0c7Thanks @github-actions! - close FiberHandle/FiberSet/FiberMap when it is releasedWhen they are closed, fibers can no longer be added to them.
-
#2207
d50a652Thanks @github-actions! - add preregisteredWords option to frequency metric key typeYou can use this to register a list of words to pre-populate the value of the metric.
import { Metric } from "effect"const counts = Metric.frequency("counts", {preregisteredWords: ["a", "b", "c"]}).register() -
#2207
9a3bd47Thanks @github-actions! - Bump TypeScript min requirement to version 5.4 -
#2207
be9d025Thanks @github-actions! - add unique identifier to Tracer.ParentSpan tag -
#2529
78b767cThanks @fubhy! - RenamedReadonlyArrayandReadonlyRecordmodules for better discoverability. -
#2207
5c2b561Thanks @github-actions! - The signatures of theHaltStrategy.matchStreamHaltStrategy.matchfunctions have been changed to the generally accepted ones -
#2207
a18f594Thanks @github-actions! - support variadic arguments in Effect.logThis makes Effect.log more similar to console.log:
Effect.log("hello", { foo: "bar" }, Cause.fail("error")) -
#2207
2f96d93Thanks @github-actions! - Fix ConfigError_tag, with the previous implementation catching theConfigErrorwithEffect.catchTagwould showAnd,Or, etc. -
#2207
5a2314bThanks @github-actions! - replace use ofunitterminology withvoidFor all the data types.
Effect.unit // => Effect.voidStream.unit // => Stream.void// etc -
#2207
271b79fThanks @github-actions! - Either: fixgetEquivalenceparameter order fromEither.getEquivalence(left, right)toEither.getEquivalence({ left, right }) -
#2207
53d1c2aThanks @github-actions! - use LazyArg for Effect.if branchesInstead of:
Effect.if(true, {onTrue: Effect.succeed("true"),onFalse: Effect.succeed("false")})You should now write:
Effect.if(true, {onTrue: () => Effect.succeed("true"),onFalse: () => Effect.succeed("false")}) -
#2207
e7e1bbeThanks @github-actions! - Replaced customNoInfertype with the nativeNoInfertype from TypeScript 5.4 -
#2207
10c169eThanks @github-actions! -Cache<Key, Error, Value>has been changed toCache<Key, Value, Error = never>.ScopedCache<Key, Error, Value>has been changed toScopedCache<Key, Value, Error = never>.Lookup<Key, Environment, Error, Value>has been changed toLookup<Key, Value, Error = never, Environment = never>
Patch Changes
-
#2104
1499974Thanks @IMax153! - don’t run resolver if there are no incomplete requests -
#2207
1b5f0c7Thanks @github-actions! - add FiberMap.has/unsafeHas api -
#2104
1499974Thanks @IMax153! - add String casing transformation apissnakeToCamelsnakeToPascalsnakeToKebabcamelToSnakepascalToSnakekebabToSnake
-
#2207
1b5f0c7Thanks @github-actions! - add FiberHandle module, for holding a reference to a running fiberimport { Effect, FiberHandle } from "effect"Effect.gen(function* (_) {const handle = yield* _(FiberHandle.make())// run some effectsyield* _(FiberHandle.run(handle, Effect.never))// this will interrupt the previous fiberyield* _(FiberHandle.run(handle, Effect.never))// this will not run, as a fiber is already runningyield* _(FiberHandle.run(handle, Effect.never, { onlyIfMissing: true }))yield* _(Effect.sleep(1000))}).pipe(Effect.scoped // The fiber will be interrupted when the scope is closed) -
#2521
6424181Thanks @patroza! - change return type of Fiber.joinAll to return an array
2.4.19
Patch Changes
-
#2503
41c8102Thanks @gcanti! - Centralize error messages for bugs -
#2493
776ef2bThanks @gcanti! - add aRegExpmodule topackages/effect, closes #2488 -
#2499
217147eThanks @tim-smart! - ensure FIFO ordering when a Deferred is resolved -
#2502
90776ecThanks @tim-smart! - make tracing spans cheaper to construct -
#2472
8709856Thanks @tim-smart! - add Subscribable trait / moduleSubscribable represents a resource that has a current value and can be subscribed to for updates.
The following data types are subscribable:
- A
SubscriptionRef - An
Actorfrom the experimentalMachinemodule
- A
-
#2500
232c353Thanks @tim-smart! - simplify scope internals -
#2507
0ca835cThanks @gcanti! - ensure correct value is passed to mapping function inmapAccumloop, closes #2506 -
#2472
8709856Thanks @tim-smart! - add Readable module / traitReadableis a common interface for objects that can be read from using agetEffect.For example,
Ref’s implementReadable:import { Effect, Readable, Ref } from "effect"import assert from "assert"Effect.gen(function* (_) {const ref = yield* _(Ref.make(123))assert(Readable.isReadable(ref))const result = yield* _(ref.get)assert(result === 123)}) -
#2498
e983740Thanks @jessekelly881! - added {Readable, Subscribable}.unwrap -
#2494
e3e0924Thanks @thewilkybarkid! - AddDuration.divideandDuration.unsafeDivide.import { Duration, Option } from "effect"import assert from "assert"assert.deepStrictEqual(Duration.divide("10 seconds", 2),Option.some(Duration.decode("5 seconds")))assert.deepStrictEqual(Duration.divide("10 seconds", 0), Option.none())assert.deepStrictEqual(Duration.divide("1 nano", 1.5), Option.none())assert.deepStrictEqual(Duration.unsafeDivide("10 seconds", 2),Duration.decode("5 seconds"))assert.deepStrictEqual(Duration.unsafeDivide("10 seconds", 0),Duration.infinity)assert.throws(() => Duration.unsafeDivide("1 nano", 1.5))
2.4.18
Patch Changes
-
#2473
dadc690Thanks @tim-smart! - add Logger.withConsoleLog/withConsoleError apisThese apis send a Logger’s output to console.log/console.error respectively.
import { Logger } from "effect"// send output to stderrconst stderrLogger = Logger.withConsoleError(Logger.stringLogger)
2.4.17
Patch Changes
-
#2461
8fdfda6Thanks @tim-smart! - add Inspectable.toStringUnknown/stringifyCircular -
#2462
607b2e7Thanks @tim-smart! - remove handled errors from Effect.retryOrElse -
#2461
8fdfda6Thanks @tim-smart! - improve formatting of Runtime failures -
#2415
8206cafThanks @tim-smart! - add Iterable moduleThis module shares many apis compared to “effect/ReadonlyArray”, but is fully lazy.
import { Iterable, pipe } from "effect"// Only 5 items will be generated & transformedpipe(Iterable.range(1, 100),Iterable.map((i) => `item ${i}`),Iterable.take(5)) -
#2438
7ddd654Thanks @mikearnaldi! - Support Heterogeneous Effects in Effect Iterable apisIncluding:
Effect.allSuccessesEffect.firstSuccessOfEffect.mergeAllEffect.reduceEffectEffect.raceAllEffect.forkAll
For example:
import { Effect } from "effect"class Foo extends Effect.Tag("Foo")<Foo, 3>() {}class Bar extends Effect.Tag("Bar")<Bar, 4>() {}// const program: Effect.Effect<(1 | 2 | 3 | 4)[], never, Foo | Bar>export const program = Effect.allSuccesses([Effect.succeed(1 as const),Effect.succeed(2 as const),Foo,Bar])The above is now possible while before it was expecting all Effects to conform to the same type
-
#2438
7ddd654Thanks @mikearnaldi! - add Effect.filterMap apiWhich allows you to filter and map an Iterable of Effects in one step.
import { Effect, Option } from "effect"// resolves with `["even: 2"]Effect.filterMap([Effect.succeed(1), Effect.succeed(2), Effect.succeed(3)],(i) => (i % 2 === 0 ? Option.some(`even: ${i}`) : Option.none())) -
#2461
8fdfda6Thanks @tim-smart! - use Inspectable.toStringUnknown for absurd runtime errors -
#2460
f456ba2Thanks @tim-smart! - use const type parameter for Config.withDefaultWhich ensures that the fallback value type is not widened for literals.
2.4.16
Patch Changes
2.4.15
Patch Changes
-
#2407
d7688c0Thanks @thewilkybarkid! - Add Config.durationThis can be used to parse Duration’s from environment variables:
import { Config, Effect } from "effect"Config.duration("CACHE_TTL").pipe(Effect.andThen((duration) => ...)) -
#2416
b3a4facThanks @mikearnaldi! - Collect exits on forEach interrupt of residual requests
2.4.14
Patch Changes
2.4.13
Patch Changes
-
#2402
3336287Thanks @tim-smart! - add Duration.subtract api -
#2399
54b7c00Thanks @coleea! - add BigInt.fromString and BigInt.fromNumber -
#2402
3336287Thanks @tim-smart! - remove use of bigint literals in Duration
2.4.12
Patch Changes
- #2385
3307729Thanks @tim-smart! - update typescript to 5.4
2.4.11
Patch Changes
-
#2384
2f488c4Thanks @tim-smart! - update dependencies -
#2381
37ca592Thanks @tim-smart! - add fiber ref for disabling the tracerYou can use it with the Effect.withTracerEnabled api:
import { Effect } from "effect"Effect.succeed(42).pipe(Effect.withSpan("my-span"),// the span will not be registered with the tracerEffect.withTracerEnabled(false)) -
#2383
317b5b8Thanks @tim-smart! - add Duration.isFinite api, to determine if a duration is not Infinity
2.4.10
Patch Changes
-
#2375
9bab1f9Thanks @tim-smart! - remove dangling variable in frequency metric hook -
#2373
9bbde5bThanks @patroza! - Use incremental counters instead of up-down for runtime metrics
2.4.9
Patch Changes
- #2357
71fd528Thanks @tim-smart! - make more data types in /platform implement Inspectable
2.4.8
Patch Changes
-
#2354
bb0b69eThanks @tim-smart! - add overload to Effect.filterOrFail that fails with NoSuchElementExceptionThis allows you to perform a filterOrFail without providing a fallback failure function.
Example:
import { Effect } from "effect"// fails with NoSuchElementExceptionEffect.succeed(1).pipe(Effect.filterOrFail((n) => n === 0)) -
#2336
6b20badThanks @jessekelly881! - added Predicate.isTruthy -
#2351
4e64e9bThanks @tim-smart! - fix metrics not using labels from fiber ref -
#2266
3851a02Thanks @patroza! - fix Effect.Tag generated proxy functions to work with andThen/tap, or others that do function/isEffect checks -
#2353
5f5fcd9Thanks @tim-smart! - Types: addHashelper -
#2299
814e5b8Thanks @alex-dixon! - Prevent Effect.if from crashing when first argument is not an Effect
2.4.7
Patch Changes
- #2328
eb93283Thanks @tim-smart! - set unhandled log level to none for fibers in FiberSet/Map
2.4.6
Patch Changes
-
#2290
4f35a7eThanks @mikearnaldi! - Remove function renaming from internals, introduce new cutpoint strategy -
#2311
9971186Thanks @tim-smart! - add Channel.splitLines apiIt splits strings on newlines. Handles both Windows newlines (
\r\n) and UNIX newlines (\n).
2.4.5
Patch Changes
-
#2300
bce21c5Thanks @gcanti! - ReadonlyArray: fixinterspersesignature -
#2303
c7d3036Thanks @gcanti! - ReadonlyArray: fixsortsignature, closes #2301
2.4.4
Patch Changes
-
#2172
5d47ee0Thanks @gcanti! - Brand: addrefinedoverloadexport function refined<A extends Brand<any>>(f: (unbranded: Brand.Unbranded<A>) => Option.Option<Brand.BrandErrors>): Brand.Constructor<A> -
#2285
817a04cThanks @tim-smart! - add support for AbortSignal’s to runPromiseIf the signal is aborted, the effect execution will be interrupted.
import { Effect } from "effect"const controller = new AbortController()Effect.runPromise(Effect.never, { signal: controller.signal })// abort after 1 secondsetTimeout(() => controller.abort(), 1000) -
#2293
d90a99dThanks @tim-smart! - add AbortSignal support to ManagedRuntime -
#2288
dd05faaThanks @tim-smart! - optimize addition of blocked requests to parallel collection -
#2288
dd05faaThanks @tim-smart! - use Chunk for request block collections -
#2280
802674bThanks @jessekelly881! - added support for PromiseLike
2.4.3
Patch Changes
-
#2211
20e63fbThanks @tim-smart! - add ManagedRuntime module, to make incremental adoption easierYou can use a ManagedRuntime to run Effect’s that can use the dependencies from the given Layer. For example:
import { Console, Effect, Layer, ManagedRuntime } from "effect"class Notifications extends Effect.Tag("Notifications")<Notifications,{ readonly notify: (message: string) => Effect.Effect<void> }>() {static Live = Layer.succeed(this, {notify: (message) => Console.log(message)})}async function main() {const runtime = ManagedRuntime.make(Notifications.Live)await runtime.runPromise(Notifications.notify("Hello, world!"))await runtime.dispose()}main() -
#2211
20e63fbThanks @tim-smart! - add Layer.toRuntimeWithMemoMap apiSimilar to Layer.toRuntime, but allows you to share a Layer.MemoMap between layer builds.
By sharing the MemoMap, layers are shared between each build - ensuring layers are only built once between multiple calls to Layer.toRuntimeWithMemoMap.
2.4.2
Patch Changes
-
#2264
e03811eThanks @patroza! - fix: unmatched function fallthrough inandThenandtap -
#2225
ac41d84Thanks @mikearnaldi! - Add Effect.Tag to simplify access to service.This change allows to define tags in the following way:
class DemoTag extends Effect.Tag("DemoTag")<DemoTag,{readonly getNumbers: () => Array<number>readonly strings: Array<string>}>() {}And use them like:
DemoTag.getNumbers()DemoTag.stringsThis fuses together
serviceFunctionsandserviceConstantsin the static side of the tag.Additionally it allows using the service like:
DemoTag.use((_) => _.getNumbers())This is especially useful when having functions that contain generics in the service given that those can’t be reliably transformed at the type level and because of that we can’t put them on the tag.
-
#2238
6137533Thanks @JJayet! - Request: swap Success and Error params -
#2270
f373529Thanks @tim-smart! - add structured logging apis- Logger.json / Logger.jsonLogger
- Logger.structured / Logger.structuredLogger
Logger.jsonlogs JSON serialized strings to the console.Logger.structuredlogs structured objects, which is useful in the browser where you can inspect objects logged to the console. -
#2257
1bf9f31Thanks @mikearnaldi! - Make sure Effect.Tag works on primitives.This change allows the following to work just fine:
import { Effect, Layer } from "effect"class DateTag extends Effect.Tag("DateTag")<DateTag, Date>() {static date = new Date(1970, 1, 1)static Live = Layer.succeed(this, this.date)}class MapTag extends Effect.Tag("MapTag")<MapTag, Map<string, string>>() {static Live = Layer.effect(this,Effect.sync(() => new Map()))}class NumberTag extends Effect.Tag("NumberTag")<NumberTag, number>() {static Live = Layer.succeed(this, 100)} -
#2244
e3ff789Thanks @tim-smart! - add FiberMap/FiberSet.join apiThis api can be used to propogate failures back to a parent fiber, in case any of the fibers added to the FiberMap/FiberSet fail with an error.
Example:
import { Effect, FiberSet } from "effect"Effect.gen(function* (_) {const set = yield* _(FiberSet.make())yield* _(FiberSet.add(set, Effect.runFork(Effect.fail("error"))))// parent fiber will fail with "error"yield* _(FiberSet.join(set))}) -
#2263
507ba40Thanks @thewilkybarkid! - Allow duration inputs to be singular -
#2255
e466afeThanks @jessekelly881! - added Either.Either.{Left,Right} and Option.Option.Value type utils -
#2270
f373529Thanks @tim-smart! - add Logger.batched, for batching logger outputIt takes a duration window and an effectful function that processes the batched output.
Example:
import { Console, Effect, Logger } from "effect"const LoggerLive = Logger.replaceScoped(Logger.defaultLogger,Logger.logfmtLogger.pipe(Logger.batched("500 millis", (messages) =>Console.log("BATCH", messages.join("\n")))))Effect.gen(function* (_) {yield* _(Effect.log("one"))yield* _(Effect.log("two"))yield* _(Effect.log("three"))}).pipe(Effect.provide(LoggerLive), Effect.runFork) -
#2233
de74eb8Thanks @gcanti! - Struct: makepick/omitdual
2.4.1
Patch Changes
-
#2219
a4a0006Thanks @KhraksMamtsov! - fix documentation forPredicate.isNullPredicate.isNotNull -
#2223
0a37676Thanks @Schniz! - document Effect.zipLeft and Effect.zipRight -
#2224
6f503b7Thanks @jessekelly881! - added isSet and isMap to Predicate module
2.4.0
Minor Changes
-
#2101
5de7be5Thanks @github-actions! - remove ReadonlyRecord.fromIterable (duplicate of fromEntries) -
#2101
489fcf3Thanks @github-actions! - - swapScheduletype parameters fromSchedule<out Env, in In, out Out>toSchedule<out Out, in In = unknown, out R = never>, closes #2154- swap
ScheduleDrivertype parameters fromScheduleDriver<out Env, in In, out Out>toScheduleDriver<out Out, in In = unknown, out R = never>
- swap
-
#2101
7d9c3bfThanks @github-actions! - ConsolidateEffect.asyncOption,Effect.asyncEither,Stream.asyncOption,Stream.asyncEither, andStream.asyncInterruptThis PR removes
Effect.asyncOptionandEffect.asyncEitheras their behavior can be entirely implemented with the new signature ofEffect.async, which optionally returns a cleanupEffectfrom the registration callback.declare const async: <A, E = never, R = never>(register: (callback: (_: Effect<A, E, R>) => void,signal: AbortSignal) => void | Effect<void, never, R>,blockingOn?: FiberId) => Effect<A, E, R>Additionally, this PR removes
Stream.asyncOption,Stream.asyncEither, andStream.asyncInterruptas their behavior can be entirely implemented with the new signature ofStream.async, which can optionally return a cleanupEffectfrom the registration callback.declare const async: <A, E = never, R = never>(register: (emit: Emit<R, E, A, void>) => Effect<void, never, R> | void,outputBuffer?: number) => Stream<A, E, R> -
#2101
d8d278bThanks @github-actions! - swapGroupBytype parameters fromGroupBy<out R, out E, out K, out V>toGroupBy<out K, out V, out E = never, out R = never> -
#2101
14c5711Thanks @github-actions! - Remove Effect.unified and Effect.unifiedFn in favour of Unify.unify.The
Unifymodule fully replaces the need for specific unify functions, when before you did:import { Effect } from "effect"const effect = Effect.unified(Math.random() > 0.5 ? Effect.succeed("OK") : Effect.fail("NO"))const effectFn = Effect.unifiedFn((n: number) =>Math.random() > 0.5 ? Effect.succeed("OK") : Effect.fail("NO"))You can now do:
import { Effect, Unify } from "effect"const effect = Unify.unify(Math.random() > 0.5 ? Effect.succeed("OK") : Effect.fail("NO"))const effectFn = Unify.unify((n: number) =>Math.random() > 0.5 ? Effect.succeed("OK") : Effect.fail("NO")) -
#2101
5de7be5Thanks @github-actions! - add key type to ReadonlyRecord -
#2101
585fcceThanks @github-actions! - add support for optional property keys topick,omitandgetBefore:
import { pipe } from "effect/Function"import * as S from "effect/Struct"const struct: {a?: stringb: numberc: boolean} = { b: 1, c: true }// errorconst x = pipe(struct, S.pick("a", "b"))const record: Record<string, number> = {}const y = pipe(record, S.pick("a", "b"))console.log(y) // => { a: undefined, b: undefined }// errorconsole.log(pipe(struct, S.get("a")))Now
import { pipe } from "effect/Function"import * as S from "effect/Struct"const struct: {a?: stringb: numberc: boolean} = { b: 1, c: true }const x = pipe(struct, S.pick("a", "b"))console.log(x) // => { b: 1 }const record: Record<string, number> = {}const y = pipe(record, S.pick("a", "b"))console.log(y) // => {}console.log(pipe(struct, S.get("a"))) // => undefined -
#2101
a025b12Thanks @github-actions! - Swap type params of Either fromEither<E, A>toEither<R, L = never>.Along the same line of the other changes this allows to shorten the most common types such as:
import { Either } from "effect"const right: Either.Either<string> = Either.right("ok")
Patch Changes
-
#2193
b9cb3a9Thanks @jessekelly881! - added Number.parse, BigInt.toNumber, ParseResult.fromOption -
#2101
93b412dThanks @github-actions! - ReadonlyArray.groupBy: allow for grouping by symbols, closes #2180 -
#2101
55b26a6Thanks @github-actions! - Either: fixfromOptionoverloads order -
#2101
2097739Thanks @github-actions! - Add Do notation methodsDo,bindTo,bindandletto Either
2.3.8
Patch Changes
-
#2167
5ad2eecThanks @tim-smart! - add Hash.cachedThis api assists with adding a layer of caching, when hashing immutable data structures.
import { Data, Hash } from "effect"class User extends Data.Class<{id: numbername: string}> {[Hash.symbol]() {return Hash.cached(this, Hash.string(`${this.id}-${this.name}`))}} -
#2187
e6d36c0Thanks @tim-smart! - update development dependencies
2.3.7
Patch Changes
-
#2142
bc8404dThanks @mikearnaldi! - Expose version control via ModuleVersion.This enables low level framework authors to run their own effect version which won’t conflict with any other effect versions running on the same process.
Imagine cases where for example a function runtime is built on effect, we don’t want lifecycle of the runtime to clash with lifecycle of user-land provided code.
To manually control the module version one can use:
import * as ModuleVersion from "effect/ModuleVersion"ModuleVersion.setCurrentVersion(`my-effect-runtime-${ModuleVersion.getCurrentVersion()}`)Note that this code performs side effects and should be executed before any module is imported ideally via an init script.
The resulting order of execution has to be:
import * as ModuleVersion from "effect/ModuleVersion"ModuleVersion.setCurrentVersion(`my-effect-runtime-${ModuleVersion.getCurrentVersion()}`)import { Effect } from "effect"// rest of code -
#2159
2c5cbcdThanks @IMax153! - Avoid incrementing cache hits for expired entries -
#2165
6565916Thanks @tim-smart! - fix Hash implemention for Option.none
2.3.6
Patch Changes
-
#2145
b1163b2Thanks @tim-smart! - add RequestResolver.aroundRequests apiThis can be used to run side effects that introspect the requests being executed.
Example:
import { Effect, Request, RequestResolver } from "effect"interface GetUserById extends Request.Request<unknown> {readonly id: number}declare const resolver: RequestResolver.RequestResolver<GetUserById>RequestResolver.aroundRequests(resolver,(requests) => Effect.log(`got ${requests.length} requests`),(requests, _) => Effect.log(`finised running ${requests.length} requests`)) -
#2148
b46b869Thanks @riordanpawley! - Flipped scheduleForked types to match new <A, E, R> signature -
#2139
de1b226Thanks @mikearnaldi! - Introduce FiberId.Single, make FiberId.None behave like FiberId.Runtime, relax FiberRefs to use Single instead of Runtime.This change is a precursor to enable easier APIs to modify the Runtime when patching FiberRefs.
-
#2137
a663390Thanks @mikearnaldi! - Expose Random Tag and functions to use a specific random service implementation -
#2143
ff88f80Thanks @mikearnaldi! - Fix Cause.pretty when toString is invalidimport { Cause } from "effect"console.log(Cause.pretty(Cause.fail([{ toString: "" }])))The code above used to throw now it prints:
Terminal window Error: [{"toString":""}] -
#2080
11be07bThanks @KhraksMamtsov! - Add functional analogue ofsatisfiesoperator. This is a convenient operator to use in thepipechain to localize type errors closer to their source.import { satisfies } from "effect/Function"const test1 = satisfies<number>()(5 as const)// ^? const test: 5// @ts-expect-errorconst test2 = satisfies<string>()(5)// ^? Argument of type 'number' is not assignable to parameter of type 'string' -
#2147
c568645Thanks @tim-smart! - generate a random span id for the built-in tracerThis ensures the same span id isn’t used between application runs.
-
#2144
88835e5Thanks @mikearnaldi! - Fix withRandom and withClock types -
#2138
b415577Thanks @mikearnaldi! - Fix internals of TestAnnotationsMap making it respect equality -
#2149
ff8046fThanks @tim-smart! - add Runtime.updateFiberRefs/setFiberRef/deleteFiberRefThis change allows you to update fiber ref values inside a Runtime object.
Example:
import { Effect, FiberRef, Runtime } from "effect"const ref = FiberRef.unsafeMake(0)const updatedRuntime = Runtime.defaultRuntime.pipe(Runtime.setFiberRef(ref, 1))// returns 1const result = Runtime.runSync(updatedRuntime)(FiberRef.get(ref))
2.3.5
Patch Changes
2.3.4
Patch Changes
- #2107
17bda66Thanks @tim-smart! - ensure large semaphore takes don’t block smaller takes
2.3.3
Patch Changes
-
#2090
efd41d8Thanks @hsubra89! - UpdateRateLimiterto support passing in a customcostper effect. This is really useful for API(s) that have a “credit cost” per endpoint.Usage Example :
import { Effect, RateLimiter } from "effect"import { compose } from "effect/Function"const program = Effect.scoped(Effect.gen(function* ($) {// Create a rate limiter that has an hourly limit of 1000 creditsconst rateLimiter = yield* $(RateLimiter.make(1000, "1 hours"))// Query API costs 1 credit per call ( 1 is the default cost )const queryAPIRL = compose(rateLimiter, RateLimiter.withCost(1))// Mutation API costs 5 credits per callconst mutationAPIRL = compose(rateLimiter, RateLimiter.withCost(5))// ...// Use the pre-defined rate limitersyield* $(queryAPIRL(Effect.log("Sample Query")))yield* $(mutationAPIRL(Effect.log("Sample Mutation")))// Or set a cost on-the-flyyield* $(rateLimiter(Effect.log("Another query with a different cost")).pipe(RateLimiter.withCost(3)))})) -
#2097
0f83515Thanks @IMax153! - Updates theRateLimiter.makeconstructor to take an object ofRateLimiter.Options, which allows for specifying the rate-limiting algorithm to utilize:You can choose from either the
token-bucketor thefixed-windowalgorithms for rate-limiting.export declare namespace RateLimiter {export interface Options {/*** The maximum number of requests that should be allowed.*/readonly limit: number/*** The interval to utilize for rate-limiting requests. The semantics of the* specified `interval` vary depending on the chosen `algorithm`:** `token-bucket`: The maximum number of requests will be spread out over* the provided interval if no tokens are available.** For example, for a `RateLimiter` using the `token-bucket` algorithm with* a `limit` of `10` and an `interval` of `1 seconds`, `1` request can be* made every `100 millis`.** `fixed-window`: The maximum number of requests will be reset during each* interval. For example, for a `RateLimiter` using the `fixed-window`* algorithm with a `limit` of `10` and an `interval` of `1 seconds`, a* maximum of `10` requests can be made each second.*/readonly interval: DurationInput/*** The algorithm to utilize for rate-limiting requests.** Defaults to `token-bucket`.*/readonly algorithm?: "fixed-window" | "token-bucket"}} -
#2097
0f83515Thanks @IMax153! - return the resulting available permits from Semaphore.release
2.3.2
Patch Changes
-
#2096
6654f5fThanks @tim-smart! - default toneverfor Runtime returning functionsThis includes:
- Effect.runtime
- FiberSet.makeRuntime
It prevents
unknownfrom creeping into types, as well asneverbeing a useful default type for propogating Fiber Refs and other context. -
#2094
2eb11b4Thanks @tim-smart! - revert some type param adjustments in FiberSetmakeRuntimenow has the R parameter first again.Default to
unknownfor the A and E parameters instead of never. -
#2103
56c09bdThanks @patroza! - Expand Either and OptionandThento support themapcase like Effects’andThenFor example:
expect(pipe(Either.right(1), Either.andThen(2))).toStrictEqual(Either.right(2))expect(pipe(Either.right(1),Either.andThen(() => 2))).toStrictEqual(Either.right(2))expect(pipe(Option.some(1), Option.andThen(2))).toStrictEqual(Option.some(2))expect(pipe(Option.some(1),Option.andThen(() => 2))).toStrictEqual(Option.some(2)) -
#2098
71aa5b1Thanks @ethanniser! - removed./internal/timeoutand replaced all usages withsetTimeoutdirectlypreviously it was required to abstract away conditionally solving an bun had an issue with
setTimeout, that caused incorrect behavior that bug has since been fixed, and theisBuncheck is no longer needed as such the timeout module is also no longer needed -
#2099
1700af8Thanks @tim-smart! - optimize Effect.zip{Left,Right}for the sequential case, avoid using Effect.all internally
2.3.1
Patch Changes
- #2085
b5a8215Thanks @gcanti! - Fix Schedule typings (some APIs didn’t have Effect parameters swapped).
2.3.0
Minor Changes
-
#2006
96bcee2Thanks @github-actions! - changeRuntime.AsyncFiberExceptiontype parameters order fromAsyncFiberException<E, A>toAsyncFiberException<A, E = never> -
#2006
96bcee2Thanks @github-actions! - changeRuntime.Canceltype parameters order fromCancel<E, A>toCancel<A, E = never> -
#2006
c77f635Thanks @github-actions! - changeExittype parameter order fromExit<E, A>toExit<A, E = never> -
#2006
e343a74Thanks @github-actions! - changeResourcetype parameters order fromResource<E, A>toResource<A, E = never> -
#2006
acf1894Thanks @github-actions! - changeFiberMaptype parameters order fromFiberMap<K, E = unknown, A = unknown>toFiberMap<K, A = unknown, E = unknown> -
#2006
9a2d1c1Thanks @github-actions! - With this change we now require a string key to be provided for all tags and renames the dear oldTagtoGenericTag, so when previously you could do:import { Effect, Context } from "effect"interface Service {readonly _: unique symbol}const Service = Context.Tag<Service,{number: Effect.Effect<never, never, number>}>()you are now mandated to do:
import { Effect, Context } from "effect"interface Service {readonly _: unique symbol}const Service = Context.GenericTag<Service,{number: Effect.Effect<never, never, number>}>("Service")This makes by default all tags globals and ensures better debuggaility when unexpected errors arise.
Furthermore we introduce a new way of constructing tags that should be considered the new default:
import { Effect, Context } from "effect"class Service extends Context.Tag("Service")<Service,{number: Effect.Effect<never, never, number>}>() {}const program = Effect.flatMap(Service, ({ number }) => number).pipe(Effect.flatMap((_) => Effect.log(`number: ${_}`)))this will use “Service” as the key and will create automatically an opaque identifier (the class) to be used at the type level, it does something similar to the above in a single shot.
-
#2006
1a77f72Thanks @github-actions! - changeEffecttype parameters order fromEffect<R, E, A>toEffect<A, E = never, R = never> -
#2006
c986f0eThanks @github-actions! - changeFiberSettype parameters order fromFiberSet<E, A>toFiberSet<A, E = never> -
#2006
96bcee2Thanks @github-actions! - changeRuntime.RunCallbackOptionstype parameters order fromRunCallbackOptions<E, A>toRunCallbackOptions<A, E = never> -
#2006
70dde23Thanks @github-actions! - changeTDeferredtype parameters order fromTDeferred<E, A>toTDeferred<A, E = never> -
#2006
81b7425Thanks @github-actions! - changeStreamable.ClassandEffectable.Classtype parameters order fromClass<R, E, A>toClass<A, E = never, R = never> -
#2006
02c3461Thanks @github-actions! - With this change we remove theData.Datatype and we makeEqual.Equal&Hash.Hashimplicit traits.The main reason is that
Data.Data<A>was structurally equivalent toA & Equal.Equalbut extendingEqual.Equaldoesn’t mean that the equality is implemented by-value, so the type was simply adding noise without gaining any level of safety.The module
Dataremains unchanged at the value level, all the functions previously available are supposed to work in exactly the same manner.At the type level instead the functions return
Readonlyvariants, so for example we have:import { Data } from "effect"const obj = Data.struct({a: 0,b: 1})will have the
objtyped as:declare const obj: {readonly a: numberreadonly b: number} -
#2006
0e56e99Thanks @github-actions! - changeDeferredtype parameters order fromDeferred<E, A>toDeferred<A, E> -
#2006
8b0ded9Thanks @github-actions! - changeFibertype parameters order fromFiber<E, A>toFiber<A, E = never> -
#2006
8dd83e8Thanks @github-actions! - changeChanneltype parameters order fromChannel<out Env, in InErr, in InElem, in InDone, out OutErr, out OutElem, out OutDone>toChannel<OutElem, InElem = unknown, OutErr = never, InErr = unknown, OutDone = void, InDone = unknown, Env = never> -
#2006
d75f6feThanks @github-actions! - changeTaketype parameters order fromTake<E, A>toTake<A, E = never> -
#2006
7356e5cThanks @github-actions! - changeSTMtype parameters order fromSTM<R, E, A>toSTM<A, E = never, R = never> -
#2006
3077cdeThanks @github-actions! - changeStreamtype parameters order fromStream<R, E, A>toStream<A, E = never, R = never> -
#2006
78f47abThanks @github-actions! - changePooltype parameters order fromPool<E, A>toPool<A, E = never>, andKeyedPoolfromKeyedPool<E, A>toKeyedPool<A, E = never> -
#2006
52e5d20Thanks @github-actions! - changeRequesttype parameters order fromRequest<E, A>toRequest<A, E = never> -
#2006
c6137ecThanks @github-actions! - changeRuntimeFibertype parameters order fromRuntimeFiber<E, A>toRuntimeFiber<A, E = never> -
#2006
f5ae081Thanks @github-actions! - UseTimeoutExceptioninstead ofNoSuchElementExceptionfor timeout. -
#2006
60686f5Thanks @github-actions! - changeLayertype parameters order fromLayer<RIn, E, ROut>toLayer<ROut, E = never, RIn = never> -
#2006
9a2d1c1Thanks @github-actions! - This change enablesEffect.serviceConstantsandEffect.serviceMembersto access any constant in the service, not only the effects, namely it is now possible to do:import { Effect, Context } from "effect"class NumberRepo extends Context.TagClass("NumberRepo")<NumberRepo,{readonly numbers: Array<number>}>() {static numbers = Effect.serviceConstants(NumberRepo).numbers} -
#2006
5127afeThanks @github-actions! - Rename ReadonlyRecord.update to .replace -
#2006
8ee2931Thanks @github-actions! - enhance DX by swapping type parameters and adding defaults to:- Effect
- async
- asyncOption
- asyncEither
- Stream
- asyncEffect
- asyncInterrupt
- asyncOption
- asyncScoped
- identity
- Effect
-
#2006
6727474Thanks @github-actions! - changeSinktype parameters order fromSink<out R, out E, in In, out L, out Z>toSink<out A, in In = unknown, out L = never, out E = never, out R = never> -
#2006
5127afeThanks @github-actions! - rename ReadonlyRecord.upsert to .set
Patch Changes
-
#2006
5127afeThanks @github-actions! - add ReadonlyRecord.modify -
#2083
be19ce0Thanks @mikearnaldi! - AddRatelimiterwhich limits the number of calls to a resource within a time window using the token bucket algorithm.Usage Example:
import { Effect, RateLimiter } from "effect"// we need a scope because the rate limiter needs to allocate a state and a background jobconst program = Effect.scoped(Effect.gen(function* ($) {// create a rate limiter that executes up to 10 requests within 2 secondsconst rateLimit = yield* $(RateLimiter.make(10, "2 seconds"))// simulate repeated callsfor (let n = 0; n < 100; n++) {// wrap the effect we want to limit with rateLimityield* $(rateLimit(Effect.log("Calling RateLimited Effect")))}}))// will print 10 calls immediately and then throttleprogram.pipe(Effect.runFork)Or, in a more real world scenario, with a dedicated Service + Layer:
import { Context, Effect, Layer, RateLimiter } from "effect"class ApiLimiter extends Context.Tag("@services/ApiLimiter")<ApiLimiter,RateLimiter.RateLimiter>() {static Live = RateLimiter.make(10, "2 seconds").pipe(Layer.scoped(ApiLimiter))}const program = Effect.gen(function* ($) {const rateLimit = yield* $(ApiLimiter)for (let n = 0; n < 100; n++) {yield* $(rateLimit(Effect.log("Calling RateLimited Effect")))}})program.pipe(Effect.provide(ApiLimiter.Live), Effect.runFork) -
#2084
4a5d01aThanks @tim-smart! - simplify RateLimiter implementation using semaphore -
#2084
4a5d01aThanks @tim-smart! - add Number.nextPow2This function returns the next power of 2 from the given number.
import { nextPow2 } from "effect/Number"assert.deepStrictEqual(nextPow2(5), 8)assert.deepStrictEqual(nextPow2(17), 32)
2.2.5
Patch Changes
-
#2075
3ddfdbfThanks @tim-smart! - add apis for manipulating context to the Runtime moduleThese include:
Runtime.updateContextfor modifying theContextdirectlyRuntime.provideServicefor adding services to an existing Runtime
Example:
import { Context, Runtime } from "effect"interface Name {readonly _: unique symbol}const Name = Context.Tag<Name, string>("Name")const runtime: Runtime.Runtime<Name> = Runtime.defaultRuntime.pipe(Runtime.provideService(Name, "John")) -
#2075
3ddfdbfThanks @tim-smart! - add apis for patching runtime flags to the Runtime moduleThe apis include:
Runtime.updateRuntimeFlagsfor updating all the flags at onceRuntime.enableRuntimeFlagfor enabling a single runtime flagRuntime.disableRuntimeFlagfor disabling a single runtime flag
2.2.4
Patch Changes
-
#2067
d0b911cThanks @tim-smart! - add releaseAll api to SemaphoreYou can use
semphore.releaseAllto atomically release all the permits of a Semaphore. -
#2071
330e1a4Thanks @tim-smart! - add Option.orElseSomeAllows you to specify a default value for an Option, similar to Option.getOrElse, except the return value is still an Option.
import * as O from "effect/Option"import { pipe } from "effect/Function"assert.deepStrictEqual(pipe(O.none(),O.orElseSome(() => "b")),O.some("b"))assert.deepStrictEqual(pipe(O.some("a"),O.orElseSome(() => "b")),O.some("a")) -
#2057
6928a2bThanks @joepjoosten! - Fix for possible stack overflow errors when using Array.push with spread operator arguments
2.2.3
Patch Changes
-
#2004
22794e0Thanks @IMax153! - add documentation to Effect.intoDeferred -
#2007
f73e6c0Thanks @tim-smart! - optimize fiber id hashing
2.2.2
Patch Changes
-
#1970
d404561Thanks @IMax153! - execute acquire inScopedRefuninterruptibly -
#1971
7b84a3cThanks @IMax153! - race interruptibly inChannel.mergeAllWith
2.2.1
Patch Changes
-
#1964
84da31fThanks @gcanti! - ReadonlyArray: fixsortWithsig, closes #1961 -
#1958
645bea2Thanks @gcanti! - Fix signatures related to predicates, closes #1916
2.2.0
Minor Changes
-
#1951
ee4ff8aThanks @github-actions! - make data-last FiberSet.run accept an Effect -
#1951
ee4ff8aThanks @github-actions! - make data-last FiberMap.run accept an Effect
Patch Changes
-
#1957
202befcThanks @IMax153! - cacheFiberIdhash in the constructor -
#1951
ee4ff8aThanks @github-actions! - add Fiber{Map,Set}.makeRuntime -
#1951
ee4ff8aThanks @github-actions! - add Fiber{Set,Map}.runtime api -
#1952
10df798Thanks @tim-smart! - avoid sleep for zero duration in schedule
2.1.2
Patch Changes
2.1.1
Patch Changes
2.1.0
Minor Changes
-
#1919
05c44b3Thanks @github-actions! - Add immediate:boolean flag to runFork/runCallback -
#1919
05c44b3Thanks @github-actions! - Improve Effect.retry options -
#1919
05c44b3Thanks @github-actions! - remove Effect.retry* variants -
#1919
05c44b3Thanks @github-actions! - Allow providing Scope to Runtime.runFork -
#1919
05c44b3Thanks @github-actions! - Add RunForkOptions to Effect.runFork
Patch Changes
- #1919
05c44b3Thanks @github-actions! - add Effect.repeat options overload
2.0.5
Patch Changes
- #1920
f7f19f6Thanks @tim-smart! - add FiberMap.remove
2.0.4
Patch Changes
-
#1897
536c1dfThanks @tim-smart! - add FiberSet module -
#1871
540b294Thanks @SandroMaglione! - added Trie module -
#1897
536c1dfThanks @tim-smart! - add MutableHashMap.clear -
#1903
a3f96d6Thanks @fubhy! - Converted value bag classes to object literals -
#1897
536c1dfThanks @tim-smart! - add FiberMap module -
#1894
25adce7Thanks @tim-smart! - allow pre-validated cron expressions for Schedule.cron -
#1897
536c1dfThanks @tim-smart! - add MutableHashSet.clear
2.0.3
Patch Changes
-
#1884
87f7ef2Thanks @fubhy! - AddedCronmodule andSchedule.cronconstructor -
#1885
1d3a06bThanks @mikearnaldi! - Avoid killing all fibers on interrupt
2.0.2
Patch Changes
- #1850
d5a1949Thanks @matheuspuel! - add index argument to many functions in ReadonlyArray
2.0.1
Patch Changes
- #1859
16bd87dThanks @sukovanej! - Include Config.LiteralValue in dts.
2.0.0
Minor Changes
d0471caThanks @mikearnaldi! - Switch to monorepo structure
Patch Changes
-
d987daaThanks @mikearnaldi! - Switch effect dependency to caret -
#1797
7b5eaa3Thanks @matheuspuel! - make serviceFunctions and similar accept an Effect as the service -
#1854
0724211Thanks @gcanti! - Add Option-returning overloads for findFirst and findLast in ReadonlyArray -
#1795
9f2bc5aThanks @matheuspuel! - add Config.literal -
#1848
04fb8b4Thanks @fubhy! - Avoid default parameter initilization -
#1847
bcf0900Thanks @fubhy! - Avoid inline creation & spreading of objects and arrays -
#1798
6299b84Thanks @leonitousconforti! - Uncommented linesIterator string function
2.0.0-next.62
Minor Changes
- #1780
d6dd74eThanks @tim-smart! - use NoSuchElementException for more optional apis
Patch Changes
-
#1785
11a6910Thanks @tim-smart! - simplify Match extraction types -
#1782
1f398cfThanks @tim-smart! - add Layer.empty -
#1786
d27b68bThanks @tim-smart! - only add one predicate in Match.discriminators
2.0.0-next.61
Patch Changes
-
#1768
7c6b90cThanks @gcanti! - Effect.mergeAll should work when Z is an iterable, closes #1765 -
#1772
a1ba0c4Thanks @gcanti! - ReadonlyRecord: addfromIterableBy -
#1778
2c5a401Thanks @IMax153! - add ConfigProvider.fromJson to support loading configuration from a JSON object -
#1770
d4d403eThanks @tim-smart! - adjust metric boundaries for timer histograms -
#1776
4c22ed5Thanks @fubhy! - Self-assign normalizedBigDecimal
2.0.0-next.60
Minor Changes
Patch Changes
-
#1756
7c1dcc7Thanks @mikearnaldi! - Fix stack filtering for first throw point -
#1749
299e8b5Thanks @IMax153! - fix the jsdoc for Effect.withConsoleScoped -
#1758
88d957dThanks @mikearnaldi! - Fix provideSomeRuntime internals, restore context and flags properly -
#1754
6a95cc0Thanks @tim-smart! - make Config implement Effect
2.0.0-next.59
Minor Changes
-
#1743
143ee1eThanks @tim-smart! - rename FiberRefs.updatedAs to FiberRef.updateAs -
#1738
d4abb06Thanks @gcanti! - ReaonlyRecord: renamefromIterabletofromIterableWithand add standardfromIterableAPI -
#1743
143ee1eThanks @tim-smart! - use native js data types for Metrics
Patch Changes
-
#1733
8177e4cThanks @IMax153! - addwithConsoleScopedtoConsole/Effectmodules -
#1726
1152a2cThanks @gcanti! - ReadonlyArray: fix the tacit use of unzip -
#1743
143ee1eThanks @tim-smart! - prefer Date.now() over new Date().getTime() -
#1735
cf4c044Thanks @tim-smart! - expose Layer MemoMap apis -
#1724
1884fa3Thanks @gcanti! - Chunk: fix the tacit use of flatten -
#1726
1152a2cThanks @gcanti! - ReadonlyArray: fix the tacit use of reverse -
#1726
1152a2cThanks @gcanti! - ReadonlyArray: fix the tacit use of dedupe -
#1743
143ee1eThanks @tim-smart! - add FiberRefs.updateManyAs -
#1743
143ee1eThanks @tim-smart! - short circuit for empty patches -
#1736
8249277Thanks @gcanti! - ReadonlyArray: add splitWhere -
#1729
3c77e12Thanks @jessekelly881! - updated BigDecimal.toString -
#1726
1152a2cThanks @gcanti! - Chunk > flatMap: fix return type -
#1726
1152a2cThanks @gcanti! - ReadonlyArray: fix sortBy signature -
#1726
1152a2cThanks @gcanti! - ReadonlyArray: fix chop signature -
#1726
1152a2cThanks @gcanti! - List > flatMap: fix return type -
#1743
143ee1eThanks @tim-smart! - replace use of throw in fiber runtime -
#1743
143ee1eThanks @tim-smart! - optimize FiberRef.update/forkAs -
#1724
1884fa3Thanks @gcanti! - ReadonlyArray: fix the tacit use of flatten -
#1727
9b5f72dThanks @photomoose! - Fix number of retries in retryN -
#1735
cf4c044Thanks @tim-smart! - fix memoization of Layer.effect/scoped -
#1726
1152a2cThanks @gcanti! - ReadonlyArray: fix dedupeWith signature -
#1726
1152a2cThanks @gcanti! - ReadonlyArray > flatMap: fix return type -
#1743
143ee1eThanks @tim-smart! - optimize MutableHashMap -
#1745
c142caaThanks @IMax153! - rename ConfigSecret to Secret -
#1733
8177e4cThanks @IMax153! - exportConsolecombinators from theEffectmodule to match other default services
2.0.0-next.58
Patch Changes
-
#1722
b5569e3Thanks @tim-smart! - update build setup to put cjs in root directory -
#1720
56a0334Thanks @tim-smart! - fix jsdoc for Inspectable.format
2.0.0-next.57
Minor Changes
-
#1701
739460b06Thanks @fubhy! - Allow to set a custom description for timer metrics -
#1704
accf8a647Thanks @fubhy! - RenamedReadonlyArray.compactandReadonlyRecord.compactto.getSomes -
#1716
023b512bdThanks @gcanti! - List: merge NonEmpty APIs into base ones -
#1717
869c9c31dThanks @gcanti! - ReadonlyArray: merge NonEmpty APIs into base ones -
#1713
906343263Thanks @gcanti! - BigDecimal: renametoStringtoformat -
#1688
9698427feThanks @tim-smart! - replace Layer.provide* with Layer.use* -
#1711
ff6fadb93Thanks @gcanti! - Chunk: merge NonEmpty APIs into base ones -
#1707
fb1a98fabThanks @gcanti! - Layer: renamezipWithPartozipWith(standard)
Patch Changes
-
#1690
eb6d7aadaThanks @tim-smart! - allow omission of Scope type in R of Stream.asyncScoped -
#1704
accf8a647Thanks @fubhy! - Added.getLeftsand.getRights -
#1703
f8d27500dThanks @jessekelly881! - improved Duration.toString -
#1689
a0bd532e8Thanks @FedericoBiccheddu! - improvePool’smakeWithTTLJSDoc example -
#1715
8b1a7e8a1Thanks @tim-smart! - only add onInterrupt in Effect.async if required -
#1694
33ffa62b4Thanks @extremegf! - Add Either.filterOrLeft -
#1695
7ccd1eb0bThanks @jessekelly881! - added Option.andThen -
#1706
8a1e98ce3Thanks @mikearnaldi! - Improve consistency between request batching and fiber environment.In prior releases request batching required operators that act on fiber context such as
Effect.locallyto be aware of batching in order to avoid bugs where the effect executed post batching would lose the fiber environment (context, refs, and flags).This change restructure how batching internally works, inside the fiber we now slice up the stack and restore the exact context that was destroyed, by rewriting the internals of forEach batching is now transparent to any other function that deals with fiber state.
-
#1687
e4d90ed38Thanks @matheuspuel! - fix YieldableError.toString crashing on react-native -
#1681
e5cd27c7dThanks @matheuspuel! - forbid excess properties when matching tags -
#1692
37a7cfe94Thanks @tim-smart! - add PrimaryKey.value -
#1679
c1146e473Thanks @k44! - fix error value ofEffect.tryPromise -
#1719
30893ed48Thanks @tim-smart! - add Request.failCause -
#1712
e2ccf5120Thanks @thewilkybarkid! - fix ReadonlyArray.difference description -
#1715
8b1a7e8a1Thanks @tim-smart! - simplify Effect.tryCatch implementation -
#1684
aeb33b158Thanks @KhraksMamtsov! - change typo in Either documentation -
#1699
06eb1d380Thanks @gcanti! - Config: standardize error messages -
#1683
a6a78ccadThanks @tim-smart! - add default type to data class props generic -
#1718
3b0768ce6Thanks @KhraksMamtsov! - get ridabsorbmention -
#1686
9f4d2874dThanks @gcanti! - Types: add variance helpers -
#1697
e1a4b6a63Thanks @tim-smart! - expose currentConcurrency fiber ref
2.0.0-next.56
Minor Changes
-
#1671
c415248cdThanks @tim-smart! - support Promise in Effect.andThen and .tap -
#1671
c415248cdThanks @tim-smart! - add Cause.UnknownException and use it overunknown -
#1678
8ed7626a4Thanks @tim-smart! - usenewfor Cause error constructors
Patch Changes
-
#1662
aa6787e16Thanks @gcanti! - TDeferred: fix E, A variance (from covariant to invariant) -
#1662
aa6787e16Thanks @gcanti! - SynchronizedRef: fix A variance (from covariant to invariant) -
#1661
6c32d12d7Thanks @fubhy! - UsesideEffects: []in package.json -
#1663
69bcb5b7aThanks @tim-smart! - add TaggedClass to /request -
#1676
995318829Thanks @tim-smart! - support undefined values in TPubSub -
#1658
396428a73Thanks @wmaurer! - ReadonlyArray: Improved refinement typings for partition -
#1672
80bf68da5Thanks @tim-smart! - add metric .register() for forcing addition to registry -
#1669
541330b11Thanks @tim-smart! - add PrimaryKey module -
#1662
aa6787e16Thanks @gcanti! - RedBlackTree: make Key invariant -
#1664
54ce5e638Thanks @gcanti! - PollingMetric: renamed to MetricPolling (standard) -
#1662
aa6787e16Thanks @gcanti! - Deferred: fix E and A variance (from covariant to invariant) -
#1660
ecc334703Thanks @gcanti! - HashMap: swap findFirst > predicate arguments (standard) -
#1662
aa6787e16Thanks @gcanti! - TSet: fix A variance (from covariant to invariant) -
#1603
4e7a6912cThanks @mikearnaldi! - Auto-flattening Effect.tap -
#1662
aa6787e16Thanks @gcanti! - RequestResolver: fix A variance (from covariant to contravariant) -
#1662
aa6787e16Thanks @gcanti! - ScopedRef: fix A variance (from covariant to invariant) -
#1662
aa6787e16Thanks @gcanti! - Reloadable: fix A variance (from covariant to invariant) -
#1660
ecc334703Thanks @gcanti! - fix ReadonlyRecord.partition signature -
#1670
c3bfc90e4Thanks @tim-smart! - add Request.Class -
#1662
aa6787e16Thanks @gcanti! - Resource: fix E, A variance (from covariant to invariant) -
#1674
c687a8701Thanks @fubhy! - Allow hrtime asDurationinput -
#1676
995318829Thanks @tim-smart! - support undefined values in TQueue -
#1668
fc9bce6a2Thanks @gcanti! - Config: propagate the path in validation, closes #1667 -
#1662
aa6787e16Thanks @gcanti! - PubSub: fix A variance (from contravariant to invariant) -
#1676
995318829Thanks @tim-smart! - support null values in PubSub -
#1655
0c6330db0Thanks @gcanti! - interfaces: revert changing methods to props (RE: #1644) -
#1662
aa6787e16Thanks @gcanti! - FiberRef: fix A variance (from covariant to invariant) -
#1662
aa6787e16Thanks @gcanti! - StrategyVariance: fix A variance (from covariant to invariant) -
#1678
8ed7626a4Thanks @tim-smart! - Cause.YieldableError extends Inspectable -
#1662
aa6787e16Thanks @gcanti! - TMap: fix K, V variance (from covariant to invariant) -
#1665
a00b920b8Thanks @gcanti! - Chunk: fix partition signature (expose the index of the element) -
#1662
aa6787e16Thanks @gcanti! - Pool: fix A variance (from covariant to invariant) -
#1662
aa6787e16Thanks @gcanti! - Cache / ConsumerCache: fix Key variance (from contravariant to invariant) -
#1662
aa6787e16Thanks @gcanti! - SubscriptionRef: fix A variance (from covariant to invariant) -
#1603
4e7a6912cThanks @mikearnaldi! - Introduce Types.NoInfer -
#1662
aa6787e16Thanks @gcanti! - TPriorityQueue: fix A variance (from covariant to invariant) -
#1662
aa6787e16Thanks @gcanti! - SortedSet: make A invariant -
#1654
d2b7e0ef0Thanks @wmaurer! - Added refinement overloads to Sink.collectAllWhile, Stream.partition and Stream.takeWhile. Added dtslint tests for Sink and Stream functions with refinement overloads -
#1662
aa6787e16Thanks @gcanti! - SortedMap: make K invariant -
#1603
4e7a6912cThanks @mikearnaldi! - Introduce Effect.andThen -
#1662
aa6787e16Thanks @gcanti! - TArray: fix A variance (from covariant to invariant) -
#1662
aa6787e16Thanks @gcanti! - KeyedPool: fix A variance (from covariant to invariant) -
#1671
c415248cdThanks @tim-smart! - move internal exceptions into core
2.0.0-next.55
Patch Changes
-
#1648
b2cbb6a79Thanks @gcanti! - Cause: fix exception constructors (should respectexactOptionalPropertyTypes: truewhen creatingmessageprop) -
#1621
33c06822dThanks @gcanti! - SortedSet: make fromIterable dual -
#1608
a9082c91cThanks @mikearnaldi! - Fix off-by-one in Random.shuffle -
#1628
ba1aa04a8Thanks @gcanti! - TSet: replace toReadonlyArray with toArray -
#1625
cc9a03ac7Thanks @gcanti! - TMap: rename reduceWithIndex / reduceWithIndexSTM to reduce / reduceSTM -
#1649
a3cda801aThanks @gcanti! - interfaces: replace 0-arity functions with values -
#1625
cc9a03ac7Thanks @gcanti! - TMap: removeIf returnsArray<[K, V]>instead ofArray<readonly [K, V]> -
#1642
b2fdff3b8Thanks @gcanti! - TMap: merge removeIf / removeIfDiscard, retainIf / retainIf ({ discard: boolean }optional argument) -
#1631
af2854596Thanks @gcanti! - Duration: refactorbetweenwith anoptionsargument forminimumandmaximum(standard) -
#1625
cc9a03ac7Thanks @gcanti! - TMap: replace toReadonlyMap with toMap -
#1631
af2854596Thanks @gcanti! - Duration: refactorclampwith anoptionsargument forminimumandmaximum(standard) -
#1638
4eedf057bThanks @gcanti! - Predicate: exclude functions fromisRecord -
#1645
d2e15f377Thanks @tim-smart! - add Logger.withSpanAnnotations -
#1611
8b22648aaThanks @tim-smart! - ensure pool acquire is interruptible when allocated dynamically -
#1642
b2fdff3b8Thanks @gcanti! - TSet: merge removeIf / removeIfDiscard, retainIf / retainIf ({ discard: boolean }optional argument) -
#1647
82006f69bThanks @gcanti! - turn on exactOptionalPropertyTypes -
#1619
66e6939eaThanks @gcanti! - remove readonly tuples from return type when possible -
#1631
af2854596Thanks @gcanti! - Order: refactorclampwith anoptionsargument forminimumandmaximum(standard) -
#1628
ba1aa04a8Thanks @gcanti! - TPriorityQueue: replace toArray with toChunk -
#1617
79719018bThanks @gcanti! - SortedMap: change entries to return IterableIterator<[K, V]> -
#1644
6e2c84d4cThanks @gcanti! - interfaces: add readonly modifiers when missing and remove bivariance by changing methods to props -
#1607
e7101ef05Thanks @mikearnaldi! - Remove potentially offenive language -
#1639
b27958bc5Thanks @gcanti! - Match: fix record signature (remove any from the codomain) -
#1628
ba1aa04a8Thanks @gcanti! - List: replace toReadonlyArray with toArray -
#1621
33c06822dThanks @gcanti! - SortedMap: make fromIterable dual -
#1631
af2854596Thanks @gcanti! - Number: refactorbetweenwith anoptionsargument forminimumandmaximum(standard) -
#1628
ba1aa04a8Thanks @gcanti! - TSet: fix toChunk (was returning an array) -
#1631
af2854596Thanks @gcanti! - Number: refactorclampwith anoptionsargument forminimumandmaximum(standard) -
#1631
af2854596Thanks @gcanti! - BigDecimal: refactorclampwith anoptionsargument forminimumandmaximum(standard) -
#1631
af2854596Thanks @gcanti! - BigInt: refactorbetweenwith anoptionsargument forminimumandmaximum(standard) -
#1631
af2854596Thanks @gcanti! - BigInt: refactorclampwith anoptionsargument forminimumandmaximum(standard) -
#1641
f0a4bf430Thanks @gcanti! - RedBlackTree: fix bug in Hash and Equal implementation -
#1625
cc9a03ac7Thanks @gcanti! - TMap: fix toChunk (was returning an array) -
#1606
265f60842Thanks @tim-smart! - add Logger.mapInputOptions -
#1632
c86f87c1bThanks @gcanti! - Either: renamereversetoflip(to align withEffect.flip) -
#1599
c3cb2dff7Thanks @gcanti! - add Refinement overloading to Effect.loop -
#1638
4eedf057bThanks @gcanti! - Match: addsymbolpredicate -
#1640
9ea7edf77Thanks @gcanti! - fix link in “please report an issue…” message -
#1597
38643141dThanks @gcanti! - add Refinement overloading to Effect.iterate, closes #1596 -
#1621
33c06822dThanks @gcanti! - RedBlackTree: make fromIterable dual -
#1631
af2854596Thanks @gcanti! - Order: refactorbetweenwith anoptionsargument forminimumandmaximum(standard) -
#1625
cc9a03ac7Thanks @gcanti! - TMap: retainIf returnsArray<[K, V]>instead ofArray<readonly [K, V]> -
#1630
67025357eThanks @gcanti! - Tuple: renametupletomake(standard) -
#1628
ba1aa04a8Thanks @gcanti! - TPriorityQueue: replace toReadonlyArray with toArray -
#1625
cc9a03ac7Thanks @gcanti! - TMap: replace toReadonlyArray with toArray -
#1631
af2854596Thanks @gcanti! - BigDecimal: refactorbetweenwith anoptionsargument forminimumandmaximum(standard)
2.0.0-next.54
Patch Changes
- #1594
a3a31c722Thanks @tim-smart! - fix regression in process.hrtime detection
2.0.0-next.53
Minor Changes
-
#1562
0effd559eThanks @tim-smart! - rename RequestResolver.fromFunctionEffect to fromEffect -
#1564
0eb0605b8Thanks @mikearnaldi! - Isolate state by version and check for version correctness
Patch Changes
-
#1586
3ed4997c6Thanks @leonitousconforti! - Fix List.map implementation of the index parameter and removed the index parameter from List.flatMapNonEmpty -
#1593
92f7316a2Thanks @tim-smart! - fix timeOrigin polyfill in clock -
#1568
a51fb6d80Thanks @tim-smart! - add Stream.accumulate -
#1592
57d8f1792Thanks @gcanti! - Predicate: add hasProperty (+ internal refactoring to leverage it) -
#1562
0effd559eThanks @tim-smart! - add RequestResolver.fromEffectTagged -
#1588
7c9d15c25Thanks @mikearnaldi! - Fix fiber failure stack -
#1568
a51fb6d80Thanks @tim-smart! - add Stream.accumulateChunks -
#1585
e0ef64102Thanks @gcanti! - Chunk: getEquivalence, resolve index out-of-bounds error when comparing chunks of different lengths
2.0.0-next.52
Patch Changes
- #1565
98de6fe6eThanks @tim-smart! - fix support for optional props in Data classes
2.0.0-next.51
Minor Changes
- #1560
1395dc58cThanks @tim-smart! - use Proxy for TaggedEnum constructors
Patch Changes
-
#1555
62140675cThanks @gcanti! - ReadonlyArray / List / Chunk: merge mapNonEmpty with map -
#1559
6114c3893Thanks @mikearnaldi! - Avoid relying on captureStackTrace for Data.Error -
#1554
fe7d7c28bThanks @sukovanej! - FixStruct.omitandStruct.pickreturn types. -
#1547
c0569f8feThanks @gcanti! - Data: improve DX (displayed types)Previously, the displayed types of data used the Omit type to exclude certain fields. This commit removes the use of Omit from the displayed types of data. This makes the types simpler and easier to understand. It also enforces all fields as readonly.
-
#1549
f82208687Thanks @mikearnaldi! - Fix missing globalValue in Logger and Query -
#1557
15013f707Thanks @mikearnaldi! - Allow optional parameters to be used in TaggedEnum
2.0.0-next.50
Minor Changes
-
#1526
656955944Thanks @gcanti! - ReadonlyRecord: remove useless alias toArray -
#1539
9c7dea219Thanks @tim-smart! - remove sampled from span options -
#1530
7c3a6d59dThanks @fubhy! - Changedividereturn type toOptionand added aunsafeDivideoperation that throws in case the divisor is0 -
#1535
fd296a6d5Thanks @tim-smart! - use context for tracer spans -
#1534
fb26bb770Thanks @fubhy! - Removed optional math variants
Patch Changes
-
#1537
9bd70154bThanks @patroza! - fix: Either/Option gen when no yield executes, just a plain return -
#1526
656955944Thanks @gcanti! - ReadonlyRecord: add missing APIs:- keys
- values
- upsert
- update
- isSubrecord
- isSubrecordBy
- reduce
- every
- some
- union
- intersection
- difference
- getEquivalence
- singleton
-
#1536
80800bfb0Thanks @fubhy! - avoid use of bigint literals
2.0.0-next.49
Patch Changes
-
#1517
685a645b9Thanks @tim-smart! - fix off-by-one bug in Stream.fromIterable -
#1489
c2a11978fThanks @FedericoBiccheddu! - AddChunk.mapNonEmpty -
#1516
ccbb23ba3Thanks @tim-smart! - export Channel.suspend -
#1511
35ecb915aThanks @tim-smart! - improve Cause toJSON output -
#1489
c2a11978fThanks @FedericoBiccheddu! - AddList.mapNonEmpty -
#1519
43fdc45bfThanks @gcanti! - HashMap: add Key, Value type-level helpers -
#1525
f710599dfThanks @ahrjarrett! - removes unnecessary type parameter from TaggedEnum -
#1521
2db755525Thanks @ahrjarrett! - enforce that members passed to TaggedEnum do not have a_tagproperty themselves -
#1529
df512220eThanks @tim-smart! - fix Channel.mergeAllWith unbounded concurrency
2.0.0-next.48
Minor Changes
-
#1500
8c81e5830Thanks @sukovanej! - Allow log annotations to be any object. -
#1506
a4fbb7055Thanks @tim-smart! - move Effect.set* Layer apis to the Layer module -
#1500
8c81e5830Thanks @sukovanej! - add sampled flag to spans -
#1506
a4fbb7055Thanks @tim-smart! - refactor Effect span apis
Patch Changes
-
#1504
f186416b9Thanks @kutyel! - feat: addapmethod toEffect,apandzipWithtoEither⚡️ -
#1507
2397b5548Thanks @tim-smart! - allow message property on Data YieldableError -
#1501
4ca2abd06Thanks @tim-smart! - add Match module -
#1500
8c81e5830Thanks @sukovanej! - allow tracing attributes to be unknown -
#1506
a4fbb7055Thanks @tim-smart! - add onEnd finalizer to Layer span apis -
#1503
6a928e49fThanks @VenomAV! - Fix Stream.groupAdjacentBy when group spans multiple chunks -
#1500
8c81e5830Thanks @sukovanej! - add Tracer.externalSpan constructor -
#1506
a4fbb7055Thanks @tim-smart! - add Layer.withParentSpan api -
#1507
2397b5548Thanks @tim-smart! - add name getter to YieldableError
2.0.0-next.47
Minor Changes
- #1495
01c479f0cThanks @mikearnaldi! - Support rendezvous-like behaviour in Queue.bounded
2.0.0-next.46
Minor Changes
-
#1483
e68453bf4Thanks @mikearnaldi! - Include stack in Data.Error/Data.TaggedError -
#1483
e68453bf4Thanks @mikearnaldi! - Include Error module in Data
Patch Changes
-
#1487
bd1748406Thanks @fubhy! - Added bigint math functions forabs,sqrt,lcmandgcd -
#1491
6ff77385cThanks @tim-smart! - fix Layer.withSpan optional args -
#1492
471b5172bThanks @tim-smart! - ensure more failures are annotated with spans
2.0.0-next.45
Patch Changes
-
#1465
10a8fb9feThanks @tim-smart! - add incremental only counters -
#1472
1c56aa9c1Thanks @tim-smart! - switch to build-utils prepare-v1 -
#1480
c31de5410Thanks @tim-smart! - refactor Effectable and Streamable public api -
#1463
8932e9b26Thanks @gcanti! - Rename Hub to PubSub, closes #1462 -
#1455
c3e99ce56Thanks @TylorS! - add Streamable for creating custom Streams -
#1465
10a8fb9feThanks @tim-smart! - add bigint counter & gauge metrics -
#1473
6c967c9bcThanks @tim-smart! - support records in Effect.tagMetrics -
#1480
c31de5410Thanks @tim-smart! - expose Effect prototype objects in Effectable module
2.0.0-next.44
Patch Changes
- #1469
5a217ac18Thanks @mikearnaldi! - Fix yield loop
2.0.0-next.43
Patch Changes
- #1467
7e258a9c1Thanks @mikearnaldi! - Attempt at resolving TS issue with module discovery
2.0.0-next.42
Patch Changes
-
#1466
31c4068feThanks @tim-smart! - ensure all fiber refs are wrapped with globalValue -
#1459
e8fb7f73bThanks @fubhy! - Fix binding issue in timeout module -
#1466
31c4068feThanks @tim-smart! - fix comparisons by reference -
#1461
90210ba28Thanks @gcanti! - Error: rename Tagged to TaggedClass (to align with the naming convention in the Data module)
2.0.0-next.41
Patch Changes
- #1456
4bc30e5ffThanks @tim-smart! - re-add types field to exports in package.json
2.0.0-next.40
Patch Changes
-
#1454
0a9afd299Thanks @tim-smart! - add Layer.withSpan -
#1451
44ea13d9cThanks @fubhy! - Move types export condition to the top
2.0.0-next.39
Patch Changes
-
#1446
3f6f23149Thanks @mikearnaldi! - Add sideEffects to package json -
#1450
713337c7cThanks @fubhy! - Hotfix type condition in package.json exports -
#1449
8f74d671dThanks @tim-smart! - add preserveModules patch for preconstruct
2.0.0-next.38
Patch Changes
- #1442
c5e4a2390Thanks @tim-smart! - add top level exports from Function
2.0.0-next.37
Minor Changes
-
#1434
61b95aefeThanks @mikearnaldi! - Switch on _op to allow for yieldable tagged errors -
#1434
61b95aefeThanks @mikearnaldi! - Unify ecosystem packages
Patch Changes
-
#1434
61b95aefeThanks @mikearnaldi! - add Error module for creating error classes -
#1434
61b95aefeThanks @mikearnaldi! - add Effectable module for creating custom Effect’s
2.0.0-next.36
Patch Changes
2.0.0-next.35
Patch Changes
-
#1435
f197821b7Thanks @tim-smart! - update dependencies -
#1432
b8b11c5a5Thanks @gcanti! - move FiberRefsPatch from FiberRefs module to its own module
2.0.0-next.34
Patch Changes
2.0.0-next.33
Patch Changes
- #1426
92af22066Thanks @tim-smart! - expose /data GlobalValue & Types modules
2.0.0-next.32
Patch Changes
2.0.0-next.31
Patch Changes
- #1419
543dfb495Thanks @tim-smart! - update dependencies
2.0.0-next.30
Patch Changes
- #1416
f464fb494Thanks @tim-smart! - update dependencies
2.0.0-next.29
Patch Changes
- #1412
93f4c9f9aThanks @tim-smart! - update peer deps
2.0.0-next.28
Patch Changes
- #1410
a8ffb5fb9Thanks @tim-smart! - update @effect/match
2.0.0-next.27
Patch Changes
- #1408
a6b9f4f01Thanks @tim-smart! - update /match
2.0.0-next.26
Patch Changes
- #1404
6441df29eThanks @tim-smart! - expose Console module
2.0.0-next.25
Patch Changes
- #1402
0844367c5Thanks @tim-smart! - use dependencies + peerDependencies for packages
2.0.0-next.24
Minor Changes
- #1395
aecaeb88cThanks @tim-smart! - update dependencies
Patch Changes
-
#1395
aecaeb88cThanks @tim-smart! - switch to using peerDependencies -
#1397
9ffd45ba7Thanks @tim-smart! - switch to @effect/build-utils and @effect/eslint-plugin
2.0.0-next.23
Patch Changes
- #1393
db1f1e677Thanks @tim-smart! - update packages
2.0.0-next.22
Patch Changes
- #1389
02703a5c7Thanks @tim-smart! - update packages
2.0.0-next.21
Patch Changes
- #1387
83401b13aThanks @tim-smart! - update /stream
2.0.0-next.20
Patch Changes
- #1385
a53697e15Thanks @tim-smart! - add /stm, /stream and /match
2.0.0-next.19
Minor Changes
- #1383
d9c229a87Thanks @tim-smart! - update /io and /data
2.0.0-next.18
Patch Changes
- #1381
bf5ebae41Thanks @tim-smart! - update /io
2.0.0-next.17
Patch Changes
- #1379
2e9b54d03Thanks @tim-smart! - update /io and /data
2.0.0-next.16
Patch Changes
2.0.0-next.15
Patch Changes
2.0.0-next.14
Patch Changes
2.0.0-next.13
Patch Changes
- #1360
fef698b15Thanks @mikearnaldi! - Elect selected modules to main export
2.0.0-next.12
Patch Changes
- #1358
54152d7afThanks @mikearnaldi! - Restructure package
2.0.0-next.11
Patch Changes
- #1356
9fcc559d2Thanks @mikearnaldi! - Update release
2.0.0-next.10
Patch Changes
- #1353
6285a7712Thanks @mikearnaldi! - Update @effect/io
2.0.0-next.9
Patch Changes
-
#1352
5220362c9Thanks @mikearnaldi! - Update dependencies -
#1350
b18068ebeThanks @mikearnaldi! - Update @effect/io and remove LogLevel isolation
2.0.0-next.8
Patch Changes
- #1348
a789742bdThanks @mikearnaldi! - Isolate LogLevel export
2.0.0-next.7
Patch Changes
- #1346
2d6cdbc2aThanks @mikearnaldi! - Add Logger extensions
2.0.0-next.6
Patch Changes
- #1344
aa550d9f9Thanks @mikearnaldi! - Update @effect/io
2.0.0-next.5
Patch Changes
- #1342
2c8c14f7cThanks @mikearnaldi! - Update @effect/io
2.0.0-next.4
Patch Changes
-
#1339
aabfb1d0fThanks @mikearnaldi! - Update @effect/io -
#1341
a2b0eca61Thanks @mikearnaldi! - Add Optic Re-Export
2.0.0-next.3
Patch Changes
- #1337
4f805f5c1Thanks @mikearnaldi! - Update docs
2.0.0-next.2
Patch Changes
-
#1333
b3dac7e1bThanks @mikearnaldi! - Update repo in package.json -
#1335
3c7d4f2e4Thanks @mikearnaldi! - Update docs
2.0.0-next.1
Patch Changes
- #1330
75780dea1Thanks @mikearnaldi! - Update dependencies
2.0.0-next.0
Major Changes
- #1321
315a3ab42Thanks @mikearnaldi! - Bootstrap Ecosystem Package
Patch Changes
-
#1329
b015fdac5Thanks @mikearnaldi! - Update to @effect/io@0.0.9 -
#1324
74fa4086eThanks @mikearnaldi! - Isolate Debug -
#1326
edc131f65Thanks @mikearnaldi! - Add Remaining Effect Re-Exports -
#1323
7f57f59deThanks @mikearnaldi! - Add fp-ts/data re-exports -
#1325
52dacbf72Thanks @mikearnaldi! - Add fp-ts/core Re-Exports