Minor Changes
-
#3541
fcfa6ee
Thanks @Schniz! - addLogger.withLeveledConsole
In browsers and different platforms,
console.error
renders differently thanconsole.info
. This helps to distinguish between different levels of logging.Logger.withLeveledConsole
takes any logger and calls the respectiveConsole
method based on the log level. For instance,Effect.logError
will callConsole.error
andEffect.logInfo
will callConsole.info
.To use it, you can replace the default logger with a
Logger.withLeveledConsole
logger: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
bb9931b
Thanks @KhraksMamtsov! - MadeRef
,SynchronizedRed
andSubscriptionRef
a subtype ofEffect
-
#3541
5798f76
Thanks @tim-smart! - add Semaphore.withPermitsIfAvailableYou can now use
Semaphore.withPermitsIfAvailable
to 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.Some
with the result of the Effect if the permits were
available, orNone
if they were not.import { Effect } from "effect" Effect.gen(function* () { const semaphore = yield* Effect.makeSemaphore(1) semaphore.withPermitsIfAvailable(1)(Effect.void) })
-
#3541
5f0bfa1
Thanks @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
812a4e8
Thanks @tim-smart! - add Logger.prettyLoggerDefault, to prevent duplicate pretty loggers -
#3541
273565e
Thanks @tim-smart! - add Effect.makeLatch, for creating a simple async latchimport { Effect } from "effect" Effect.gen(function* () { // Create a latch, starting in the closed state const latch = yield* Effect.makeLatch(false) // Fork a fiber that logs "open sesame" when the latch is opened const fiber = yield* Effect.log("open sesame").pipe( latch.whenOpen, Effect.fork ) // Open the latch yield* latch.open yield* fiber.await })
-
#3541
569a801
Thanks @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.take
function.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
aa1fa53
Thanks @vinassefranche! - Add Number.round -
#3541
02f6b06
Thanks @fubhy! - Add additionalDuration
conversion apisDuration.toMinutes
Duration.toHours
Duration.toDays
Duration.toWeeks
-
#3541
12b893e
Thanks @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
bbad27e
Thanks @dilame! - addStream.share
apiThe
Stream.share
api 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
adf7d7a
Thanks @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 mailbox yield* mailbox.offer(1) yield* mailbox.offer(2) yield* mailbox.offerAll([3, 4, 5]) // take messages from the mailbox const [messages, done] = yield* mailbox.takeAll assert.deepStrictEqual(Chunk.toReadonlyArray(messages), [1, 2, 3, 4, 5]) assert.strictEqual(done, false) // signal that the mailbox is done yield* mailbox.end const [messages2, done2] = yield* mailbox.takeAll assert.deepStrictEqual(messages2, Chunk.empty()) assert.strictEqual(done2, true) // signal that the mailbox is failed yield* mailbox.fail("boom") })
-
#3541
007289a
Thanks @mikearnaldi! - Cache some fiber references in the runtime to optimize reading in hot-paths -
#3541
42a8f99
Thanks @fubhy! - AddedRcMap.keys
andMutableHashMap.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
eebfd29
Thanks @fubhy! - AddDuration.parts
apiconst parts = Duration.parts(Duration.sum("5 minutes", "20 seconds")) assert.equal(parts.minutes, 5) assert.equal(parts.seconds, 20)
-
#3541
040703d
Thanks @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 })