github Effect-TS/effect effect@3.8.0

latest releases: @effect/typeclass@0.29.14, @effect/vitest@0.13.14, @effect/sql-sqlite-wasm@0.20.5...
one month ago

Minor Changes

  • #3541 fcfa6ee Thanks @Schniz! - add Logger.withLeveledConsole

    In browsers and different platforms, console.error renders differently than console.info. This helps to distinguish between different levels of logging. Logger.withLeveledConsole takes any logger and calls the respective Console method based on the log level. For instance, Effect.logError will call Console.error and Effect.logInfo will call Console.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! - Made Ref, SynchronizedRed and SubscriptionRef a subtype of Effect

  • #3541 5798f76 Thanks @tim-smart! - add Semaphore.withPermitsIfAvailable

    You 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, or None 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! - The Deferred<A> is now a subtype of Effect<A>. This change simplifies handling of deferred values, removing the need for explicit call Deffer.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 latch

    import { 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> and Queue<A> is subtype of Effect<A>. This means that now it can be used as an Effect, and when called, it will automatically extract and return an item from the queue, without having to explicitly use the Queue.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 additional Duration conversion apis

    • Duration.toMinutes
    • Duration.toHours
    • Duration.toDays
    • Duration.toWeeks
  • #3541 12b893e Thanks @KhraksMamtsov! - The Fiber<A, E> is now a subtype of Effect<A, E>. This change removes the need for explicit call Fiber.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! - add Stream.share api

    The 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 signals

    import { 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! - Added RcMap.keys and MutableHashMap.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! - Add Duration.parts api

    const parts = Duration.parts(Duration.sum("5 minutes", "20 seconds"))
    assert.equal(parts.minutes, 5)
    assert.equal(parts.seconds, 20)
  • #3541 040703d Thanks @KhraksMamtsov! - The FiberRef<A> is now a subtype of Effect<A>. This change simplifies handling of deferred values, removing the need for explicit call FiberRef.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
    })

Don't miss a new effect release

NewReleases is sending notifications on new releases.