Merge commit '36c66dd290d3ce6eb1ccd310d0c658d4a32bb8eb' as 'repos/effect'
This commit is contained in:
163
repos/effect/migration/cause.md
Normal file
163
repos/effect/migration/cause.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# Cause: Flattened Structure
|
||||
|
||||
In v3, `Cause<E>` was a recursive tree with six variants:
|
||||
|
||||
```
|
||||
Empty | Fail<E> | Die | Interrupt | Sequential<E> | Parallel<E>
|
||||
```
|
||||
|
||||
The `Sequential` and `Parallel` variants composed causes into a tree to
|
||||
represent errors from finalizers or concurrent operations.
|
||||
|
||||
In v4, `Cause<E>` has been flattened to a simple wrapper around an array of
|
||||
`Reason` values:
|
||||
|
||||
```ts
|
||||
interface Cause<E> {
|
||||
readonly reasons: ReadonlyArray<Reason<E>>
|
||||
}
|
||||
|
||||
type Reason<E> = Fail<E> | Die | Interrupt
|
||||
```
|
||||
|
||||
There are only three reason variants — `Fail`, `Die`, and `Interrupt`. The
|
||||
`Empty`, `Sequential`, and `Parallel` variants have been removed. An empty
|
||||
cause is represented by an empty `reasons` array. Multiple failures (from
|
||||
concurrent or sequential composition) are collected into a flat array.
|
||||
|
||||
## Accessing Reasons
|
||||
|
||||
**v3** — pattern match on the recursive tree structure:
|
||||
|
||||
```ts
|
||||
import { Cause } from "effect"
|
||||
|
||||
const handle = (cause: Cause.Cause<string>) => {
|
||||
switch (cause._tag) {
|
||||
case "Fail":
|
||||
return cause.error
|
||||
case "Die":
|
||||
return cause.defect
|
||||
case "Empty":
|
||||
return undefined
|
||||
case "Sequential":
|
||||
return handle(cause.left)
|
||||
case "Parallel":
|
||||
return handle(cause.left)
|
||||
case "Interrupt":
|
||||
return cause.fiberId
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**v4** — iterate over the flat `reasons` array:
|
||||
|
||||
```ts
|
||||
import { Cause } from "effect"
|
||||
|
||||
const handle = (cause: Cause.Cause<string>) => {
|
||||
for (const reason of cause.reasons) {
|
||||
switch (reason._tag) {
|
||||
case "Fail":
|
||||
return reason.error
|
||||
case "Die":
|
||||
return reason.defect
|
||||
case "Interrupt":
|
||||
return reason.fiberId
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Reason Guards
|
||||
|
||||
The v3 type-level guards (`isFailType`, `isDieType`, `isInterruptType`, etc.)
|
||||
have been replaced by reason-level guards:
|
||||
|
||||
| v3 | v4 |
|
||||
| ------------------------------- | --------------------------------- |
|
||||
| `Cause.isEmptyType(cause)` | `cause.reasons.length === 0` |
|
||||
| `Cause.isFailType(cause)` | `Cause.isFailReason(reason)` |
|
||||
| `Cause.isDieType(cause)` | `Cause.isDieReason(reason)` |
|
||||
| `Cause.isInterruptType(cause)` | `Cause.isInterruptReason(reason)` |
|
||||
| `Cause.isSequentialType(cause)` | Removed |
|
||||
| `Cause.isParallelType(cause)` | Removed |
|
||||
|
||||
## Cause-Level Predicates
|
||||
|
||||
| v3 | v4 |
|
||||
| -------------------------------- | -------------------------------- |
|
||||
| `Cause.isFailure(cause)` | `Cause.hasFails(cause)` |
|
||||
| `Cause.isDie(cause)` | `Cause.hasDies(cause)` |
|
||||
| `Cause.isInterrupted(cause)` | `Cause.hasInterrupts(cause)` |
|
||||
| `Cause.isInterruptedOnly(cause)` | `Cause.hasInterruptsOnly(cause)` |
|
||||
|
||||
## Constructors
|
||||
|
||||
| v3 | v4 |
|
||||
| ------------------------------- | ---------------------------- |
|
||||
| `Cause.empty` | `Cause.empty` |
|
||||
| `Cause.fail(error)` | `Cause.fail(error)` |
|
||||
| `Cause.die(defect)` | `Cause.die(defect)` |
|
||||
| `Cause.interrupt(fiberId)` | `Cause.interrupt(fiberId)` |
|
||||
| `Cause.sequential(left, right)` | `Cause.combine(left, right)` |
|
||||
| `Cause.parallel(left, right)` | `Cause.combine(left, right)` |
|
||||
|
||||
In v4, `Cause.combine` concatenates the `reasons` arrays of two causes. The
|
||||
distinction between sequential and parallel composition is no longer
|
||||
represented in the data structure.
|
||||
|
||||
## Extractors
|
||||
|
||||
| v3 | v4 |
|
||||
| ------------------------------ | ------------------------------------------ |
|
||||
| `Cause.failureOption(cause)` | `Cause.findErrorOption(cause)` |
|
||||
| `Cause.failureOrCause(cause)` | `Cause.findError(cause)` |
|
||||
| `Cause.dieOption(cause)` | `Cause.findDefect(cause)` |
|
||||
| `Cause.interruptOption(cause)` | `Cause.findInterrupt(cause)` |
|
||||
| `Cause.failures(cause)` | `cause.reasons.filter(Cause.isFailReason)` |
|
||||
| `Cause.defects(cause)` | `cause.reasons.filter(Cause.isDieReason)` |
|
||||
| `Cause.interruptors(cause)` | `Cause.interruptors(cause)` |
|
||||
|
||||
Note: `findError` and `findDefect` return `Result.Result` instead of `Option`.
|
||||
Use `findErrorOption` for the `Option`-based variant.
|
||||
|
||||
## Error Classes
|
||||
|
||||
All `*Exception` classes have been renamed to `*Error`:
|
||||
|
||||
| v3 | v4 |
|
||||
| -------------------------------------- | ----------------------------- |
|
||||
| `Cause.NoSuchElementException` | `Cause.NoSuchElementError` |
|
||||
| `Cause.TimeoutException` | `Cause.TimeoutError` |
|
||||
| `Cause.IllegalArgumentException` | `Cause.IllegalArgumentError` |
|
||||
| `Cause.ExceededCapacityException` | `Cause.ExceededCapacityError` |
|
||||
| `Cause.UnknownException` | `Cause.UnknownError` |
|
||||
| `Cause.RuntimeException` | Removed |
|
||||
| `Cause.InterruptedException` | Removed |
|
||||
| `Cause.InvalidPubSubCapacityException` | Removed |
|
||||
|
||||
The corresponding guards follow the same pattern:
|
||||
|
||||
| v3 | v4 |
|
||||
| -------------------------------------- | ---------------------------------- |
|
||||
| `Cause.isNoSuchElementException(u)` | `Cause.isNoSuchElementError(u)` |
|
||||
| `Cause.isTimeoutException(u)` | `Cause.isTimeoutError(u)` |
|
||||
| `Cause.isIllegalArgumentException(u)` | `Cause.isIllegalArgumentError(u)` |
|
||||
| `Cause.isExceededCapacityException(u)` | `Cause.isExceededCapacityError(u)` |
|
||||
| `Cause.isUnknownException(u)` | `Cause.isUnknownError(u)` |
|
||||
|
||||
## New in v4
|
||||
|
||||
- **`Cause.fromReasons(reasons)`** — construct a `Cause` from an array of
|
||||
`Reason` values.
|
||||
- **`Cause.makeFailReason(error)`**, **`Cause.makeDieReason(defect)`**,
|
||||
**`Cause.makeInterruptReason(fiberId)`** — construct individual `Reason`
|
||||
values.
|
||||
- **`Cause.annotate(cause, annotations)`** — attach annotations to a `Cause`.
|
||||
- **`Cause.findFail(cause)`**, **`Cause.findDie(cause)`**,
|
||||
**`Cause.findInterrupt(cause)`** — extract specific reason types using
|
||||
the `Result` module.
|
||||
- **`Cause.filterInterruptors(cause)`** — extract interrupting fiber IDs as
|
||||
a `Result`.
|
||||
- **`Cause.Done`** — a graceful completion signal for queues and streams.
|
||||
72
repos/effect/migration/equality.md
Normal file
72
repos/effect/migration/equality.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Equality
|
||||
|
||||
## Structural Equality by Default
|
||||
|
||||
In v3, `Equal.equals` used **reference equality** for plain objects and arrays.
|
||||
Structural comparison was only available inside a `structuralRegion`, which
|
||||
temporarily enabled deep comparison. Outside a structural region, two distinct
|
||||
objects with identical contents were not considered equal:
|
||||
|
||||
```ts
|
||||
// v3
|
||||
import { Equal } from "effect"
|
||||
|
||||
Equal.equals({ a: 1 }, { a: 1 }) // false — reference equality
|
||||
Equal.equals([1, 2], [1, 2]) // false — reference equality
|
||||
```
|
||||
|
||||
In v4, `Equal.equals` uses **structural equality** by default. Plain objects,
|
||||
arrays, `Map`s, `Set`s, `Date`s, and `RegExp`s are compared by value without
|
||||
opting in:
|
||||
|
||||
```ts
|
||||
// v4
|
||||
import { Equal } from "effect"
|
||||
|
||||
Equal.equals({ a: 1 }, { a: 1 }) // true
|
||||
Equal.equals([1, [2, 3]], [1, [2, 3]]) // true
|
||||
Equal.equals(new Map([["a", 1]]), new Map([["a", 1]])) // true
|
||||
Equal.equals(new Set([1, 2]), new Set([1, 2])) // true
|
||||
```
|
||||
|
||||
Objects that implement the `Equal` interface continue to use their custom
|
||||
equality logic, same as v3.
|
||||
|
||||
## Opting Out: `byReference`
|
||||
|
||||
If you need reference equality for a specific object, v4 provides
|
||||
`Equal.byReference` and `Equal.byReferenceUnsafe`:
|
||||
|
||||
```ts
|
||||
import { Equal } from "effect"
|
||||
|
||||
const obj = Equal.byReference({ a: 1 })
|
||||
Equal.equals(obj, { a: 1 }) // false — reference equality
|
||||
```
|
||||
|
||||
- **`byReference(obj)`** — creates a `Proxy` that uses reference equality,
|
||||
leaving the original object unchanged.
|
||||
- **`byReferenceUnsafe(obj)`** — marks the object itself for reference
|
||||
equality without creating a proxy. More performant but permanently changes
|
||||
how the object is compared.
|
||||
|
||||
## `NaN` Equality
|
||||
|
||||
In v3, `Equal.equals(NaN, NaN)` returned `false` (following IEEE 754).
|
||||
In v4, `NaN` is considered equal to `NaN`:
|
||||
|
||||
```ts
|
||||
Equal.equals(NaN, NaN) // v3: false, v4: true
|
||||
```
|
||||
|
||||
## `equivalence` → `asEquivalence`
|
||||
|
||||
The function that wraps `equals` as an `Equivalence` has been renamed:
|
||||
|
||||
```ts
|
||||
// v3
|
||||
Equal.equivalence<number>()
|
||||
|
||||
// v4
|
||||
Equal.asEquivalence<number>()
|
||||
```
|
||||
106
repos/effect/migration/error-handling.md
Normal file
106
repos/effect/migration/error-handling.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Error Handling: `catch*` Renamings
|
||||
|
||||
The `catch` combinators on `Effect` have been renamed in v4. The general
|
||||
pattern: `catchAll*` is shortened to `catch*`, and the `catchSome*` family is
|
||||
replaced by `catchFilter` / `catchCauseFilter`.
|
||||
|
||||
## Renamings
|
||||
|
||||
| v3 | v4 |
|
||||
| ------------------------ | ------------------------------ |
|
||||
| `Effect.catchAll` | `Effect.catch` |
|
||||
| `Effect.catchAllCause` | `Effect.catchCause` |
|
||||
| `Effect.catchAllDefect` | `Effect.catchDefect` |
|
||||
| `Effect.catchTag` | `Effect.catchTag` (unchanged) |
|
||||
| `Effect.catchTags` | `Effect.catchTags` (unchanged) |
|
||||
| `Effect.catchIf` | `Effect.catchIf` (unchanged) |
|
||||
| `Effect.catchSome` | `Effect.catchFilter` |
|
||||
| `Effect.catchSomeCause` | `Effect.catchCauseFilter` |
|
||||
| `Effect.catchSomeDefect` | Removed |
|
||||
|
||||
## `Effect.catchAll` → `Effect.catch`
|
||||
|
||||
**v3**
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
const program = Effect.fail("error").pipe(
|
||||
Effect.catchAll((error) => Effect.succeed(`recovered: ${error}`))
|
||||
)
|
||||
```
|
||||
|
||||
**v4**
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
const program = Effect.fail("error").pipe(
|
||||
Effect.catch((error) => Effect.succeed(`recovered: ${error}`))
|
||||
)
|
||||
```
|
||||
|
||||
## `Effect.catchAllCause` → `Effect.catchCause`
|
||||
|
||||
**v3**
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
const program = Effect.die("defect").pipe(
|
||||
Effect.catchAllCause((cause) => Effect.succeed("recovered"))
|
||||
)
|
||||
```
|
||||
|
||||
**v4**
|
||||
|
||||
```ts
|
||||
import { Cause, Effect } from "effect"
|
||||
|
||||
const program = Effect.die("defect").pipe(
|
||||
Effect.catchCause((cause) => Effect.succeed("recovered"))
|
||||
)
|
||||
```
|
||||
|
||||
## `Effect.catchSome` → `Effect.catchFilter`
|
||||
|
||||
In v3, `catchSome` took a function returning `Option<Effect>`. In v4,
|
||||
`catchFilter` uses the `Filter` module instead.
|
||||
|
||||
**v3**
|
||||
|
||||
```ts
|
||||
import { Effect, Option } from "effect"
|
||||
|
||||
const program = Effect.fail(42).pipe(
|
||||
Effect.catchSome((error) =>
|
||||
error === 42
|
||||
? Option.some(Effect.succeed("caught"))
|
||||
: Option.none()
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
**v4**
|
||||
|
||||
```ts
|
||||
import { Effect, Filter } from "effect"
|
||||
|
||||
const program = Effect.fail(42).pipe(
|
||||
Effect.catchFilter(
|
||||
Filter.fromPredicate((error: number) => error === 42),
|
||||
(error) => Effect.succeed("caught")
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
## New in v4
|
||||
|
||||
- **`Effect.catchReason(errorTag, reasonTag, handler)`** — catches a specific
|
||||
`reason` within a tagged error without removing the parent error from the
|
||||
error channel. Useful for handling nested error causes (e.g. an `AiError`
|
||||
with a `reason: RateLimitError | QuotaExceededError`).
|
||||
- **`Effect.catchReasons(errorTag, cases)`** — like `catchReason` but handles
|
||||
multiple reason tags at once via an object of handlers.
|
||||
- **`Effect.catchEager(handler)`** — an optimization variant of `catch` that
|
||||
evaluates synchronous recovery effects immediately.
|
||||
74
repos/effect/migration/fiber-keep-alive.md
Normal file
74
repos/effect/migration/fiber-keep-alive.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Fiber Keep-Alive: Automatic Process Lifetime Management
|
||||
|
||||
In v3, the core `effect` runtime did **not** keep the Node.js process alive while
|
||||
fibers were suspended on certain asynchronous operations. If a fiber was waiting on
|
||||
something like `Deferred.await` and there was no other work scheduled on the
|
||||
event loop, the process would exit immediately — the fiber's suspension did not
|
||||
register as pending work from Node.js's perspective.
|
||||
|
||||
The only way to prevent this was to use `runMain` from `@effect/platform-node`
|
||||
(or `@effect/platform-bun`), which installed a long-lived `setInterval` timer
|
||||
to hold the process open until the root fiber completed.
|
||||
|
||||
In v4, **the keep-alive mechanism is built into the core runtime**.
|
||||
|
||||
## The Problem in v3
|
||||
|
||||
Consider the following program:
|
||||
|
||||
```ts
|
||||
import { Deferred, Effect } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const deferred = yield* Deferred.make<string>()
|
||||
|
||||
yield* Deferred.await(deferred)
|
||||
})
|
||||
|
||||
Effect.runPromise(program)
|
||||
```
|
||||
|
||||
In v3, when the main fiber reached `yield* Deferred.await(deferred)`, it suspended
|
||||
while waiting for the worker fiber to complete the deferred. However, from the
|
||||
JavaScript runtime's perspective, the event loop had no more work to do. Thus,
|
||||
the process would exit.
|
||||
|
||||
The workaround was to use `runMain` from the platform package, which installs
|
||||
a timer that holds the process open until the root fiber completes:
|
||||
|
||||
```ts
|
||||
import { NodeRuntime } from "@effect/platform-node"
|
||||
|
||||
NodeRuntime.runMain(program)
|
||||
```
|
||||
|
||||
## What Changed in v4
|
||||
|
||||
In v4, the Effect fiber runtime automatically manages a reference-counted
|
||||
keep-alive timer.
|
||||
|
||||
This means the following program works in v4 **without** `runMain`:
|
||||
|
||||
```ts
|
||||
import { Deferred, Effect, Fiber } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const deferred = yield* Deferred.make<string>()
|
||||
|
||||
// The process stays alive while waiting — no runMain needed
|
||||
yield* Deferred.await(deferred)
|
||||
})
|
||||
|
||||
Effect.runPromise(program)
|
||||
```
|
||||
|
||||
## `runMain` Is Still Recommended
|
||||
|
||||
Even though the core runtime now handles keep-alive, `runMain` from the platform
|
||||
packages is still the recommended way to run Effect programs. It provides:
|
||||
|
||||
- **Signal handling** — listens for `SIGINT` / `SIGTERM` and interrupts the
|
||||
root fiber gracefully.
|
||||
- **Exit code management** — calls `process.exit(code)` when the program fails
|
||||
or receives a signal.
|
||||
- **Error reporting** — reports unhandled errors to the console.
|
||||
109
repos/effect/migration/fiberref.md
Normal file
109
repos/effect/migration/fiberref.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# FiberRef: `FiberRef` → `Context.Reference`
|
||||
|
||||
In v4, `FiberRef`, `FiberRefs`, `FiberRefsPatch`, and `Differ` have been removed.
|
||||
Fiber-local state is now handled by `Context.Reference` — the same mechanism
|
||||
used for services with default values.
|
||||
|
||||
## Built-in References
|
||||
|
||||
v3's built-in `FiberRef` values are now `Context.Reference` values exported
|
||||
from `References` and related modules.
|
||||
|
||||
| v3 FiberRef | v4 Reference |
|
||||
| ----------------------------------- | ---------------------------------- |
|
||||
| `FiberRef.currentConcurrency` | `References.CurrentConcurrency` |
|
||||
| `FiberRef.currentLogLevel` | `References.CurrentLogLevel` |
|
||||
| `FiberRef.currentMinimumLogLevel` | `References.MinimumLogLevel` |
|
||||
| `FiberRef.currentLogAnnotations` | `References.CurrentLogAnnotations` |
|
||||
| `FiberRef.currentLogSpan` | `References.CurrentLogSpans` |
|
||||
| `FiberRef.currentScheduler` | `References.Scheduler` |
|
||||
| `FiberRef.currentMaxOpsBeforeYield` | `References.MaxOpsBeforeYield` |
|
||||
| `FiberRef.currentTracerEnabled` | `References.TracerEnabled` |
|
||||
| `FiberRef.unhandledErrorLogLevel` | `References.UnhandledLogLevel` |
|
||||
|
||||
## Reading References
|
||||
|
||||
In v3, `FiberRef.get` retrieved the current value. In v4, references are
|
||||
services — `yield*` them directly.
|
||||
|
||||
**v3**
|
||||
|
||||
```ts
|
||||
import { Effect, FiberRef } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const level = yield* FiberRef.get(FiberRef.currentLogLevel)
|
||||
console.log(level)
|
||||
})
|
||||
```
|
||||
|
||||
**v4**
|
||||
|
||||
```ts
|
||||
import { Effect, References } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const level = yield* References.CurrentLogLevel
|
||||
console.log(level) // "Info" (default)
|
||||
})
|
||||
```
|
||||
|
||||
## Scoped Updates (`Effect.locally` → `Effect.provideService`)
|
||||
|
||||
v3's `Effect.locally` set a `FiberRef` value for the duration of an effect. In
|
||||
v4, use `Effect.provideService` with the reference.
|
||||
|
||||
**v3**
|
||||
|
||||
```ts
|
||||
import { Effect, FiberRef, LogLevel } from "effect"
|
||||
|
||||
const program = Effect.locally(
|
||||
myEffect,
|
||||
FiberRef.currentLogLevel,
|
||||
LogLevel.Debug
|
||||
)
|
||||
```
|
||||
|
||||
**v4**
|
||||
|
||||
```ts
|
||||
import { Effect, References } from "effect"
|
||||
|
||||
const program = Effect.provideService(
|
||||
myEffect,
|
||||
References.CurrentLogLevel,
|
||||
"Debug"
|
||||
)
|
||||
```
|
||||
|
||||
## Writing References
|
||||
|
||||
v3's `FiberRef.set` mutated the current fiber's ref value. In v4, references are
|
||||
set via `Effect.provideService`, which scopes the value to the provided effect.
|
||||
|
||||
**v3**
|
||||
|
||||
```ts
|
||||
import { Effect, FiberRef } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
yield* FiberRef.set(FiberRef.currentConcurrency, 10)
|
||||
// subsequent code sees concurrency = 10
|
||||
})
|
||||
```
|
||||
|
||||
**v4**
|
||||
|
||||
```ts
|
||||
import { Effect, References } from "effect"
|
||||
|
||||
const program = Effect.provideService(
|
||||
Effect.gen(function*() {
|
||||
const concurrency = yield* References.CurrentConcurrency
|
||||
console.log(concurrency) // 10
|
||||
}),
|
||||
References.CurrentConcurrency,
|
||||
10
|
||||
)
|
||||
```
|
||||
94
repos/effect/migration/forking.md
Normal file
94
repos/effect/migration/forking.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Forking: Renamed Combinators and New Options
|
||||
|
||||
The `fork*` family of combinators has been renamed in v4 for clarity, and all
|
||||
variants now accept an options object for controlling fiber startup behavior.
|
||||
|
||||
## Renamings
|
||||
|
||||
| v3 | v4 | Description |
|
||||
| ----------------------------- | ------------------- | -------------------------------------------- |
|
||||
| `Effect.fork` | `Effect.forkChild` | Fork as a child of the current fiber |
|
||||
| `Effect.forkDaemon` | `Effect.forkDetach` | Fork detached from parent lifecycle |
|
||||
| `Effect.forkScoped` | `Effect.forkScoped` | Fork tied to the current `Scope` (unchanged) |
|
||||
| `Effect.forkIn` | `Effect.forkIn` | Fork in a specific `Scope` (unchanged) |
|
||||
| `Effect.forkAll` | — | Removed |
|
||||
| `Effect.forkWithErrorHandler` | — | Removed |
|
||||
|
||||
## `Effect.fork` → `Effect.forkChild`
|
||||
|
||||
**v3**
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
const fiber = Effect.fork(myEffect)
|
||||
```
|
||||
|
||||
**v4**
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
const fiber = Effect.forkChild(myEffect)
|
||||
```
|
||||
|
||||
## `Effect.forkDaemon` → `Effect.forkDetach`
|
||||
|
||||
**v3**
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
const fiber = Effect.forkDaemon(myEffect)
|
||||
```
|
||||
|
||||
**v4**
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
const fiber = Effect.forkDetach(myEffect)
|
||||
```
|
||||
|
||||
## Fork Options
|
||||
|
||||
In v4, `forkChild`, `forkDetach`, `forkScoped`, and `forkIn` all accept an
|
||||
optional options object with the following fields:
|
||||
|
||||
```ts
|
||||
{
|
||||
readonly startImmediately?: boolean | undefined
|
||||
readonly uninterruptible?: boolean | "inherit" | undefined
|
||||
}
|
||||
```
|
||||
|
||||
- **`startImmediately`** — When `true`, the forked fiber begins executing
|
||||
immediately rather than being deferred. Defaults to `undefined` (deferred).
|
||||
- **`uninterruptible`** — Controls whether the forked fiber can be interrupted.
|
||||
`true` makes it uninterruptible, `"inherit"` inherits the parent's
|
||||
interruptibility, and `undefined` uses the default behavior.
|
||||
|
||||
**Usage as data-last (curried)**
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
const fiber = myEffect.pipe(
|
||||
Effect.forkChild({ startImmediately: true })
|
||||
)
|
||||
```
|
||||
|
||||
**Usage as data-first**
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
const fiber = Effect.forkChild(myEffect, { startImmediately: true })
|
||||
```
|
||||
|
||||
## Removed Combinators
|
||||
|
||||
**`Effect.forkAll`** and **`Effect.forkWithErrorHandler`** have been removed in
|
||||
v4. For `forkAll`, fork effects individually with `forkChild` or use
|
||||
higher-level concurrency combinators. For error handling on forked fibers,
|
||||
observe the fiber's result via `Fiber.join` or `Fiber.await`.
|
||||
32
repos/effect/migration/generators.md
Normal file
32
repos/effect/migration/generators.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Generators
|
||||
|
||||
## `Effect.gen`: Passing `this`
|
||||
|
||||
In v3, you could pass a `self` value directly as the first argument to
|
||||
`Effect.gen`. In v4, `self` must be wrapped in an options object.
|
||||
|
||||
**v3**
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
class MyService {
|
||||
readonly local = 1
|
||||
compute = Effect.gen(this, function*() {
|
||||
return yield* Effect.succeed(this.local + 1)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
**v4**
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
class MyService {
|
||||
readonly local = 1
|
||||
compute = Effect.gen({ self: this }, function*() {
|
||||
return yield* Effect.succeed(this.local + 1)
|
||||
})
|
||||
}
|
||||
```
|
||||
98
repos/effect/migration/layer-memoization.md
Normal file
98
repos/effect/migration/layer-memoization.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Layer Memoization
|
||||
|
||||
In v3, each call to `Effect.provide` created its own memoization scope. Layers
|
||||
were memoized / deduplicated within a single `Effect.provide` call, but would
|
||||
**not** be shared across separate calls — so two `Effect.provide` calls with
|
||||
overlapping layers would silently build those layers twice.
|
||||
|
||||
In v4, the underlying `MemoMap` data structure which facilitates memoization of
|
||||
`Layer`s is shared between `Effect.provide` calls (unless explicitly disabled
|
||||
via the `{ local: true }` option). Thus, layers are automatically memoized /
|
||||
deduplicated across `Effect.provide` calls.
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
import { Console, Context, Effect, Layer } from "effect"
|
||||
|
||||
const MyService = Context.Service<{ readonly value: string }>("MyService")
|
||||
|
||||
const MyServiceLayer = Layer.effect(
|
||||
MyService,
|
||||
Effect.gen(function*() {
|
||||
yield* Console.log("Building MyService")
|
||||
return { value: "hello" }
|
||||
})
|
||||
)
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const a = yield* MyService
|
||||
return a.value
|
||||
})
|
||||
|
||||
// Same layer provided twice in separate provide calls
|
||||
const main = program.pipe(
|
||||
Effect.provide(MyServiceLayer),
|
||||
Effect.provide(MyServiceLayer)
|
||||
)
|
||||
|
||||
// Effect v3: "Building MyService" is logged TWICE
|
||||
// Effect v4: "Building MyService" is logged ONCE
|
||||
Effect.runPromise(main)
|
||||
```
|
||||
|
||||
## Prefer Layer Composition Over Multipl Provides
|
||||
|
||||
Even though v4 memoizes across `provide` calls, **composing layers before
|
||||
providing is still the recommended pattern**. Layer composition makes your
|
||||
dependency graph explicit and lets you see the full structure in one place:
|
||||
|
||||
```ts
|
||||
// Preferred — provide once
|
||||
const main = program.pipe(Effect.provide(MyServiceLayer))
|
||||
```
|
||||
|
||||
The auto-memoization feature is a safety net to avoid the footguns associated
|
||||
with multiple `Effect.provide` calls present in v3. It is **NOT** a substitute
|
||||
for proper layer composition.
|
||||
|
||||
## Opting Out of Shared Memoization
|
||||
|
||||
There are cases where you **want** a layer to be built fresh — for example,
|
||||
test isolation or creating independent resource pools. v4 provides two
|
||||
mechanisms:
|
||||
|
||||
### `Layer.fresh`
|
||||
|
||||
Wraps a layer so it always builds with a fresh memo map, bypassing the shared
|
||||
cache. This existed in v3 as well.
|
||||
|
||||
```ts
|
||||
import { Effect, Layer } from "effect"
|
||||
|
||||
const main = program.pipe(
|
||||
Effect.provide(MyServiceLayer),
|
||||
Effect.provide(Layer.fresh(MyServiceLayer))
|
||||
)
|
||||
// "Building MyService" is logged TWICE — fresh bypasses the shared cache
|
||||
```
|
||||
|
||||
### `Effect.provide` with `{ local: true }`
|
||||
|
||||
New in v4. Builds the provided layer with a **local memo map** instead of the
|
||||
fiber's shared one. The layer and all its sublayers are built from scratch and
|
||||
are not shared with other `provide` calls.
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
const main = program.pipe(
|
||||
Effect.provide(MyServiceLayer),
|
||||
Effect.provide(MyServiceLayer, { local: true })
|
||||
)
|
||||
// "Building MyService" is logged TWICE — local creates its own memo map
|
||||
```
|
||||
|
||||
Use `local: true` when you need an entire layer subtree to be isolated — for
|
||||
example, when providing layers in a test harness where each test should get
|
||||
independent resources.
|
||||
88
repos/effect/migration/runtime.md
Normal file
88
repos/effect/migration/runtime.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Runtime: `Runtime<R>` Removed
|
||||
|
||||
In v3, `Runtime<R>` bundled a `Context<R>`, `RuntimeFlags`, and `FiberRefs`
|
||||
into a single value used to execute effects:
|
||||
|
||||
```ts
|
||||
// v3
|
||||
interface Runtime<in R> {
|
||||
readonly context: Context.Context<R>
|
||||
readonly runtimeFlags: RuntimeFlags
|
||||
readonly fiberRefs: FiberRefs
|
||||
}
|
||||
```
|
||||
|
||||
In v4, this type no longer exists and you can use `Context<R>` instead.
|
||||
Run functions live directly on `Effect`, and the `Runtime` module is reduced to
|
||||
process lifecycle utilities.
|
||||
|
||||
## `Runtime.runFork(runtime)` -> `Effect.runForkWith(services)`
|
||||
|
||||
In v3, running an effect with dependencies usually meant pulling the current
|
||||
runtime from `Effect.runtime<R>()` and calling `Runtime.runFork(runtime)` inside
|
||||
the main effect.
|
||||
|
||||
**v3**
|
||||
|
||||
```ts
|
||||
import { Context, Effect, Runtime } from "effect"
|
||||
|
||||
class Logger extends Context.Tag("Logger")<Logger, {
|
||||
readonly log: (message: string) => void
|
||||
}>() {}
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const logger = yield* Logger
|
||||
logger.log("Hello from Logger")
|
||||
})
|
||||
|
||||
const main = Effect.gen(function*() {
|
||||
const runtime = yield* Effect.runtime<Logger>()
|
||||
return Runtime.runFork(runtime)(program)
|
||||
}).pipe(
|
||||
Effect.provideService(Logger, {
|
||||
log: (message) => console.log(message)
|
||||
})
|
||||
)
|
||||
|
||||
const fiber = Effect.runFork(main)
|
||||
```
|
||||
|
||||
In v4, use the same pattern with `Effect.context<R>()`, then run with
|
||||
`Effect.runForkWith(services)`:
|
||||
|
||||
**v4**
|
||||
|
||||
```ts
|
||||
import { Context, Effect } from "effect"
|
||||
|
||||
class Logger extends Context.Service<Logger, {
|
||||
readonly log: (message: string) => void
|
||||
}>()("Logger") {}
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const logger = yield* Logger
|
||||
logger.log("Hello from Logger")
|
||||
})
|
||||
|
||||
const main = Effect.gen(function*() {
|
||||
const services = yield* Effect.context<Logger>()
|
||||
return Effect.runForkWith(services)(program)
|
||||
}).pipe(
|
||||
Effect.provideContext(Context.make(Logger, {
|
||||
log: (message) => console.log(message)
|
||||
}))
|
||||
)
|
||||
|
||||
const fiber = Effect.runFork(main)
|
||||
```
|
||||
|
||||
If your effect has no service requirements, use `Effect.runFork(effect)`.
|
||||
|
||||
## `Runtime` Module Contents
|
||||
|
||||
The `Runtime` module now only contains:
|
||||
|
||||
- `Teardown` — interface for handling process exit
|
||||
- `defaultTeardown` — default teardown implementation
|
||||
- `makeRunMain` — creates platform-specific main runners
|
||||
1071
repos/effect/migration/schema.md
Normal file
1071
repos/effect/migration/schema.md
Normal file
File diff suppressed because it is too large
Load Diff
50
repos/effect/migration/scope.md
Normal file
50
repos/effect/migration/scope.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Scope
|
||||
|
||||
## `Scope.extend` → `Scope.provide`
|
||||
|
||||
`Scope.extend` has been renamed to `Scope.provide` in v4. The behavior is
|
||||
identical: it provides a `Scope` to an effect that requires one, removing
|
||||
`Scope` from the effect's requirements without closing the scope when the
|
||||
effect completes.
|
||||
|
||||
The new name better reflects the operation — you are providing a service (the
|
||||
`Scope`) to an effect, consistent with how other services are provided in
|
||||
Effect.
|
||||
|
||||
**v3**
|
||||
|
||||
```ts
|
||||
import { Effect, Scope } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const scope = yield* Scope.make()
|
||||
yield* Scope.extend(myEffect, scope)
|
||||
})
|
||||
```
|
||||
|
||||
**v4**
|
||||
|
||||
```ts
|
||||
import { Effect, Scope } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const scope = yield* Scope.make()
|
||||
yield* Scope.provide(scope)(myEffect)
|
||||
})
|
||||
```
|
||||
|
||||
Both data-first and data-last (curried) forms are supported:
|
||||
|
||||
```ts
|
||||
// data-first
|
||||
Scope.provide(myEffect, scope)
|
||||
|
||||
// data-last (curried)
|
||||
myEffect.pipe(Scope.provide(scope))
|
||||
```
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| v3 | v4 |
|
||||
| -------------- | --------------- |
|
||||
| `Scope.extend` | `Scope.provide` |
|
||||
235
repos/effect/migration/services.md
Normal file
235
repos/effect/migration/services.md
Normal file
@@ -0,0 +1,235 @@
|
||||
# Services: `Context.Tag` → `Context.Service`
|
||||
|
||||
In v3, services were defined using `Context.Tag`, `Context.GenericTag`,
|
||||
`Effect.Tag`, or `Effect.Service`. In v4, all of these have been replaced by
|
||||
`Context.Service`.
|
||||
|
||||
The underlying runtime data structure is a typed map from service identifiers to
|
||||
their implementations.
|
||||
|
||||
## Defining Services
|
||||
|
||||
**v3: `Context.GenericTag`**
|
||||
|
||||
```ts
|
||||
import { Context } from "effect"
|
||||
|
||||
interface Database {
|
||||
readonly query: (sql: string) => string
|
||||
}
|
||||
|
||||
const Database = Context.GenericTag<Database>("Database")
|
||||
```
|
||||
|
||||
**v4: `Context.Service` (function syntax)**
|
||||
|
||||
```ts
|
||||
import { Context } from "effect"
|
||||
|
||||
interface Database {
|
||||
readonly query: (sql: string) => string
|
||||
}
|
||||
|
||||
const Database = Context.Service<Database>("Database")
|
||||
```
|
||||
|
||||
## Class-Based Services
|
||||
|
||||
**v3: `Context.Tag` class syntax**
|
||||
|
||||
```ts
|
||||
import { Context } from "effect"
|
||||
|
||||
class Database extends Context.Tag("Database")<Database, {
|
||||
readonly query: (sql: string) => string
|
||||
}>() {}
|
||||
```
|
||||
|
||||
**v4: `Context.Service` class syntax**
|
||||
|
||||
```ts
|
||||
import { Context } from "effect"
|
||||
|
||||
class Database extends Context.Service<Database, {
|
||||
readonly query: (sql: string) => string
|
||||
}>()("Database") {}
|
||||
```
|
||||
|
||||
Note the difference in argument order: in v3, the identifier string is passed to
|
||||
`Context.Tag(id)` before the type parameters. In v4, the type parameters come
|
||||
first via `Context.Service<Self, Shape>()` and the identifier string is
|
||||
passed to the returned constructor `(id)`.
|
||||
|
||||
## `Effect.Tag` Accessors → `Context.Service` with `use`
|
||||
|
||||
v3's `Effect.Tag` provided proxy access to service methods as static properties
|
||||
on the tag class (accessors). This allowed calling service methods directly
|
||||
without first yielding the service:
|
||||
|
||||
```ts
|
||||
// v3 — static accessor proxy
|
||||
const program = Notifications.notify("hello")
|
||||
```
|
||||
|
||||
This pattern had significant limitations. The proxy was implemented via mapped
|
||||
types over the service shape, which meant **generic methods lost their type
|
||||
parameters**. A service method like `get<T>(key: string): Effect<T>` would
|
||||
have its generic erased when accessed through the proxy, collapsing to
|
||||
`get(key: string): Effect<unknown>`. For the same reason, overloaded signatures
|
||||
were not preserved.
|
||||
|
||||
In v4, accessors are removed. The most direct replacement is `Service.use`,
|
||||
which receives the service instance and runs a callback:
|
||||
|
||||
**v3**
|
||||
|
||||
```ts
|
||||
import { Effect } from "effect"
|
||||
|
||||
class Notifications extends Effect.Tag("Notifications")<Notifications, {
|
||||
readonly notify: (message: string) => Effect.Effect<void>
|
||||
}>() {}
|
||||
|
||||
// Static proxy access
|
||||
const program = Notifications.notify("hello")
|
||||
```
|
||||
|
||||
**v4 — `use`**
|
||||
|
||||
```ts
|
||||
import { Context, Effect } from "effect"
|
||||
|
||||
class Notifications extends Context.Service<Notifications, {
|
||||
readonly notify: (message: string) => Effect.Effect<void>
|
||||
}>()("Notifications") {}
|
||||
|
||||
// use: access the service and call a method in one step
|
||||
const program = Notifications.use((n) => n.notify("hello"))
|
||||
```
|
||||
|
||||
`use` takes an effectful callback `(service: Shape) => Effect<A, E, R>` and
|
||||
returns an `Effect<A, E, R | Identifier>`. `useSync` takes a pure callback
|
||||
`(service: Shape) => A` and returns an `Effect<A, never, Identifier>`. Both
|
||||
return Effects — `useSync` just allows the accessor function itself to be
|
||||
synchronous:
|
||||
|
||||
```ts
|
||||
// ┌─── Effect<void, never, Notifications>
|
||||
// ▼
|
||||
const program = Notifications.use((n) => n.notify("hello"))
|
||||
|
||||
// ┌─── Effect<number, never, Config>
|
||||
// ▼
|
||||
const port = Config.useSync((c) => c.port)
|
||||
```
|
||||
|
||||
**Prefer `yield*` over `use` in most cases.** While `use` is a convenient
|
||||
one-liner, it makes it easy to accidentally leak service dependencies into
|
||||
return values. When you call `use`, the service is available inside the
|
||||
callback but the dependency is not visible at the call site — making it harder
|
||||
to track which services your code depends on. Using `yield*` in a generator
|
||||
makes dependencies explicit and keeps service access co-located with the rest
|
||||
of your effect logic:
|
||||
|
||||
```ts
|
||||
const program = Effect.gen(function*() {
|
||||
const notifications = yield* Notifications
|
||||
yield* notifications.notify("hello")
|
||||
yield* notifications.notify("world")
|
||||
})
|
||||
```
|
||||
|
||||
## `Effect.Service` → `Context.Service` with `make`
|
||||
|
||||
v3's `Effect.Service` allowed defining a service with an effectful constructor
|
||||
and dependencies inline. In v4, use `Context.Service` with a `make` option.
|
||||
|
||||
**v3**
|
||||
|
||||
In v3, `Effect.Service` automatically generated a `.Default` layer from the
|
||||
provided constructor, and wired `dependencies` into it:
|
||||
|
||||
```ts
|
||||
import { Effect, Layer } from "effect"
|
||||
|
||||
class Logger extends Effect.Service<Logger>()("Logger", {
|
||||
effect: Effect.gen(function*() {
|
||||
const config = yield* Config
|
||||
return { log: (msg: string) => Effect.log(`[${config.prefix}] ${msg}`) }
|
||||
}),
|
||||
dependencies: [Config.Default]
|
||||
}) {}
|
||||
|
||||
// Logger.Default is auto-generated: Layer<Logger, never, never>
|
||||
// (dependencies are already wired in)
|
||||
const program = Effect.gen(function*() {
|
||||
const logger = yield* Logger
|
||||
yield* logger.log("hello")
|
||||
}).pipe(Effect.provide(Logger.Default))
|
||||
```
|
||||
|
||||
**v4**
|
||||
|
||||
In v4, `Context.Service` with `make` stores the constructor effect on the
|
||||
class but does **not** auto-generate a layer. Define layers explicitly using
|
||||
`Layer.effect`:
|
||||
|
||||
```ts
|
||||
import { Context, Effect, Layer } from "effect"
|
||||
|
||||
class Logger extends Context.Service<Logger>()("Logger", {
|
||||
make: Effect.gen(function*() {
|
||||
const config = yield* Config
|
||||
return { log: (msg: string) => Effect.log(`[${config.prefix}] ${msg}`) }
|
||||
})
|
||||
}) {
|
||||
// Build the layer yourself from the make effect
|
||||
static readonly layer = Layer.effect(this, this.make).pipe(
|
||||
Layer.provide(Config.layer)
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The `dependencies` option no longer exists. Wire dependencies via
|
||||
`Layer.provide` as shown above.
|
||||
|
||||
Note: v4 adopts the convention of naming layers with `layer` (e.g.
|
||||
`Logger.layer`) instead of v3's `Default` or `Live`. Use `layer`
|
||||
for the primary layer and descriptive suffixes for variants (e.g.
|
||||
`layerTest`, `layerConfig`).
|
||||
|
||||
## References (Services with Defaults)
|
||||
|
||||
**v3: `Context.Reference`**
|
||||
|
||||
```ts
|
||||
import { Context } from "effect"
|
||||
|
||||
class LogLevel extends Context.Reference<LogLevel>()("LogLevel", {
|
||||
defaultValue: () => "info" as const
|
||||
}) {}
|
||||
```
|
||||
|
||||
**v4: `Context.Reference`**
|
||||
|
||||
```ts
|
||||
import { Context } from "effect"
|
||||
|
||||
const LogLevel = Context.Reference<"info" | "warn" | "error">("LogLevel", {
|
||||
defaultValue: () => "info" as const
|
||||
})
|
||||
```
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| v3 | v4 |
|
||||
| ------------------------------------- | --------------------------------------- |
|
||||
| `Context.GenericTag<T>(id)` | `Context.Service<T>(id)` |
|
||||
| `Context.Tag(id)<Self, Shape>()` | `Context.Service<Self, Shape>()(id)` |
|
||||
| `Effect.Tag(id)<Self, Shape>()` | `Context.Service<Self, Shape>()(id)` |
|
||||
| `Effect.Service<Self>()(id, opts)` | `Context.Service<Self>()(id, { make })` |
|
||||
| `Context.Reference<Self>()(id, opts)` | `Context.Reference<T>(id, opts)` |
|
||||
| `Context.make(tag, impl)` | `Context.make(tag, impl)` |
|
||||
| `Context.get(ctx, tag)` | `Context.get(map, tag)` |
|
||||
| `Context.add(ctx, tag, impl)` | `Context.add(map, tag, impl)` |
|
||||
| `Context.mergeAll(...)` | `Context.mergeAll(...)` |
|
||||
421
repos/effect/migration/v3-to-v4.md
Normal file
421
repos/effect/migration/v3-to-v4.md
Normal file
@@ -0,0 +1,421 @@
|
||||
# v3 to v4 Import and API Rename Maps
|
||||
|
||||
Mapped modules: 290
|
||||
No counterpart: 43
|
||||
API renames: 53
|
||||
|
||||
This file is intended for migration agents. It contains user-facing import
|
||||
specifier mappings and API rename mappings.
|
||||
|
||||
Use the import map when rewriting import declarations. Use the API renames when
|
||||
rewriting renamed symbols.
|
||||
|
||||
## Import Map
|
||||
|
||||
Each line is `v3 import -> v4 direct module import`. When a grouped v4 barrel
|
||||
exists, the suggested barrel import is shown in parentheses.
|
||||
|
||||
```text
|
||||
@effect/platform/ChannelSchema -> effect/ChannelSchema (barrel: effect)
|
||||
@effect/platform/FileSystem -> effect/FileSystem (barrel: effect)
|
||||
effect/JSONSchema -> effect/JsonSchema (barrel: effect)
|
||||
@effect/platform/Path -> effect/Path (barrel: effect)
|
||||
@effect/platform/Error -> effect/PlatformError (barrel: effect)
|
||||
effect/Either -> effect/Result (barrel: effect)
|
||||
@effect/platform/Terminal -> effect/Terminal (barrel: effect)
|
||||
effect/TDeferred -> effect/TxDeferred (barrel: effect)
|
||||
effect/TMap -> effect/TxHashMap (barrel: effect)
|
||||
effect/TSet -> effect/TxHashSet (barrel: effect)
|
||||
effect/TPriorityQueue -> effect/TxPriorityQueue (barrel: effect)
|
||||
effect/TPubSub -> effect/TxPubSub (barrel: effect)
|
||||
effect/TQueue -> effect/TxQueue (barrel: effect)
|
||||
effect/TReentrantLock -> effect/TxReentrantLock (barrel: effect)
|
||||
effect/TRef -> effect/TxRef (barrel: effect)
|
||||
effect/TSemaphore -> effect/TxSemaphore (barrel: effect)
|
||||
effect/TSubscriptionRef -> effect/TxSubscriptionRef (barrel: effect)
|
||||
effect/FastCheck -> effect/testing/FastCheck (barrel: effect/testing)
|
||||
effect/TestClock -> effect/testing/TestClock (barrel: effect/testing)
|
||||
@effect/cli/Args -> effect/unstable/cli/Argument (barrel: effect/unstable/cli)
|
||||
@effect/cli/ValidationError -> effect/unstable/cli/CliError (barrel: effect/unstable/cli)
|
||||
@effect/cli/Command -> effect/unstable/cli/Command (barrel: effect/unstable/cli)
|
||||
@effect/cli/CommandDescriptor -> effect/unstable/cli/Completions (barrel: effect/unstable/cli)
|
||||
@effect/cli/Options -> effect/unstable/cli/Flag (barrel: effect/unstable/cli)
|
||||
@effect/cli/BuiltInOptions -> effect/unstable/cli/GlobalFlag (barrel: effect/unstable/cli)
|
||||
@effect/cli/HelpDoc -> effect/unstable/cli/HelpDoc (barrel: effect/unstable/cli)
|
||||
@effect/cli/Primitive -> effect/unstable/cli/Primitive (barrel: effect/unstable/cli)
|
||||
@effect/cli/Prompt -> effect/unstable/cli/Prompt (barrel: effect/unstable/cli)
|
||||
@effect/cluster/ClusterCron -> effect/unstable/cluster/ClusterCron (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/ClusterError -> effect/unstable/cluster/ClusterError (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/ClusterMetrics -> effect/unstable/cluster/ClusterMetrics (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/ClusterSchema -> effect/unstable/cluster/ClusterSchema (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/ClusterWorkflowEngine -> effect/unstable/cluster/ClusterWorkflowEngine (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/DeliverAt -> effect/unstable/cluster/DeliverAt (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/Entity -> effect/unstable/cluster/Entity (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/EntityAddress -> effect/unstable/cluster/EntityAddress (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/EntityId -> effect/unstable/cluster/EntityId (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/EntityProxy -> effect/unstable/cluster/EntityProxy (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/EntityProxyServer -> effect/unstable/cluster/EntityProxyServer (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/EntityResource -> effect/unstable/cluster/EntityResource (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/EntityType -> effect/unstable/cluster/EntityType (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/Envelope -> effect/unstable/cluster/Envelope (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/HttpRunner -> effect/unstable/cluster/HttpRunner (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/K8sHttpClient -> effect/unstable/cluster/K8sHttpClient (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/MachineId -> effect/unstable/cluster/MachineId (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/Message -> effect/unstable/cluster/Message (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/MessageStorage -> effect/unstable/cluster/MessageStorage (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/Reply -> effect/unstable/cluster/Reply (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/Runner -> effect/unstable/cluster/Runner (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/RunnerAddress -> effect/unstable/cluster/RunnerAddress (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/RunnerHealth -> effect/unstable/cluster/RunnerHealth (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/RunnerServer -> effect/unstable/cluster/RunnerServer (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/RunnerStorage -> effect/unstable/cluster/RunnerStorage (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/Runners -> effect/unstable/cluster/Runners (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/ShardId -> effect/unstable/cluster/ShardId (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/Sharding -> effect/unstable/cluster/Sharding (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/ShardingConfig -> effect/unstable/cluster/ShardingConfig (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/ShardingRegistrationEvent -> effect/unstable/cluster/ShardingRegistrationEvent (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/SingleRunner -> effect/unstable/cluster/SingleRunner (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/Singleton -> effect/unstable/cluster/Singleton (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/SingletonAddress -> effect/unstable/cluster/SingletonAddress (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/Snowflake -> effect/unstable/cluster/Snowflake (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/SocketRunner -> effect/unstable/cluster/SocketRunner (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/SqlMessageStorage -> effect/unstable/cluster/SqlMessageStorage (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/SqlRunnerStorage -> effect/unstable/cluster/SqlRunnerStorage (barrel: effect/unstable/cluster)
|
||||
@effect/cluster/TestRunner -> effect/unstable/cluster/TestRunner (barrel: effect/unstable/cluster)
|
||||
@effect/experimental/DevTools -> effect/unstable/devtools/DevTools (barrel: effect/unstable/devtools)
|
||||
@effect/experimental/DevTools/Client -> effect/unstable/devtools/DevToolsClient (barrel: effect/unstable/devtools)
|
||||
@effect/experimental/DevTools/Domain -> effect/unstable/devtools/DevToolsSchema (barrel: effect/unstable/devtools)
|
||||
@effect/experimental/DevTools/Server -> effect/unstable/devtools/DevToolsServer (barrel: effect/unstable/devtools)
|
||||
@effect/platform/MsgPack -> effect/unstable/encoding/Msgpack (barrel: effect/unstable/encoding)
|
||||
@effect/platform/Ndjson -> effect/unstable/encoding/Ndjson (barrel: effect/unstable/encoding)
|
||||
@effect/experimental/Sse -> effect/unstable/encoding/Sse (barrel: effect/unstable/encoding)
|
||||
@effect/ai/AiError -> effect/unstable/ai/AiError (barrel: effect/unstable/ai)
|
||||
@effect/ai/Chat -> effect/unstable/ai/Chat (barrel: effect/unstable/ai)
|
||||
@effect/ai/EmbeddingModel -> effect/unstable/ai/EmbeddingModel (barrel: effect/unstable/ai)
|
||||
@effect/ai/IdGenerator -> effect/unstable/ai/IdGenerator (barrel: effect/unstable/ai)
|
||||
@effect/ai/LanguageModel -> effect/unstable/ai/LanguageModel (barrel: effect/unstable/ai)
|
||||
@effect/ai/McpSchema -> effect/unstable/ai/McpSchema (barrel: effect/unstable/ai)
|
||||
@effect/ai/McpServer -> effect/unstable/ai/McpServer (barrel: effect/unstable/ai)
|
||||
@effect/ai/Model -> effect/unstable/ai/Model (barrel: effect/unstable/ai)
|
||||
@effect/ai/Prompt -> effect/unstable/ai/Prompt (barrel: effect/unstable/ai)
|
||||
@effect/ai/Response -> effect/unstable/ai/Response (barrel: effect/unstable/ai)
|
||||
@effect/ai/Telemetry -> effect/unstable/ai/Telemetry (barrel: effect/unstable/ai)
|
||||
@effect/ai/Tokenizer -> effect/unstable/ai/Tokenizer (barrel: effect/unstable/ai)
|
||||
@effect/ai/Tool -> effect/unstable/ai/Tool (barrel: effect/unstable/ai)
|
||||
@effect/ai/Toolkit -> effect/unstable/ai/Toolkit (barrel: effect/unstable/ai)
|
||||
@effect/experimental/Event -> effect/unstable/eventlog/Event (barrel: effect/unstable/eventlog)
|
||||
@effect/experimental/EventGroup -> effect/unstable/eventlog/EventGroup (barrel: effect/unstable/eventlog)
|
||||
@effect/experimental/EventJournal -> effect/unstable/eventlog/EventJournal (barrel: effect/unstable/eventlog)
|
||||
@effect/experimental/EventLog -> effect/unstable/eventlog/EventLog (barrel: effect/unstable/eventlog)
|
||||
@effect/experimental/EventLogEncryption -> effect/unstable/eventlog/EventLogEncryption (barrel: effect/unstable/eventlog)
|
||||
@effect/experimental/EventLogRemote -> effect/unstable/eventlog/EventLogMessage (barrel: effect/unstable/eventlog)
|
||||
@effect/experimental/EventLogRemote -> effect/unstable/eventlog/EventLogRemote (barrel: effect/unstable/eventlog)
|
||||
@effect/experimental/EventLogServer -> effect/unstable/eventlog/EventLogServer (barrel: effect/unstable/eventlog)
|
||||
@effect/experimental/EventLogServer -> effect/unstable/eventlog/EventLogServerEncrypted (barrel: effect/unstable/eventlog)
|
||||
@effect/sql/SqlEventJournal -> effect/unstable/eventlog/SqlEventJournal (barrel: effect/unstable/eventlog)
|
||||
@effect/sql/SqlEventLogServer -> effect/unstable/eventlog/SqlEventLogServerEncrypted (barrel: effect/unstable/eventlog)
|
||||
@effect/platform/Cookies -> effect/unstable/http/Cookies (barrel: effect/unstable/http)
|
||||
@effect/platform/Etag -> effect/unstable/http/Etag (barrel: effect/unstable/http)
|
||||
@effect/platform/FetchHttpClient -> effect/unstable/http/FetchHttpClient (barrel: effect/unstable/http)
|
||||
@effect/platform/Headers -> effect/unstable/http/Headers (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpBody -> effect/unstable/http/HttpBody (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpClient -> effect/unstable/http/HttpClient (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpClientError -> effect/unstable/http/HttpClientError (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpClientRequest -> effect/unstable/http/HttpClientRequest (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpClientResponse -> effect/unstable/http/HttpClientResponse (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpApp -> effect/unstable/http/HttpEffect (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpIncomingMessage -> effect/unstable/http/HttpIncomingMessage (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpMethod -> effect/unstable/http/HttpMethod (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpMiddleware -> effect/unstable/http/HttpMiddleware (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpPlatform -> effect/unstable/http/HttpPlatform (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpRouter -> effect/unstable/http/HttpRouter (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpServer -> effect/unstable/http/HttpServer (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpServerError -> effect/unstable/http/HttpServerError (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpServerRequest -> effect/unstable/http/HttpServerRequest (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpServerRespondable -> effect/unstable/http/HttpServerRespondable (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpServerResponse -> effect/unstable/http/HttpServerResponse (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpTraceContext -> effect/unstable/http/HttpTraceContext (barrel: effect/unstable/http)
|
||||
@effect/platform/Multipart -> effect/unstable/http/Multipart (barrel: effect/unstable/http)
|
||||
@effect/platform/Template -> effect/unstable/http/Template (barrel: effect/unstable/http)
|
||||
@effect/platform/Url -> effect/unstable/http/Url (barrel: effect/unstable/http)
|
||||
@effect/platform/UrlParams -> effect/unstable/http/UrlParams (barrel: effect/unstable/http)
|
||||
@effect/platform/HttpApi -> effect/unstable/httpapi/HttpApi (barrel: effect/unstable/httpapi)
|
||||
@effect/platform/HttpApiBuilder -> effect/unstable/httpapi/HttpApiBuilder (barrel: effect/unstable/httpapi)
|
||||
@effect/platform/HttpApiClient -> effect/unstable/httpapi/HttpApiClient (barrel: effect/unstable/httpapi)
|
||||
@effect/platform/HttpApiEndpoint -> effect/unstable/httpapi/HttpApiEndpoint (barrel: effect/unstable/httpapi)
|
||||
@effect/platform/HttpApiError -> effect/unstable/httpapi/HttpApiError (barrel: effect/unstable/httpapi)
|
||||
@effect/platform/HttpApiGroup -> effect/unstable/httpapi/HttpApiGroup (barrel: effect/unstable/httpapi)
|
||||
@effect/platform/HttpApiMiddleware -> effect/unstable/httpapi/HttpApiMiddleware (barrel: effect/unstable/httpapi)
|
||||
@effect/platform/HttpApiScalar -> effect/unstable/httpapi/HttpApiScalar (barrel: effect/unstable/httpapi)
|
||||
@effect/platform/HttpApiSchema -> effect/unstable/httpapi/HttpApiSchema (barrel: effect/unstable/httpapi)
|
||||
@effect/platform/HttpApiSecurity -> effect/unstable/httpapi/HttpApiSecurity (barrel: effect/unstable/httpapi)
|
||||
@effect/platform/HttpApiSwagger -> effect/unstable/httpapi/HttpApiSwagger (barrel: effect/unstable/httpapi)
|
||||
@effect/platform/OpenApi -> effect/unstable/httpapi/OpenApi (barrel: effect/unstable/httpapi)
|
||||
@effect/opentelemetry/Otlp -> effect/unstable/observability/Otlp (barrel: effect/unstable/observability)
|
||||
@effect/opentelemetry/internal/otlpExporter -> effect/unstable/observability/OtlpExporter (barrel: effect/unstable/observability)
|
||||
@effect/opentelemetry/OtlpLogger -> effect/unstable/observability/OtlpLogger (barrel: effect/unstable/observability)
|
||||
@effect/opentelemetry/OtlpMetrics -> effect/unstable/observability/OtlpMetrics (barrel: effect/unstable/observability)
|
||||
@effect/opentelemetry/OtlpResource -> effect/unstable/observability/OtlpResource (barrel: effect/unstable/observability)
|
||||
@effect/opentelemetry/OtlpSerialization -> effect/unstable/observability/OtlpSerialization (barrel: effect/unstable/observability)
|
||||
@effect/opentelemetry/OtlpTracer -> effect/unstable/observability/OtlpTracer (barrel: effect/unstable/observability)
|
||||
@effect/platform/KeyValueStore -> effect/unstable/persistence/KeyValueStore (barrel: effect/unstable/persistence)
|
||||
@effect/experimental/Persistence -> effect/unstable/persistence/Persistable (barrel: effect/unstable/persistence)
|
||||
@effect/experimental/PersistedCache -> effect/unstable/persistence/PersistedCache (barrel: effect/unstable/persistence)
|
||||
@effect/experimental/PersistedQueue -> effect/unstable/persistence/PersistedQueue (barrel: effect/unstable/persistence)
|
||||
@effect/experimental/Persistence -> effect/unstable/persistence/Persistence (barrel: effect/unstable/persistence)
|
||||
@effect/experimental/RateLimiter -> effect/unstable/persistence/RateLimiter (barrel: effect/unstable/persistence)
|
||||
@effect/platform/Command -> effect/unstable/process/ChildProcess (barrel: effect/unstable/process)
|
||||
@effect/platform/CommandExecutor -> effect/unstable/process/ChildProcessSpawner (barrel: effect/unstable/process)
|
||||
@effect/experimental/Reactivity -> effect/unstable/reactivity/Reactivity (barrel: effect/unstable/reactivity)
|
||||
@effect/rpc/Rpc -> effect/unstable/rpc/Rpc (barrel: effect/unstable/rpc)
|
||||
@effect/rpc/RpcClient -> effect/unstable/rpc/RpcClient (barrel: effect/unstable/rpc)
|
||||
@effect/rpc/RpcClientError -> effect/unstable/rpc/RpcClientError (barrel: effect/unstable/rpc)
|
||||
@effect/rpc/RpcGroup -> effect/unstable/rpc/RpcGroup (barrel: effect/unstable/rpc)
|
||||
@effect/rpc/RpcMessage -> effect/unstable/rpc/RpcMessage (barrel: effect/unstable/rpc)
|
||||
@effect/rpc/RpcMiddleware -> effect/unstable/rpc/RpcMiddleware (barrel: effect/unstable/rpc)
|
||||
@effect/rpc/RpcSchema -> effect/unstable/rpc/RpcSchema (barrel: effect/unstable/rpc)
|
||||
@effect/rpc/RpcSerialization -> effect/unstable/rpc/RpcSerialization (barrel: effect/unstable/rpc)
|
||||
@effect/rpc/RpcServer -> effect/unstable/rpc/RpcServer (barrel: effect/unstable/rpc)
|
||||
@effect/rpc/RpcTest -> effect/unstable/rpc/RpcTest (barrel: effect/unstable/rpc)
|
||||
@effect/rpc/RpcWorker -> effect/unstable/rpc/RpcWorker (barrel: effect/unstable/rpc)
|
||||
@effect/sql/Model -> effect/unstable/schema/Model (barrel: effect/unstable/schema)
|
||||
@effect/experimental/VariantSchema -> effect/unstable/schema/VariantSchema (barrel: effect/unstable/schema)
|
||||
@effect/platform/Socket -> effect/unstable/socket/Socket (barrel: effect/unstable/socket)
|
||||
@effect/platform/SocketServer -> effect/unstable/socket/SocketServer (barrel: effect/unstable/socket)
|
||||
@effect/sql/Migrator -> effect/unstable/sql/Migrator (barrel: effect/unstable/sql)
|
||||
@effect/sql/SqlClient -> effect/unstable/sql/SqlClient (barrel: effect/unstable/sql)
|
||||
@effect/sql/SqlConnection -> effect/unstable/sql/SqlConnection (barrel: effect/unstable/sql)
|
||||
@effect/sql/SqlError -> effect/unstable/sql/SqlError (barrel: effect/unstable/sql)
|
||||
@effect/sql/Model -> effect/unstable/sql/SqlModel (barrel: effect/unstable/sql)
|
||||
@effect/sql/SqlResolver -> effect/unstable/sql/SqlResolver (barrel: effect/unstable/sql)
|
||||
@effect/sql/SqlSchema -> effect/unstable/sql/SqlSchema (barrel: effect/unstable/sql)
|
||||
@effect/sql/SqlStream -> effect/unstable/sql/SqlStream (barrel: effect/unstable/sql)
|
||||
@effect/sql/Statement -> effect/unstable/sql/Statement (barrel: effect/unstable/sql)
|
||||
@effect/platform/Transferable -> effect/unstable/workers/Transferable (barrel: effect/unstable/workers)
|
||||
@effect/platform/Worker -> effect/unstable/workers/Worker (barrel: effect/unstable/workers)
|
||||
@effect/platform/WorkerError -> effect/unstable/workers/WorkerError (barrel: effect/unstable/workers)
|
||||
@effect/platform/WorkerRunner -> effect/unstable/workers/WorkerRunner (barrel: effect/unstable/workers)
|
||||
@effect/workflow/Activity -> effect/unstable/workflow/Activity (barrel: effect/unstable/workflow)
|
||||
@effect/workflow/DurableClock -> effect/unstable/workflow/DurableClock (barrel: effect/unstable/workflow)
|
||||
@effect/workflow/DurableDeferred -> effect/unstable/workflow/DurableDeferred (barrel: effect/unstable/workflow)
|
||||
@effect/workflow/DurableQueue -> effect/unstable/workflow/DurableQueue (barrel: effect/unstable/workflow)
|
||||
@effect/workflow/Workflow -> effect/unstable/workflow/Workflow (barrel: effect/unstable/workflow)
|
||||
@effect/workflow/WorkflowEngine -> effect/unstable/workflow/WorkflowEngine (barrel: effect/unstable/workflow)
|
||||
@effect/workflow/WorkflowProxy -> effect/unstable/workflow/WorkflowProxy (barrel: effect/unstable/workflow)
|
||||
@effect/workflow/WorkflowProxyServer -> effect/unstable/workflow/WorkflowProxyServer (barrel: effect/unstable/workflow)
|
||||
effect/Array -> effect/Array (barrel: effect)
|
||||
effect/BigDecimal -> effect/BigDecimal (barrel: effect)
|
||||
effect/BigInt -> effect/BigInt (barrel: effect)
|
||||
effect/Boolean -> effect/Boolean (barrel: effect)
|
||||
effect/Brand -> effect/Brand (barrel: effect)
|
||||
effect/Cache -> effect/Cache (barrel: effect)
|
||||
effect/Cause -> effect/Cause (barrel: effect)
|
||||
effect/Channel -> effect/Channel (barrel: effect)
|
||||
effect/Chunk -> effect/Chunk (barrel: effect)
|
||||
effect/Clock -> effect/Clock (barrel: effect)
|
||||
@effect/typeclass/Semigroup -> effect/Combiner (barrel: effect)
|
||||
effect/Config -> effect/Config (barrel: effect)
|
||||
effect/ConfigProvider -> effect/ConfigProvider (barrel: effect)
|
||||
effect/Console -> effect/Console (barrel: effect)
|
||||
effect/Context -> effect/Context (barrel: effect)
|
||||
effect/Cron -> effect/Cron (barrel: effect)
|
||||
effect/Data -> effect/Data (barrel: effect)
|
||||
effect/DateTime -> effect/DateTime (barrel: effect)
|
||||
effect/Deferred -> effect/Deferred (barrel: effect)
|
||||
effect/Differ -> effect/Differ (barrel: effect)
|
||||
effect/Duration -> effect/Duration (barrel: effect)
|
||||
effect/Effect -> effect/Effect (barrel: effect)
|
||||
effect/Effectable -> effect/Effectable (barrel: effect)
|
||||
effect/Encoding -> effect/Encoding (barrel: effect)
|
||||
effect/Equal -> effect/Equal (barrel: effect)
|
||||
effect/Equivalence -> effect/Equivalence (barrel: effect)
|
||||
effect/ExecutionPlan -> effect/ExecutionPlan (barrel: effect)
|
||||
effect/Exit -> effect/Exit (barrel: effect)
|
||||
effect/Fiber -> effect/Fiber (barrel: effect)
|
||||
effect/FiberHandle -> effect/FiberHandle (barrel: effect)
|
||||
effect/FiberMap -> effect/FiberMap (barrel: effect)
|
||||
effect/FiberSet -> effect/FiberSet (barrel: effect)
|
||||
effect/Inspectable -> effect/Formatter (barrel: effect)
|
||||
effect/Function -> effect/Function (barrel: effect)
|
||||
effect/Graph -> effect/Graph (barrel: effect)
|
||||
effect/HKT -> effect/HKT (barrel: effect)
|
||||
effect/Hash -> effect/Hash (barrel: effect)
|
||||
effect/HashMap -> effect/HashMap (barrel: effect)
|
||||
effect/HashRing -> effect/HashRing (barrel: effect)
|
||||
effect/HashSet -> effect/HashSet (barrel: effect)
|
||||
effect/Inspectable -> effect/Inspectable (barrel: effect)
|
||||
effect/Iterable -> effect/Iterable (barrel: effect)
|
||||
effect/Layer -> effect/Layer (barrel: effect)
|
||||
effect/LayerMap -> effect/LayerMap (barrel: effect)
|
||||
effect/LogLevel -> effect/LogLevel (barrel: effect)
|
||||
effect/Logger -> effect/Logger (barrel: effect)
|
||||
effect/ManagedRuntime -> effect/ManagedRuntime (barrel: effect)
|
||||
effect/Match -> effect/Match (barrel: effect)
|
||||
effect/Metric -> effect/Metric (barrel: effect)
|
||||
effect/MutableHashMap -> effect/MutableHashMap (barrel: effect)
|
||||
effect/MutableHashSet -> effect/MutableHashSet (barrel: effect)
|
||||
effect/MutableList -> effect/MutableList (barrel: effect)
|
||||
effect/MutableRef -> effect/MutableRef (barrel: effect)
|
||||
effect/NonEmptyIterable -> effect/NonEmptyIterable (barrel: effect)
|
||||
effect/Number -> effect/Number (barrel: effect)
|
||||
effect/Option -> effect/Option (barrel: effect)
|
||||
effect/Order -> effect/Order (barrel: effect)
|
||||
effect/Ordering -> effect/Ordering (barrel: effect)
|
||||
effect/PartitionedSemaphore -> effect/PartitionedSemaphore (barrel: effect)
|
||||
effect/Pipeable -> effect/Pipeable (barrel: effect)
|
||||
effect/Pool -> effect/Pool (barrel: effect)
|
||||
effect/Predicate -> effect/Predicate (barrel: effect)
|
||||
effect/PrimaryKey -> effect/PrimaryKey (barrel: effect)
|
||||
effect/PubSub -> effect/PubSub (barrel: effect)
|
||||
effect/Queue -> effect/Queue (barrel: effect)
|
||||
effect/Random -> effect/Random (barrel: effect)
|
||||
effect/RcMap -> effect/RcMap (barrel: effect)
|
||||
effect/RcRef -> effect/RcRef (barrel: effect)
|
||||
effect/Record -> effect/Record (barrel: effect)
|
||||
effect/Inspectable -> effect/Redactable (barrel: effect)
|
||||
effect/Redacted -> effect/Redacted (barrel: effect)
|
||||
@effect/typeclass/Monoid -> effect/Reducer (barrel: effect)
|
||||
effect/Ref -> effect/Ref (barrel: effect)
|
||||
effect/FiberRef -> effect/References (barrel: effect)
|
||||
effect/RegExp -> effect/RegExp (barrel: effect)
|
||||
effect/Request -> effect/Request (barrel: effect)
|
||||
effect/RequestResolver -> effect/RequestResolver (barrel: effect)
|
||||
effect/Resource -> effect/Resource (barrel: effect)
|
||||
effect/Runtime -> effect/Runtime (barrel: effect)
|
||||
effect/Schedule -> effect/Schedule (barrel: effect)
|
||||
effect/Scheduler -> effect/Scheduler (barrel: effect)
|
||||
effect/Schema -> effect/Schema (barrel: effect)
|
||||
effect/SchemaAST -> effect/SchemaAST (barrel: effect)
|
||||
effect/ParseResult -> effect/SchemaIssue (barrel: effect)
|
||||
effect/ParseResult -> effect/SchemaParser (barrel: effect)
|
||||
effect/Schema -> effect/SchemaTransformation (barrel: effect)
|
||||
effect/Scope -> effect/Scope (barrel: effect)
|
||||
effect/ScopedCache -> effect/ScopedCache (barrel: effect)
|
||||
effect/ScopedRef -> effect/ScopedRef (barrel: effect)
|
||||
effect/Sink -> effect/Sink (barrel: effect)
|
||||
effect/Stream -> effect/Stream (barrel: effect)
|
||||
effect/String -> effect/String (barrel: effect)
|
||||
effect/Struct -> effect/Struct (barrel: effect)
|
||||
effect/SubscriptionRef -> effect/SubscriptionRef (barrel: effect)
|
||||
effect/Symbol -> effect/Symbol (barrel: effect)
|
||||
effect/SynchronizedRef -> effect/SynchronizedRef (barrel: effect)
|
||||
effect/Take -> effect/Take (barrel: effect)
|
||||
effect/Tracer -> effect/Tracer (barrel: effect)
|
||||
effect/Trie -> effect/Trie (barrel: effect)
|
||||
effect/Tuple -> effect/Tuple (barrel: effect)
|
||||
effect/Types -> effect/Types (barrel: effect)
|
||||
effect/Unify -> effect/Unify (barrel: effect)
|
||||
effect/Utils -> effect/Utils (barrel: effect)
|
||||
```
|
||||
|
||||
## No Counterpart Imports
|
||||
|
||||
These v4 modules did not have a mapped v3 module. Treat them as v4-only unless a
|
||||
more specific migration guide says otherwise.
|
||||
|
||||
```text
|
||||
effect/ErrorReporter (barrel: effect)
|
||||
effect/Filter (barrel: effect)
|
||||
effect/JsonPatch (barrel: effect)
|
||||
effect/JsonPointer (barrel: effect)
|
||||
effect/Latch (barrel: effect)
|
||||
effect/Newtype (barrel: effect)
|
||||
effect/Optic (barrel: effect)
|
||||
effect/Pull (barrel: effect)
|
||||
effect/SchemaGetter (barrel: effect)
|
||||
effect/SchemaRepresentation (barrel: effect)
|
||||
effect/SchemaUtils (barrel: effect)
|
||||
effect/Semaphore (barrel: effect)
|
||||
effect/Stdio (barrel: effect)
|
||||
effect/TxChunk (barrel: effect)
|
||||
effect/UndefinedOr (barrel: effect)
|
||||
effect/testing/TestConsole (barrel: effect/testing)
|
||||
effect/testing/TestSchema (barrel: effect/testing)
|
||||
effect/unstable/ai/AnthropicStructuredOutput (barrel: effect/unstable/ai)
|
||||
effect/unstable/ai/OpenAiStructuredOutput (barrel: effect/unstable/ai)
|
||||
effect/unstable/ai/ResponseIdTracker (barrel: effect/unstable/ai)
|
||||
effect/unstable/cli/CliOutput (barrel: effect/unstable/cli)
|
||||
effect/unstable/cli/Param (barrel: effect/unstable/cli)
|
||||
effect/unstable/eventlog/EventLogServerUnencrypted (barrel: effect/unstable/eventlog)
|
||||
effect/unstable/eventlog/EventLogSessionAuth (barrel: effect/unstable/eventlog)
|
||||
effect/unstable/eventlog/SqlEventLogServerUnencrypted (barrel: effect/unstable/eventlog)
|
||||
effect/unstable/http/FindMyWay (barrel: effect/unstable/http)
|
||||
effect/unstable/http/HttpStaticServer (barrel: effect/unstable/http)
|
||||
effect/unstable/http/Multipasta (barrel: effect/unstable/http)
|
||||
effect/unstable/http/Multipasta/HeadersParser (barrel: effect/unstable/http)
|
||||
effect/unstable/http/Multipasta/Node (barrel: effect/unstable/http)
|
||||
effect/unstable/http/Multipasta/Search (barrel: effect/unstable/http)
|
||||
effect/unstable/http/Multipasta/Web (barrel: effect/unstable/http)
|
||||
effect/unstable/httpapi/HttpApiTest (barrel: effect/unstable/httpapi)
|
||||
effect/unstable/observability/PrometheusMetrics (barrel: effect/unstable/observability)
|
||||
effect/unstable/persistence/Redis (barrel: effect/unstable/persistence)
|
||||
effect/unstable/reactivity/AsyncResult (barrel: effect/unstable/reactivity)
|
||||
effect/unstable/reactivity/Atom (barrel: effect/unstable/reactivity)
|
||||
effect/unstable/reactivity/AtomHttpApi (barrel: effect/unstable/reactivity)
|
||||
effect/unstable/reactivity/AtomRef (barrel: effect/unstable/reactivity)
|
||||
effect/unstable/reactivity/AtomRegistry (barrel: effect/unstable/reactivity)
|
||||
effect/unstable/reactivity/AtomRpc (barrel: effect/unstable/reactivity)
|
||||
effect/unstable/reactivity/Hydration (barrel: effect/unstable/reactivity)
|
||||
effect/unstable/rpc/Utils (barrel: effect/unstable/rpc)
|
||||
```
|
||||
|
||||
## API Renames
|
||||
|
||||
Each line is `v3 API -> v4 API`. Use these mappings when rewriting renamed
|
||||
symbols from v3 source code to v4.
|
||||
|
||||
```text
|
||||
Effect.async -> Effect.callback
|
||||
Effect.zipRight -> Effect.andThen
|
||||
Effect.zipLeft -> Effect.tap
|
||||
Effect.either -> Effect.result
|
||||
Effect.catchAll -> Effect.catch
|
||||
Effect.catchAllCause -> Effect.catchCause
|
||||
Effect.catchAllDefect -> Effect.catchDefect
|
||||
Effect.catchSome -> Effect.catchIf
|
||||
Effect.catchIf -> Effect.catchIf
|
||||
Effect.optionFromOptional -> Effect.catchNoSuchElement
|
||||
Effect.catchSomeCause -> Effect.catchCauseIf
|
||||
Effect.tapErrorCause -> Effect.tapCause
|
||||
Effect.ignoreLogged -> Effect.ignore
|
||||
Effect.makeLatchUnsafe -> Latch.makeUnsafe
|
||||
Effect.makeLatch -> Latch.make
|
||||
Layer.scoped -> Layer.effect
|
||||
Layer.scopedDiscard -> Layer.effectDiscard
|
||||
Layer.tapErrorCause -> Layer.tapCause
|
||||
Mailbox -> Queue.Queue
|
||||
Mailbox.make -> Queue.make
|
||||
Either -> Result.Result
|
||||
Either.right -> Result.succeed
|
||||
Either.left -> Result.fail
|
||||
Scope.extend -> Scope.provide
|
||||
Effect.makeSemaphoreUnsafe -> Semaphore.makeUnsafe
|
||||
Effect.makeSemaphore -> Semaphore.make
|
||||
Stream.Context -> Stream.Services
|
||||
StreamHaltStrategy.HaltStrategy -> Stream.HaltStrategy
|
||||
Stream.repeatEffect -> Stream.fromEffectRepeat
|
||||
Stream.repeatEffectWithSchedule -> Stream.fromEffectSchedule
|
||||
Stream.async -> Stream.callback
|
||||
Stream.asyncEffect -> Stream.callback
|
||||
Stream.asyncPush -> Stream.callback
|
||||
Stream.asyncScoped -> Stream.callback
|
||||
Stream.repeatEffectChunk -> Stream.fromIterableEffectRepeat
|
||||
Stream.fromChunk -> Stream.fromArray
|
||||
Stream.fromChunks -> Stream.fromArrays
|
||||
Stream.mapChunks -> Stream.mapArray
|
||||
Stream.mapChunksEffect -> Stream.mapArrayEffect
|
||||
Stream.either -> Stream.result
|
||||
Stream.flattenChunks -> Stream.flattenArray
|
||||
Stream.flattenIterables -> Stream.flattenIterable
|
||||
Stream.mergeEither -> Stream.mergeResult
|
||||
Stream.zipWithChunks -> Stream.zipWithArray
|
||||
Stream.bufferChunks -> Stream.bufferArray
|
||||
Stream.catchAllCause -> Stream.catchCause
|
||||
Stream.tapErrorCause -> Stream.tapCause
|
||||
Stream.catchAll -> Stream.catch
|
||||
Stream.catchSome -> Stream.catchIf
|
||||
Stream.catchSomeCause -> Stream.catchCauseIf
|
||||
Stream.combineChunks -> Stream.combineArray
|
||||
provideSomeLayer -> Stream.provide
|
||||
provideSomeContext -> Stream.provide
|
||||
```
|
||||
173
repos/effect/migration/yieldable.md
Normal file
173
repos/effect/migration/yieldable.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# Effect Subtyping (v3) → Yieldable (v4)
|
||||
|
||||
In v3, many types were structural subtypes of `Effect` — they carried the
|
||||
Effect type ID at runtime and could be used anywhere an `Effect` was expected.
|
||||
This included `Ref`, `Deferred`, `Fiber`, `FiberRef`, `Config`, `Option`,
|
||||
`Either`, `Context.Tag`, and others.
|
||||
|
||||
While convenient, this created a class of subtle bugs. Because these types
|
||||
_were_ Effects, they could be silently passed to Effect combinators when you
|
||||
intended to pass the value itself. For example, passing a `Ref` where you meant
|
||||
to pass the value inside the `Ref`, or accidentally mapping over a `Deferred`
|
||||
as an Effect instead of awaiting it.
|
||||
|
||||
v4 replaces this with the **`Yieldable`** trait: a narrower contract that
|
||||
allows `yield*` in generators but does **not** make the type assignable to
|
||||
`Effect`.
|
||||
|
||||
## The `Yieldable` Interface
|
||||
|
||||
```ts
|
||||
interface Yieldable<Self, A, E = never, R = never> {
|
||||
asEffect(): Effect<A, E, R>
|
||||
[Symbol.iterator](): EffectIterator<Self>
|
||||
}
|
||||
```
|
||||
|
||||
Some example types that implement `Yieldable`:
|
||||
|
||||
- `Effect` itself
|
||||
- `Option` — yields the value or fails with `NoSuchElementError`
|
||||
- `Result` — yields the success or fails with the error
|
||||
- `Config` — yields the config value or fails with `ConfigError`
|
||||
- `Context.Service` — yields the service from the environment
|
||||
|
||||
Some example types that are **no longer** Effect subtypes and do **not**
|
||||
implement `Yieldable`:
|
||||
|
||||
- `Ref` — use `Ref.get(ref)` to read
|
||||
- `Deferred` — use `Deferred.await(deferred)` to wait
|
||||
- `Fiber` — use `Fiber.join(fiber)` to await
|
||||
|
||||
## `yield*` Still Works
|
||||
|
||||
`yield*` in `Effect.gen` works with any `Yieldable`. The runtime calls
|
||||
`.asEffect()` internally when yielding.
|
||||
|
||||
```ts
|
||||
import { Effect, Option } from "effect"
|
||||
|
||||
// The type of program is `Effect<number, NoSuchElementError>`
|
||||
const program = Effect.gen(function*() {
|
||||
// yield* works with Yieldable types — same as v3
|
||||
const value = yield* Option.some(42)
|
||||
return value // 42
|
||||
})
|
||||
```
|
||||
|
||||
## Effect Combinators Require `.asEffect()`
|
||||
|
||||
In v3, you could pass a `Yieldable` type directly to Effect combinators because
|
||||
it was a subtype of `Effect`. In v4, you must explicitly convert with
|
||||
`.asEffect()`.
|
||||
|
||||
**v3** — Option is an Effect subtype, so this compiles:
|
||||
|
||||
```ts
|
||||
import { Effect, Option } from "effect"
|
||||
|
||||
// Option<number> is assignable to Effect<number, NoSuchElementError>
|
||||
const program = Effect.map(Option.some(42), (n) => n + 1)
|
||||
```
|
||||
|
||||
**v4** — Option is not an Effect, so you must convert explicitly:
|
||||
|
||||
```ts
|
||||
import { Effect, Option } from "effect"
|
||||
|
||||
// Option is Yieldable but not Effect — use .asEffect()
|
||||
const program = Effect.map(Option.some(42).asEffect(), (n) => n + 1)
|
||||
|
||||
// Or more idiomatically, use a generator:
|
||||
const program2 = Effect.gen(function*() {
|
||||
const n = yield* Option.some(42)
|
||||
return n + 1
|
||||
})
|
||||
```
|
||||
|
||||
## Types No Longer Subtypes of Effect
|
||||
|
||||
Several types that extended `Effect` in v3 no longer do so in v4. Use the
|
||||
appropriate module functions instead.
|
||||
|
||||
**v3** — `Ref` extends `Effect<A>`, yielding the current value:
|
||||
|
||||
```ts
|
||||
import { Effect, Ref } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const ref = yield* Ref.make(0)
|
||||
const value = yield* ref // Ref is an Effect<number>
|
||||
})
|
||||
```
|
||||
|
||||
**v4** — `Ref` is a plain value, use `Ref.get`:
|
||||
|
||||
```ts
|
||||
import { Effect, Ref } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const ref = yield* Ref.make(0)
|
||||
const value = yield* Ref.get(ref)
|
||||
})
|
||||
```
|
||||
|
||||
**v3** — `Deferred` extends `Effect<A, E>`, resolving when completed:
|
||||
|
||||
```ts
|
||||
import { Deferred, Effect } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const deferred = yield* Deferred.make<string, never>()
|
||||
const value = yield* deferred // Deferred is an Effect<string>
|
||||
})
|
||||
```
|
||||
|
||||
**v4** — `Deferred` is a plain value, use `Deferred.await`:
|
||||
|
||||
```ts
|
||||
import { Deferred, Effect } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const deferred = yield* Deferred.make<string, never>()
|
||||
const value = yield* Deferred.await(deferred)
|
||||
})
|
||||
```
|
||||
|
||||
**v3** — `Fiber` extends `Effect<A, E>`, joining on yield:
|
||||
|
||||
```ts
|
||||
import { Effect, Fiber } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const fiber = yield* Effect.fork(task)
|
||||
const result = yield* fiber // Fiber is an Effect<A, E>
|
||||
})
|
||||
```
|
||||
|
||||
**v4** — `Fiber` is a plain value, use `Fiber.join`:
|
||||
|
||||
```ts
|
||||
import { Effect, Fiber } from "effect"
|
||||
|
||||
const program = Effect.gen(function*() {
|
||||
const fiber = yield* Effect.forkChild(task)
|
||||
const result = yield* Fiber.join(fiber)
|
||||
})
|
||||
```
|
||||
|
||||
## Why This Changed
|
||||
|
||||
The v3 subtyping approach meant the type system could not distinguish between
|
||||
"I have a Ref" and "I have an Effect that reads the Ref." This ambiguity led
|
||||
to bugs that were difficult to diagnose:
|
||||
|
||||
- Passing a `Ref` to `Effect.map` would read the ref's value rather than
|
||||
transforming the ref itself — often not the intended behavior.
|
||||
- A `Deferred` in a data structure could silently be treated as an Effect,
|
||||
causing unexpected awaits.
|
||||
- Combinators like `Effect.all` would accept an array of `Ref` values and
|
||||
silently read all of them, instead of producing a type error.
|
||||
|
||||
The `Yieldable` trait preserves the ergonomic `yield*` syntax in generators
|
||||
while making the conversion to `Effect` explicit everywhere else.
|
||||
Reference in New Issue
Block a user