effect 3.21.5 → 3.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/cjs/Context.js +1 -1
  2. package/dist/cjs/Graph.js +123 -66
  3. package/dist/cjs/Graph.js.map +1 -1
  4. package/dist/cjs/Mailbox.js +3 -2
  5. package/dist/cjs/Mailbox.js.map +1 -1
  6. package/dist/cjs/ParseResult.js +18 -0
  7. package/dist/cjs/ParseResult.js.map +1 -1
  8. package/dist/cjs/internal/config.js +5 -1
  9. package/dist/cjs/internal/config.js.map +1 -1
  10. package/dist/cjs/internal/configProvider.js +14 -1
  11. package/dist/cjs/internal/configProvider.js.map +1 -1
  12. package/dist/cjs/internal/effect/circular.js +5 -4
  13. package/dist/cjs/internal/effect/circular.js.map +1 -1
  14. package/dist/cjs/internal/mailbox.js +11 -19
  15. package/dist/cjs/internal/mailbox.js.map +1 -1
  16. package/dist/cjs/internal/opCodes/config.js +3 -1
  17. package/dist/cjs/internal/opCodes/config.js.map +1 -1
  18. package/dist/cjs/internal/stream/emit.js +6 -34
  19. package/dist/cjs/internal/stream/emit.js.map +1 -1
  20. package/dist/cjs/internal/stream.js +26 -16
  21. package/dist/cjs/internal/stream.js.map +1 -1
  22. package/dist/cjs/internal/version.js +1 -1
  23. package/dist/dts/Context.d.ts +1 -1
  24. package/dist/dts/Graph.d.ts +22 -3
  25. package/dist/dts/Graph.d.ts.map +1 -1
  26. package/dist/dts/Mailbox.d.ts.map +1 -1
  27. package/dist/dts/ParseResult.d.ts.map +1 -1
  28. package/dist/dts/internal/stream.d.ts.map +1 -1
  29. package/dist/esm/Context.js +1 -1
  30. package/dist/esm/Graph.js +116 -61
  31. package/dist/esm/Graph.js.map +1 -1
  32. package/dist/esm/Mailbox.js +3 -2
  33. package/dist/esm/Mailbox.js.map +1 -1
  34. package/dist/esm/ParseResult.js +18 -0
  35. package/dist/esm/ParseResult.js.map +1 -1
  36. package/dist/esm/internal/config.js +5 -1
  37. package/dist/esm/internal/config.js.map +1 -1
  38. package/dist/esm/internal/configProvider.js +14 -1
  39. package/dist/esm/internal/configProvider.js.map +1 -1
  40. package/dist/esm/internal/effect/circular.js +5 -4
  41. package/dist/esm/internal/effect/circular.js.map +1 -1
  42. package/dist/esm/internal/mailbox.js +10 -17
  43. package/dist/esm/internal/mailbox.js.map +1 -1
  44. package/dist/esm/internal/opCodes/config.js +2 -0
  45. package/dist/esm/internal/opCodes/config.js.map +1 -1
  46. package/dist/esm/internal/stream/emit.js +6 -34
  47. package/dist/esm/internal/stream/emit.js.map +1 -1
  48. package/dist/esm/internal/stream.js +22 -13
  49. package/dist/esm/internal/stream.js.map +1 -1
  50. package/dist/esm/internal/version.js +1 -1
  51. package/package.json +1 -1
  52. package/src/Context.ts +1 -1
  53. package/src/Graph.ts +149 -77
  54. package/src/Mailbox.ts +3 -2
  55. package/src/ParseResult.ts +18 -0
  56. package/src/internal/config.ts +14 -1
  57. package/src/internal/configProvider.ts +24 -1
  58. package/src/internal/effect/circular.ts +5 -4
  59. package/src/internal/mailbox.ts +13 -52
  60. package/src/internal/opCodes/config.ts +6 -0
  61. package/src/internal/stream/emit.ts +7 -39
  62. package/src/internal/stream.ts +62 -24
  63. package/src/internal/version.ts +1 -1
@@ -1,4 +1,4 @@
1
- let moduleVersion = "3.21.5";
1
+ let moduleVersion = "3.22.1";
2
2
  export const getCurrentVersion = () => moduleVersion;
3
3
  export const setCurrentVersion = version => {
4
4
  moduleVersion = version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect",
3
- "version": "3.21.5",
3
+ "version": "3.22.1",
4
4
  "description": "The missing standard library for TypeScript, for writing production-grade software.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/Context.ts CHANGED
@@ -165,7 +165,7 @@ export declare namespace Tag {
165
165
  }
166
166
 
167
167
  /**
168
- * Creates a new `Tag` instance with an optional key parameter.
168
+ * Creates a new `Tag` instance with the specified key.
169
169
  *
170
170
  * @example
171
171
  * ```ts
package/src/Graph.ts CHANGED
@@ -872,6 +872,29 @@ export const mapEdges = <N, E, T extends Kind = "directed">(
872
872
  }
873
873
  }
874
874
 
875
+ /** @internal */
876
+ const rebuildAdjacency = <N, E, T extends Kind = "directed">(
877
+ mutable: MutableGraph<N, E, T>
878
+ ): void => {
879
+ mutable.adjacency.clear()
880
+ mutable.reverseAdjacency.clear()
881
+
882
+ for (const nodeIndex of mutable.nodes.keys()) {
883
+ mutable.adjacency.set(nodeIndex, [])
884
+ mutable.reverseAdjacency.set(nodeIndex, [])
885
+ }
886
+
887
+ for (const [edgeIndex, edgeData] of mutable.edges) {
888
+ mutable.adjacency.get(edgeData.source)!.push(edgeIndex)
889
+ mutable.reverseAdjacency.get(edgeData.target)!.push(edgeIndex)
890
+
891
+ if (mutable.type === "undirected") {
892
+ mutable.adjacency.get(edgeData.target)!.push(edgeIndex)
893
+ mutable.reverseAdjacency.get(edgeData.source)!.push(edgeIndex)
894
+ }
895
+ }
896
+ }
897
+
875
898
  /**
876
899
  * Reverses all edge directions in a mutable graph by swapping source and target nodes.
877
900
  *
@@ -898,6 +921,10 @@ export const mapEdges = <N, E, T extends Kind = "directed">(
898
921
  export const reverse = <N, E, T extends Kind = "directed">(
899
922
  mutable: MutableGraph<N, E, T>
900
923
  ): void => {
924
+ if (mutable.type === "undirected") {
925
+ return
926
+ }
927
+
901
928
  // Reverse all edges by swapping source and target
902
929
  for (const [index, edgeData] of mutable.edges) {
903
930
  mutable.edges.set(index, {
@@ -907,22 +934,7 @@ export const reverse = <N, E, T extends Kind = "directed">(
907
934
  })
908
935
  }
909
936
 
910
- // Clear and rebuild adjacency lists with reversed directions
911
- mutable.adjacency.clear()
912
- mutable.reverseAdjacency.clear()
913
-
914
- // Rebuild adjacency lists with reversed directions
915
- for (const [edgeIndex, edgeData] of mutable.edges) {
916
- // Add to forward adjacency (source -> target)
917
- const sourceEdges = mutable.adjacency.get(edgeData.source) || []
918
- sourceEdges.push(edgeIndex)
919
- mutable.adjacency.set(edgeData.source, sourceEdges)
920
-
921
- // Add to reverse adjacency (target <- source)
922
- const targetEdges = mutable.reverseAdjacency.get(edgeData.target) || []
923
- targetEdges.push(edgeIndex)
924
- mutable.reverseAdjacency.set(edgeData.target, targetEdges)
925
- }
937
+ rebuildAdjacency(mutable)
926
938
 
927
939
  // Invalidate cycle flag since edge directions changed
928
940
  mutable.isAcyclic = Option.none()
@@ -1452,8 +1464,11 @@ export const hasEdge = <N, E, T extends Kind = "directed">(
1452
1464
  // Check if any edge in the adjacency list connects to the target
1453
1465
  for (const edgeIndex of adjacencyList) {
1454
1466
  const edge = graph.edges.get(edgeIndex)
1455
- if (edge !== undefined && edge.target === target) {
1456
- return true
1467
+ if (edge !== undefined) {
1468
+ const neighbor = graph.type === "undirected" && edge.target === source ? edge.source : edge.target
1469
+ if (neighbor === target) {
1470
+ return true
1471
+ }
1457
1472
  }
1458
1473
  }
1459
1474
 
@@ -1489,6 +1504,31 @@ export const edgeCount = <N, E, T extends Kind = "directed">(
1489
1504
  graph: Graph<N, E, T> | MutableGraph<N, E, T>
1490
1505
  ): number => graph.edges.size
1491
1506
 
1507
+ const getDirectedNeighbors = <N, E>(
1508
+ graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
1509
+ nodeIndex: NodeIndex,
1510
+ direction: Direction
1511
+ ): Array<NodeIndex> => {
1512
+ const adjacencyMap = direction === "incoming"
1513
+ ? graph.reverseAdjacency
1514
+ : graph.adjacency
1515
+
1516
+ const adjacencyList = adjacencyMap.get(nodeIndex)
1517
+ if (adjacencyList === undefined) {
1518
+ return []
1519
+ }
1520
+
1521
+ const result: Array<NodeIndex> = []
1522
+ for (const edgeIndex of adjacencyList) {
1523
+ const edge = graph.edges.get(edgeIndex)
1524
+ if (edge !== undefined) {
1525
+ result.push(direction === "incoming" ? edge.source : edge.target)
1526
+ }
1527
+ }
1528
+
1529
+ return result
1530
+ }
1531
+
1492
1532
  /**
1493
1533
  * Returns the neighboring nodes (targets of outgoing edges) for a given node.
1494
1534
  *
@@ -1527,24 +1567,47 @@ export const neighbors = <N, E, T extends Kind = "directed">(
1527
1567
  return getUndirectedNeighbors(graph as any, nodeIndex)
1528
1568
  }
1529
1569
 
1530
- const adjacencyList = graph.adjacency.get(nodeIndex)
1531
- if (adjacencyList === undefined) {
1532
- return []
1533
- }
1570
+ return getDirectedNeighbors(graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">, nodeIndex, "outgoing")
1571
+ }
1534
1572
 
1535
- const result: Array<NodeIndex> = []
1536
- for (const edgeIndex of adjacencyList) {
1537
- const edge = graph.edges.get(edgeIndex)
1538
- if (edge !== undefined) {
1539
- result.push(edge.target)
1540
- }
1573
+ /**
1574
+ * Returns the outgoing neighbor node indices for a node in a directed graph.
1575
+ *
1576
+ * Throws a `GraphError` when used with an undirected graph.
1577
+ *
1578
+ * @since 3.22.0
1579
+ * @category queries
1580
+ */
1581
+ export const successors = <N, E>(
1582
+ graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
1583
+ nodeIndex: NodeIndex
1584
+ ): Array<NodeIndex> => {
1585
+ if ((graph as Graph<N, E, Kind> | MutableGraph<N, E, Kind>).type === "undirected") {
1586
+ throw new GraphError({ message: "Cannot get successors of undirected graph" })
1541
1587
  }
1588
+ return getDirectedNeighbors(graph, nodeIndex, "outgoing")
1589
+ }
1542
1590
 
1543
- return result
1591
+ /**
1592
+ * Returns the incoming neighbor node indices for a node in a directed graph.
1593
+ *
1594
+ * Throws a `GraphError` when used with an undirected graph.
1595
+ *
1596
+ * @since 3.22.0
1597
+ * @category queries
1598
+ */
1599
+ export const predecessors = <N, E>(
1600
+ graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
1601
+ nodeIndex: NodeIndex
1602
+ ): Array<NodeIndex> => {
1603
+ if ((graph as Graph<N, E, Kind> | MutableGraph<N, E, Kind>).type === "undirected") {
1604
+ throw new GraphError({ message: "Cannot get predecessors of undirected graph" })
1605
+ }
1606
+ return getDirectedNeighbors(graph, nodeIndex, "incoming")
1544
1607
  }
1545
1608
 
1546
1609
  /**
1547
- * Get neighbors of a node in a specific direction for bidirectional traversal.
1610
+ * Get directed neighbors of a node in a specific direction.
1548
1611
  *
1549
1612
  * @example
1550
1613
  * ```ts
@@ -1566,36 +1629,19 @@ export const neighbors = <N, E, T extends Kind = "directed">(
1566
1629
  * const incoming = Graph.neighborsDirected(graph, nodeB, "incoming")
1567
1630
  * ```
1568
1631
  *
1632
+ * @deprecated Use {@link successors} for outgoing neighbors or {@link predecessors} for incoming neighbors.
1569
1633
  * @since 3.18.0
1570
1634
  * @category queries
1571
1635
  */
1572
- export const neighborsDirected = <N, E, T extends Kind = "directed">(
1573
- graph: Graph<N, E, T> | MutableGraph<N, E, T>,
1636
+ export const neighborsDirected = <N, E>(
1637
+ graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
1574
1638
  nodeIndex: NodeIndex,
1575
1639
  direction: Direction
1576
1640
  ): Array<NodeIndex> => {
1577
- const adjacencyMap = direction === "incoming"
1578
- ? graph.reverseAdjacency
1579
- : graph.adjacency
1580
-
1581
- const adjacencyList = adjacencyMap.get(nodeIndex)
1582
- if (adjacencyList === undefined) {
1583
- return []
1584
- }
1585
-
1586
- const result: Array<NodeIndex> = []
1587
- for (const edgeIndex of adjacencyList) {
1588
- const edge = graph.edges.get(edgeIndex)
1589
- if (edge !== undefined) {
1590
- // For incoming direction, we want the source node instead of target
1591
- const neighborNode = direction === "incoming"
1592
- ? edge.source
1593
- : edge.target
1594
- result.push(neighborNode)
1595
- }
1641
+ if ((graph as Graph<N, E, Kind> | MutableGraph<N, E, Kind>).type === "undirected") {
1642
+ throw new GraphError({ message: "Cannot get directed neighbors of undirected graph" })
1596
1643
  }
1597
-
1598
- return result
1644
+ return getDirectedNeighbors(graph, nodeIndex, direction)
1599
1645
  }
1600
1646
 
1601
1647
  // =============================================================================
@@ -1990,7 +2036,11 @@ export const isAcyclic = <N, E, T extends Kind = "directed">(
1990
2036
  recursionStack.add(node)
1991
2037
 
1992
2038
  // Get neighbors for this node
1993
- const nodeNeighbors = Array.from(neighborsDirected(graph, node, "outgoing"))
2039
+ const nodeNeighbors = getDirectedNeighbors(
2040
+ graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
2041
+ node,
2042
+ "outgoing"
2043
+ )
1994
2044
  stack[stack.length - 1] = [node, nodeNeighbors, 0, false]
1995
2045
  continue
1996
2046
  }
@@ -2141,7 +2191,7 @@ const getTraversalNeighbors = <N, E, T extends Kind>(
2141
2191
  ): Array<NodeIndex> =>
2142
2192
  graph.type === "undirected"
2143
2193
  ? getUndirectedNeighbors(graph as any, nodeIndex)
2144
- : neighborsDirected(graph, nodeIndex, direction)
2194
+ : getDirectedNeighbors(graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">, nodeIndex, direction)
2145
2195
 
2146
2196
  const getTraversableNeighbor = <N, E, T extends Kind>(
2147
2197
  graph: Graph<N, E, T> | MutableGraph<N, E, T>,
@@ -2231,9 +2281,13 @@ export const connectedComponents = <N, E>(
2231
2281
  * @since 3.18.0
2232
2282
  * @category algorithms
2233
2283
  */
2234
- export const stronglyConnectedComponents = <N, E, T extends Kind = "directed">(
2235
- graph: Graph<N, E, T> | MutableGraph<N, E, T>
2284
+ export const stronglyConnectedComponents = <N, E>(
2285
+ graph: Graph<N, E, "directed"> | MutableGraph<N, E, "directed">
2236
2286
  ): Array<Array<NodeIndex>> => {
2287
+ if ((graph as Graph<N, E, Kind> | MutableGraph<N, E, Kind>).type === "undirected") {
2288
+ throw new GraphError({ message: "Cannot find strongly connected components of undirected graph" })
2289
+ }
2290
+
2237
2291
  const visited = new Set<NodeIndex>()
2238
2292
  const finishOrder: Array<NodeIndex> = []
2239
2293
  // Iterate directly over node keys
@@ -2259,7 +2313,7 @@ export const stronglyConnectedComponents = <N, E, T extends Kind = "directed">(
2259
2313
  }
2260
2314
 
2261
2315
  visited.add(node)
2262
- const nodeNeighborsList = neighbors(graph, node)
2316
+ const nodeNeighborsList = getDirectedNeighbors(graph, node, "outgoing")
2263
2317
  stack[stack.length - 1] = [node, nodeNeighborsList, 0, false]
2264
2318
  continue
2265
2319
  }
@@ -2377,6 +2431,22 @@ export interface BellmanFordConfig<E> {
2377
2431
  cost: (edgeData: E) => number
2378
2432
  }
2379
2433
 
2434
+ const validateNonNegativeEdgeWeights = <N, E, T extends Kind = "directed">(
2435
+ graph: Graph<N, E, T> | MutableGraph<N, E, T>,
2436
+ cost: (edgeData: E) => number,
2437
+ algorithm: string
2438
+ ): Map<EdgeIndex, number> => {
2439
+ const edgeWeights = new Map<EdgeIndex, number>()
2440
+ for (const [edgeIndex, edgeData] of graph.edges) {
2441
+ const weight = cost(edgeData.data)
2442
+ if (weight < 0 || Number.isNaN(weight)) {
2443
+ throw new GraphError({ message: `${algorithm} requires non-negative edge weights` })
2444
+ }
2445
+ edgeWeights.set(edgeIndex, weight)
2446
+ }
2447
+ return edgeWeights
2448
+ }
2449
+
2380
2450
  /**
2381
2451
  * Find the shortest path between two nodes using Dijkstra's algorithm.
2382
2452
  *
@@ -2419,6 +2489,8 @@ export const dijkstra = <N, E, T extends Kind = "directed">(
2419
2489
  throw missingNode(target)
2420
2490
  }
2421
2491
 
2492
+ const edgeWeights = validateNonNegativeEdgeWeights(graph, cost, "Dijkstra's algorithm")
2493
+
2422
2494
  // Early return if source equals target
2423
2495
  if (source === target) {
2424
2496
  return Option.some({
@@ -2479,12 +2551,7 @@ export const dijkstra = <N, E, T extends Kind = "directed">(
2479
2551
  const edge = graph.edges.get(edgeIndex)
2480
2552
  if (edge !== undefined) {
2481
2553
  const neighbor = getTraversableNeighbor(graph, currentNode, edge)
2482
- const weight = cost(edge.data)
2483
-
2484
- // Validate non-negative weights
2485
- if (weight < 0) {
2486
- throw new Error(`Dijkstra's algorithm requires non-negative edge weights, found ${weight}`)
2487
- }
2554
+ const weight = edgeWeights.get(edgeIndex)!
2488
2555
 
2489
2556
  const newDistance = currentDistance + weight
2490
2557
  const neighborDistance = distances.get(neighbor)!
@@ -2738,6 +2805,8 @@ export const astar = <N, E, T extends Kind = "directed">(
2738
2805
  throw missingNode(target)
2739
2806
  }
2740
2807
 
2808
+ const edgeWeights = validateNonNegativeEdgeWeights(graph, cost, "A* algorithm")
2809
+
2741
2810
  // Early return if source equals target
2742
2811
  if (source === target) {
2743
2812
  return Option.some({
@@ -2813,12 +2882,7 @@ export const astar = <N, E, T extends Kind = "directed">(
2813
2882
  const edge = graph.edges.get(edgeIndex)
2814
2883
  if (edge !== undefined) {
2815
2884
  const neighbor = getTraversableNeighbor(graph, currentNode, edge)
2816
- const weight = cost(edge.data)
2817
-
2818
- // Validate non-negative weights
2819
- if (weight < 0) {
2820
- throw new Error(`A* algorithm requires non-negative edge weights, found ${weight}`)
2821
- }
2885
+ const weight = edgeWeights.get(edgeIndex)!
2822
2886
 
2823
2887
  const tentativeGScore = currentGScore + weight
2824
2888
  const neighborGScore = gScore.get(neighbor)!
@@ -3497,6 +3561,7 @@ export const topo = <N, E, T extends Kind = "directed">(
3497
3561
  [Symbol.iterator]: () => {
3498
3562
  const inDegree = new Map<NodeIndex, number>()
3499
3563
  const remaining = new Set<NodeIndex>()
3564
+ const initialSet = new Set(initials)
3500
3565
  const queue = [...initials]
3501
3566
 
3502
3567
  // Initialize in-degree counts
@@ -3511,12 +3576,15 @@ export const topo = <N, E, T extends Kind = "directed">(
3511
3576
  inDegree.set(edgeData.target, currentInDegree + 1)
3512
3577
  }
3513
3578
 
3514
- // Add nodes with zero in-degree to queue if no initials provided
3515
- if (initials.length === 0) {
3516
- for (const [nodeIndex, degree] of inDegree) {
3517
- if (degree === 0) {
3518
- queue.push(nodeIndex)
3519
- }
3579
+ for (const nodeIndex of initials) {
3580
+ if (inDegree.get(nodeIndex)! !== 0) {
3581
+ throw new GraphError({ message: `Initial node ${nodeIndex} has incoming edges` })
3582
+ }
3583
+ }
3584
+
3585
+ for (const [nodeIndex, degree] of inDegree) {
3586
+ if (degree === 0 && !initialSet.has(nodeIndex)) {
3587
+ queue.push(nodeIndex)
3520
3588
  }
3521
3589
  }
3522
3590
 
@@ -3528,7 +3596,11 @@ export const topo = <N, E, T extends Kind = "directed">(
3528
3596
  remaining.delete(current)
3529
3597
 
3530
3598
  // Process outgoing edges, reducing in-degree of targets
3531
- const neighbors = neighborsDirected(graph, current, "outgoing")
3599
+ const neighbors = getDirectedNeighbors(
3600
+ graph as Graph<N, E, "directed"> | MutableGraph<N, E, "directed">,
3601
+ current,
3602
+ "outgoing"
3603
+ )
3532
3604
  for (const neighbor of neighbors) {
3533
3605
  if (remaining.has(neighbor)) {
3534
3606
  const currentInDegree = inDegree.get(neighbor) || 0
package/src/Mailbox.ts CHANGED
@@ -9,6 +9,7 @@ import type { Effect } from "./Effect.js"
9
9
  import type { Exit } from "./Exit.js"
10
10
  import type { Inspectable } from "./Inspectable.js"
11
11
  import * as internal from "./internal/mailbox.js"
12
+ import * as internalStream from "./internal/stream.js"
12
13
  import type { Option } from "./Option.js"
13
14
  import { hasProperty } from "./Predicate.js"
14
15
  import type { Scope } from "./Scope.js"
@@ -258,7 +259,7 @@ export const toChannel: <A, E>(self: ReadonlyMailbox<A, E>) => Channel<Chunk<A>,
258
259
  * @experimental
259
260
  * @category conversions
260
261
  */
261
- export const toStream: <A, E>(self: ReadonlyMailbox<A, E>) => Stream<A, E> = internal.toStream
262
+ export const toStream: <A, E>(self: ReadonlyMailbox<A, E>) => Stream<A, E> = internalStream.mailboxToStream
262
263
 
263
264
  /**
264
265
  * Create a `ReadonlyMailbox` from a `Stream`.
@@ -295,4 +296,4 @@ export const fromStream: {
295
296
  readonly strategy?: "suspend" | "dropping" | "sliding" | undefined
296
297
  }
297
298
  ): Effect<ReadonlyMailbox<A, E>, never, R | Scope>
298
- } = internal.fromStream
299
+ } = internalStream.mailboxFromStream
@@ -914,6 +914,24 @@ const go = (ast: AST.AST, isDecoding: boolean): Parser => {
914
914
  case "Enums":
915
915
  return fromRefinement(ast, (u): u is any => ast.enums.some(([_, value]) => value === u))
916
916
  case "TemplateLiteral": {
917
+ if (ast.spans.every((span) => AST.isStringKeyword(span.type))) {
918
+ return fromRefinement(ast, (u): u is any => {
919
+ if (!Predicate.isString(u) || !u.startsWith(ast.head)) {
920
+ return false
921
+ }
922
+ let position = ast.head.length
923
+ for (let i = 0; i < ast.spans.length - 1; i++) {
924
+ const literal = ast.spans[i].literal
925
+ const index = u.indexOf(literal, position)
926
+ if (index === -1) {
927
+ return false
928
+ }
929
+ position = index + literal.length
930
+ }
931
+ const literal = ast.spans[ast.spans.length - 1].literal
932
+ return u.endsWith(literal) && u.length - literal.length >= position
933
+ })
934
+ }
917
935
  const regex = AST.getTemplateLiteralRegExp(ast)
918
936
  return fromRefinement(ast, (u): u is any => Predicate.isString(u) && regex.test(u))
919
937
  }
@@ -39,6 +39,7 @@ export type ConfigPrimitive =
39
39
  | MapOrFail
40
40
  | Nested
41
41
  | Primitive
42
+ | RedactedConfig
42
43
  | Sequence
43
44
  | Table
44
45
  | Zipped
@@ -125,6 +126,14 @@ export interface Primitive extends
125
126
  }>
126
127
  {}
127
128
 
129
+ /** @internal */
130
+ export interface RedactedConfig extends
131
+ Op<OpCodes.OP_REDACTED, {
132
+ readonly original: Config.Config<unknown>
133
+ redact(value: unknown): Redacted.Redacted<unknown>
134
+ }>
135
+ {}
136
+
128
137
  /** @internal */
129
138
  export interface Sequence extends
130
139
  Op<OpCodes.OP_SEQUENCE, {
@@ -475,7 +484,11 @@ export const redacted = <A>(
475
484
  nameOrConfig?: string | Config.Config<A>
476
485
  ): Config.Config<Redacted.Redacted<A | string>> => {
477
486
  const config: Config.Config<A | string> = isConfig(nameOrConfig) ? nameOrConfig : string(nameOrConfig)
478
- return map(config, redacted_.make)
487
+ const redacted = Object.create(proto)
488
+ redacted._tag = OpCodes.OP_REDACTED
489
+ redacted.original = config
490
+ redacted.redact = redacted_.make
491
+ return redacted
479
492
  }
480
493
 
481
494
  /** @internal */
@@ -236,6 +236,18 @@ const appendConfigPath = (path: ReadonlyArray<string>, config: Config.Config<unk
236
236
  return path
237
237
  }
238
238
 
239
+ const RedactedConfigErrorReducer: ConfigError.ConfigErrorReducer<unknown, ConfigError.ConfigError> = {
240
+ andCase: (_, left, right) => configError.And(left, right),
241
+ orCase: (_, left, right) => configError.Or(left, right),
242
+ invalidDataCase: (_, path) => configError.InvalidData(path, "<redacted>"),
243
+ missingDataCase: (_, path) => configError.MissingData(path, "<redacted>"),
244
+ sourceUnavailableCase: (_, path, _message, cause) => configError.SourceUnavailable(path, "<redacted>", cause),
245
+ unsupportedCase: (_, path) => configError.Unsupported(path, "<redacted>")
246
+ }
247
+
248
+ const redactConfigError = (error: ConfigError.ConfigError): ConfigError.ConfigError =>
249
+ configError.reduceWithContext(error, void 0, RedactedConfigErrorReducer)
250
+
239
251
  const fromFlatLoop = <A>(
240
252
  flat: ConfigProvider.ConfigProvider.Flat,
241
253
  prefix: ReadonlyArray<string>,
@@ -320,6 +332,15 @@ const fromFlatLoop = <A>(
320
332
  )
321
333
  ) as unknown as Effect.Effect<Array<A>, ConfigError.ConfigError>
322
334
  }
335
+ case OpCodes.OP_REDACTED: {
336
+ return core.suspend(() =>
337
+ pipe(
338
+ fromFlatLoop(flat, prefix, op.original, split),
339
+ core.mapError(redactConfigError),
340
+ core.map(Arr.map(op.redact))
341
+ )
342
+ ) as unknown as Effect.Effect<Array<A>, ConfigError.ConfigError>
343
+ }
323
344
  case OpCodes.OP_SEQUENCE: {
324
345
  return pipe(
325
346
  pathPatch.patch(prefix, flat.patch),
@@ -719,7 +740,9 @@ interface JsonArray extends Array<string | number | boolean | null | JsonArray |
719
740
  export const fromJson = (json: unknown): ConfigProvider.ConfigProvider => {
720
741
  const hiddenDelimiter = "\ufeff"
721
742
  const indexedEntries = Arr.map(
722
- getIndexedEntries(json as JsonMap),
743
+ getIndexedEntries(json as JsonMap).filter(([path]) =>
744
+ path.every((component) => component._tag === "KeyIndex" || !component.name.includes(hiddenDelimiter))
745
+ ),
723
746
  ([key, value]): [string, string] => [configPathToString(key).join(hiddenDelimiter), value]
724
747
  )
725
748
  return fromMap(new Map(indexedEntries), {
@@ -604,26 +604,27 @@ export const timeoutTo = dual<
604
604
  core.fiberIdWith((parentFiberId) =>
605
605
  core.uninterruptibleMask((restore) =>
606
606
  fiberRuntime.raceFibersWith(
607
- restore(self),
607
+ core.exit(restore(self)),
608
608
  core.interruptible(effect.sleep(duration)),
609
609
  {
610
610
  onSelfWin: (winner, loser) =>
611
611
  core.flatMap(
612
612
  winner.await,
613
613
  (exit) => {
614
- if (exit._tag === "Success") {
614
+ const selfExit = core.exitFlatten(exit)
615
+ if (selfExit._tag === "Success") {
615
616
  return core.flatMap(
616
617
  winner.inheritAll,
617
618
  () =>
618
619
  core.as(
619
620
  core.interruptAsFiber(loser, parentFiberId),
620
- onSuccess(exit.value)
621
+ onSuccess(selfExit.value)
621
622
  )
622
623
  )
623
624
  } else {
624
625
  return core.flatMap(
625
626
  core.interruptAsFiber(loser, parentFiberId),
626
- () => core.exitFailCause(exit.cause)
627
+ () => core.exitFailCause(selfExit.cause)
627
628
  )
628
629
  }
629
630
  }
@@ -13,15 +13,9 @@ import * as Option from "../Option.js"
13
13
  import { pipeArguments } from "../Pipeable.js"
14
14
  import { hasProperty } from "../Predicate.js"
15
15
  import type { Scheduler } from "../Scheduler.js"
16
- import type { Scope } from "../Scope.js"
17
- import type { Stream } from "../Stream.js"
18
16
  import * as channel from "./channel.js"
19
- import * as channelExecutor from "./channel/channelExecutor.js"
20
17
  import * as coreChannel from "./core-stream.js"
21
18
  import * as core from "./core.js"
22
- import * as circular from "./effect/circular.js"
23
- import * as fiberRuntime from "./fiberRuntime.js"
24
- import * as stream from "./stream.js"
25
19
 
26
20
  /** @internal */
27
21
  export const TypeId: Api.TypeId = Symbol.for("effect/Mailbox") as Api.TypeId
@@ -255,8 +249,17 @@ class MailboxImpl<A, E> extends Effectable.Class<readonly [messages: Chunk.Chunk
255
249
  return core.exitAs(this.state.exit, constDone)
256
250
  } else if (n <= 0) {
257
251
  return core.succeed([empty, false])
252
+ } else if (
253
+ this.capacity <= 0 && this.messages.length === 0 && this.messagesChunk.length === 0 &&
254
+ this.state.offers.size > 0
255
+ ) {
256
+ this.capacity = 1
257
+ this.releaseCapacity()
258
+ this.capacity = 0
259
+ const messages = Chunk.of(this.messages.pop()!)
260
+ return core.succeed([messages, this.releaseCapacity()])
258
261
  }
259
- n = Math.min(n, this.capacity)
262
+ n = Math.min(n, this.capacity || 1)
260
263
  let messages: Chunk.Chunk<A>
261
264
  if (n <= this.messagesChunk.length) {
262
265
  messages = Chunk.take(this.messagesChunk, n)
@@ -288,7 +291,9 @@ class MailboxImpl<A, E> extends Effectable.Class<readonly [messages: Chunk.Chunk
288
291
  this.capacity = 1
289
292
  this.releaseCapacity()
290
293
  this.capacity = 0
291
- return this.messages.length > 0 ? core.exitSucceed(this.messages.pop()!) : undefined
294
+ const message = this.messages.pop()!
295
+ this.releaseCapacity()
296
+ return core.exitSucceed(message)
292
297
  } else {
293
298
  return undefined
294
299
  }
@@ -515,47 +520,3 @@ export const toChannel = <A, E>(self: Api.ReadonlyMailbox<A, E>): Channel<Chunk.
515
520
  : channel.zipRight(coreChannel.write(messages), loop))
516
521
  return loop
517
522
  }
518
-
519
- /** @internal */
520
- export const toStream = <A, E>(self: Api.ReadonlyMailbox<A, E>): Stream<A, E> => stream.fromChannel(toChannel(self))
521
-
522
- /** @internal */
523
- export const fromStream: {
524
- (options?: {
525
- readonly capacity?: number | undefined
526
- readonly strategy?: "suspend" | "dropping" | "sliding" | undefined
527
- }): <A, E, R>(self: Stream<A, E, R>) => Effect<Api.ReadonlyMailbox<A, E>, never, R | Scope>
528
- <A, E, R>(
529
- self: Stream<A, E, R>,
530
- options?: {
531
- readonly capacity?: number | undefined
532
- readonly strategy?: "suspend" | "dropping" | "sliding" | undefined
533
- }
534
- ): Effect<Api.ReadonlyMailbox<A, E>, never, R | Scope>
535
- } = dual((args) => stream.isStream(args[0]), <A, E, R>(
536
- self: Stream<A, E, R>,
537
- options?: {
538
- readonly capacity?: number | undefined
539
- readonly strategy?: "suspend" | "dropping" | "sliding" | undefined
540
- }
541
- ): Effect<Api.ReadonlyMailbox<A, E>, never, R | Scope> =>
542
- core.tap(
543
- fiberRuntime.acquireRelease(
544
- make<A, E>(options),
545
- (mailbox) => mailbox.shutdown
546
- ),
547
- (mailbox) => {
548
- const writer: Channel<never, Chunk.Chunk<A>, never, E> = coreChannel.readWithCause({
549
- onInput: (input: Chunk.Chunk<A>) => coreChannel.flatMap(mailbox.offerAll(input), () => writer),
550
- onFailure: (cause: Cause<E>) => mailbox.failCause(cause),
551
- onDone: () => mailbox.end
552
- })
553
- return fiberRuntime.scopeWith((scope) =>
554
- stream.toChannel(self).pipe(
555
- coreChannel.pipeTo(writer),
556
- channelExecutor.runIn(scope),
557
- circular.forkIn(scope)
558
- )
559
- )
560
- }
561
- ))
@@ -46,6 +46,12 @@ export type OP_PRIMITIVE = typeof OP_PRIMITIVE
46
46
  /** @internal */
47
47
  export const OP_PRIMITIVE = "Primitive" as const
48
48
 
49
+ /** @internal */
50
+ export type OP_REDACTED = typeof OP_REDACTED
51
+
52
+ /** @internal */
53
+ export const OP_REDACTED = "Redacted" as const
54
+
49
55
  /** @internal */
50
56
  export type OP_SEQUENCE = typeof OP_SEQUENCE
51
57