@livestore/utils 0.4.0 → 0.5.0-dev.0

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 (247) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/NoopTracer.d.ts +7 -8
  3. package/dist/NoopTracer.d.ts.map +1 -1
  4. package/dist/NoopTracer.js +3 -18
  5. package/dist/NoopTracer.js.map +1 -1
  6. package/dist/NoopTracer.test.d.ts +2 -0
  7. package/dist/NoopTracer.test.d.ts.map +1 -0
  8. package/dist/NoopTracer.test.js +17 -0
  9. package/dist/NoopTracer.test.js.map +1 -0
  10. package/dist/browser/Opfs/Opfs.d.ts +179 -29
  11. package/dist/browser/Opfs/Opfs.d.ts.map +1 -1
  12. package/dist/browser/Opfs/Opfs.js +132 -307
  13. package/dist/browser/Opfs/Opfs.js.map +1 -1
  14. package/dist/browser/Opfs/debug-utils.d.ts.map +1 -1
  15. package/dist/browser/Opfs/debug-utils.js +5 -4
  16. package/dist/browser/Opfs/debug-utils.js.map +1 -1
  17. package/dist/browser/Opfs/utils.d.ts +8 -8
  18. package/dist/browser/Opfs/utils.d.ts.map +1 -1
  19. package/dist/browser/Opfs/utils.js +35 -26
  20. package/dist/browser/Opfs/utils.js.map +1 -1
  21. package/dist/browser/QuotaExceededError.d.ts +10 -9
  22. package/dist/browser/QuotaExceededError.d.ts.map +1 -1
  23. package/dist/browser/WebChannelBrowser.d.ts.map +1 -1
  24. package/dist/browser/WebChannelBrowser.js +21 -10
  25. package/dist/browser/WebChannelBrowser.js.map +1 -1
  26. package/dist/browser/WebError.d.ts +54 -86
  27. package/dist/browser/WebError.d.ts.map +1 -1
  28. package/dist/browser/WebError.js +91 -84
  29. package/dist/browser/WebError.js.map +1 -1
  30. package/dist/browser/WebError.test.js +6 -6
  31. package/dist/browser/WebError.test.js.map +1 -1
  32. package/dist/browser/WebLock.d.ts.map +1 -1
  33. package/dist/browser/WebLock.js +13 -13
  34. package/dist/browser/WebLock.js.map +1 -1
  35. package/dist/effect/Debug.d.ts +4 -7
  36. package/dist/effect/Debug.d.ts.map +1 -1
  37. package/dist/effect/Debug.js +32 -36
  38. package/dist/effect/Debug.js.map +1 -1
  39. package/dist/effect/Effect.d.ts +31 -22
  40. package/dist/effect/Effect.d.ts.map +1 -1
  41. package/dist/effect/Effect.js +51 -47
  42. package/dist/effect/Effect.js.map +1 -1
  43. package/dist/effect/Effect.test.d.ts +2 -0
  44. package/dist/effect/Effect.test.d.ts.map +1 -0
  45. package/dist/effect/Effect.test.js +72 -0
  46. package/dist/effect/Effect.test.js.map +1 -0
  47. package/dist/effect/Error.d.ts +4 -6
  48. package/dist/effect/Error.d.ts.map +1 -1
  49. package/dist/effect/Logger.d.ts +0 -6
  50. package/dist/effect/Logger.d.ts.map +1 -1
  51. package/dist/effect/Logger.js +0 -32
  52. package/dist/effect/Logger.js.map +1 -1
  53. package/dist/effect/OtelTracer.d.ts +1 -1
  54. package/dist/effect/OtelTracer.d.ts.map +1 -1
  55. package/dist/effect/OtelTracer.js +2 -3
  56. package/dist/effect/OtelTracer.js.map +1 -1
  57. package/dist/effect/RpcClient.d.ts +7 -7
  58. package/dist/effect/RpcClient.d.ts.map +1 -1
  59. package/dist/effect/RpcClient.js +72 -52
  60. package/dist/effect/RpcClient.js.map +1 -1
  61. package/dist/effect/Schedule.d.ts +1 -1
  62. package/dist/effect/Schedule.d.ts.map +1 -1
  63. package/dist/effect/Schedule.js +2 -2
  64. package/dist/effect/Schedule.js.map +1 -1
  65. package/dist/effect/Schema/debug-diff.d.ts +1 -1
  66. package/dist/effect/Schema/debug-diff.d.ts.map +1 -1
  67. package/dist/effect/Schema/debug-diff.js +5 -7
  68. package/dist/effect/Schema/debug-diff.js.map +1 -1
  69. package/dist/effect/Schema/debug-diff.test.js +7 -4
  70. package/dist/effect/Schema/debug-diff.test.js.map +1 -1
  71. package/dist/effect/Schema/index.d.ts +28 -20
  72. package/dist/effect/Schema/index.d.ts.map +1 -1
  73. package/dist/effect/Schema/index.js +55 -28
  74. package/dist/effect/Schema/index.js.map +1 -1
  75. package/dist/effect/Stream.d.ts +13 -5
  76. package/dist/effect/Stream.d.ts.map +1 -1
  77. package/dist/effect/Stream.js +19 -12
  78. package/dist/effect/Stream.js.map +1 -1
  79. package/dist/effect/Stream.test.js +9 -9
  80. package/dist/effect/Stream.test.js.map +1 -1
  81. package/dist/effect/Subscribable.d.ts +9 -3
  82. package/dist/effect/Subscribable.d.ts.map +1 -1
  83. package/dist/effect/Subscribable.js +20 -35
  84. package/dist/effect/Subscribable.js.map +1 -1
  85. package/dist/effect/SubscriptionRef.d.ts +5 -6
  86. package/dist/effect/SubscriptionRef.d.ts.map +1 -1
  87. package/dist/effect/SubscriptionRef.js +2 -3
  88. package/dist/effect/SubscriptionRef.js.map +1 -1
  89. package/dist/effect/TaskTracing.d.ts +1 -1
  90. package/dist/effect/TaskTracing.d.ts.map +1 -1
  91. package/dist/effect/TaskTracing.js +12 -16
  92. package/dist/effect/TaskTracing.js.map +1 -1
  93. package/dist/effect/WebChannel/WebChannel.d.ts +7 -7
  94. package/dist/effect/WebChannel/WebChannel.d.ts.map +1 -1
  95. package/dist/effect/WebChannel/WebChannel.js +64 -43
  96. package/dist/effect/WebChannel/WebChannel.js.map +1 -1
  97. package/dist/effect/WebChannel/WebChannel.test.js +15 -15
  98. package/dist/effect/WebChannel/WebChannel.test.js.map +1 -1
  99. package/dist/effect/WebChannel/broadcastChannelWithAck.d.ts.map +1 -1
  100. package/dist/effect/WebChannel/broadcastChannelWithAck.js +16 -9
  101. package/dist/effect/WebChannel/broadcastChannelWithAck.js.map +1 -1
  102. package/dist/effect/WebChannel/common.d.ts +16 -17
  103. package/dist/effect/WebChannel/common.d.ts.map +1 -1
  104. package/dist/effect/WebChannel/common.js +6 -6
  105. package/dist/effect/WebChannel/common.js.map +1 -1
  106. package/dist/effect/WebSocket.d.ts +4 -6
  107. package/dist/effect/WebSocket.d.ts.map +1 -1
  108. package/dist/effect/WebSocket.js +4 -4
  109. package/dist/effect/WebSocket.js.map +1 -1
  110. package/dist/effect/WebSocket.test.js +2 -2
  111. package/dist/effect/WebSocket.test.js.map +1 -1
  112. package/dist/effect/mod.browser-build.test.d.ts +2 -0
  113. package/dist/effect/mod.browser-build.test.d.ts.map +1 -0
  114. package/dist/effect/mod.browser-build.test.js +18 -0
  115. package/dist/effect/mod.browser-build.test.js.map +1 -0
  116. package/dist/effect/mod.d.ts +13 -15
  117. package/dist/effect/mod.d.ts.map +1 -1
  118. package/dist/effect/mod.js +13 -18
  119. package/dist/effect/mod.js.map +1 -1
  120. package/dist/effect/spanEvent.d.ts.map +1 -1
  121. package/dist/effect/spanEvent.js +2 -2
  122. package/dist/effect/spanEvent.js.map +1 -1
  123. package/dist/effect/spanEvent.test.js +10 -13
  124. package/dist/effect/spanEvent.test.js.map +1 -1
  125. package/dist/fast-deep-equal.d.ts.map +1 -1
  126. package/dist/fast-deep-equal.js +1 -2
  127. package/dist/fast-deep-equal.js.map +1 -1
  128. package/dist/misc.js +2 -2
  129. package/dist/misc.js.map +1 -1
  130. package/dist/mod.d.ts +0 -35
  131. package/dist/mod.d.ts.map +1 -1
  132. package/dist/mod.js +0 -8
  133. package/dist/mod.js.map +1 -1
  134. package/dist/node/mod.d.ts +17 -11
  135. package/dist/node/mod.d.ts.map +1 -1
  136. package/dist/node/mod.js +23 -16
  137. package/dist/node/mod.js.map +1 -1
  138. package/dist/object/index.d.ts +0 -9
  139. package/dist/object/index.d.ts.map +1 -1
  140. package/dist/object/index.js +0 -9
  141. package/dist/object/index.js.map +1 -1
  142. package/dist/string.d.ts +0 -2
  143. package/dist/string.d.ts.map +1 -1
  144. package/dist/string.js +0 -2
  145. package/dist/string.js.map +1 -1
  146. package/package.json +18 -36
  147. package/src/NoopTracer.test.ts +20 -0
  148. package/src/NoopTracer.ts +18 -41
  149. package/src/browser/Opfs/Opfs.ts +304 -277
  150. package/src/browser/Opfs/debug-utils.ts +7 -6
  151. package/src/browser/Opfs/utils.ts +36 -26
  152. package/src/browser/QuotaExceededError.ts +13 -10
  153. package/src/browser/WebChannelBrowser.ts +25 -11
  154. package/src/browser/WebError.test.ts +6 -6
  155. package/src/browser/WebError.ts +107 -133
  156. package/src/browser/WebLock.ts +13 -14
  157. package/src/effect/Debug.ts +66 -59
  158. package/src/effect/Effect.test.ts +117 -0
  159. package/src/effect/Effect.ts +84 -71
  160. package/src/effect/Logger.ts +0 -48
  161. package/src/effect/OtelTracer.ts +2 -3
  162. package/src/effect/RpcClient.ts +80 -61
  163. package/src/effect/Schedule.ts +4 -5
  164. package/src/effect/Schema/debug-diff.test.ts +6 -6
  165. package/src/effect/Schema/debug-diff.ts +6 -8
  166. package/src/effect/Schema/index.ts +122 -61
  167. package/src/effect/Stream.test.ts +9 -9
  168. package/src/effect/Stream.ts +23 -16
  169. package/src/effect/Subscribable.ts +31 -42
  170. package/src/effect/SubscriptionRef.ts +8 -12
  171. package/src/effect/TaskTracing.ts +13 -16
  172. package/src/effect/WebChannel/WebChannel.test.ts +23 -23
  173. package/src/effect/WebChannel/WebChannel.ts +87 -55
  174. package/src/effect/WebChannel/broadcastChannelWithAck.ts +21 -11
  175. package/src/effect/WebChannel/common.ts +14 -15
  176. package/src/effect/WebSocket.test.ts +2 -2
  177. package/src/effect/WebSocket.ts +9 -6
  178. package/src/effect/mod.browser-build.test.ts +19 -0
  179. package/src/effect/mod.ts +35 -69
  180. package/src/effect/spanEvent.test.ts +10 -13
  181. package/src/effect/spanEvent.ts +5 -3
  182. package/src/fast-deep-equal.ts +1 -2
  183. package/src/misc.ts +2 -2
  184. package/src/mod.ts +0 -36
  185. package/src/node/mod.ts +26 -20
  186. package/src/object/index.ts +0 -24
  187. package/src/string.ts +0 -3
  188. package/dist/effect/BucketQueue.d.ts +0 -20
  189. package/dist/effect/BucketQueue.d.ts.map +0 -1
  190. package/dist/effect/BucketQueue.js +0 -34
  191. package/dist/effect/BucketQueue.js.map +0 -1
  192. package/dist/effect/Scheduler.d.ts +0 -4
  193. package/dist/effect/Scheduler.d.ts.map +0 -1
  194. package/dist/effect/Scheduler.js +0 -9
  195. package/dist/effect/Scheduler.js.map +0 -1
  196. package/dist/effect/ServiceContext.d.ts +0 -37
  197. package/dist/effect/ServiceContext.d.ts.map +0 -1
  198. package/dist/effect/ServiceContext.js +0 -55
  199. package/dist/effect/ServiceContext.js.map +0 -1
  200. package/dist/guards.d.ts +0 -20
  201. package/dist/guards.d.ts.map +0 -1
  202. package/dist/guards.js +0 -20
  203. package/dist/guards.js.map +0 -1
  204. package/dist/node/ChildProcessRunner/ChildProcessRunner.d.ts +0 -4
  205. package/dist/node/ChildProcessRunner/ChildProcessRunner.d.ts.map +0 -1
  206. package/dist/node/ChildProcessRunner/ChildProcessRunner.js +0 -128
  207. package/dist/node/ChildProcessRunner/ChildProcessRunner.js.map +0 -1
  208. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts +0 -10
  209. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts.map +0 -1
  210. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js +0 -217
  211. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js.map +0 -1
  212. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.d.ts +0 -84
  213. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.d.ts.map +0 -1
  214. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.js +0 -68
  215. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/schema.js.map +0 -1
  216. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.d.ts +0 -2
  217. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.d.ts.map +0 -1
  218. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js +0 -52
  219. package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js.map +0 -1
  220. package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts +0 -23
  221. package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts.map +0 -1
  222. package/dist/node/ChildProcessRunner/ChildProcessWorker.js +0 -138
  223. package/dist/node/ChildProcessRunner/ChildProcessWorker.js.map +0 -1
  224. package/dist/object/omit.d.ts +0 -3
  225. package/dist/object/omit.d.ts.map +0 -1
  226. package/dist/object/omit.js +0 -14
  227. package/dist/object/omit.js.map +0 -1
  228. package/dist/object/pick.d.ts +0 -14
  229. package/dist/object/pick.d.ts.map +0 -1
  230. package/dist/object/pick.js +0 -17
  231. package/dist/object/pick.js.map +0 -1
  232. package/dist/time.d.ts +0 -12
  233. package/dist/time.d.ts.map +0 -1
  234. package/dist/time.js +0 -22
  235. package/dist/time.js.map +0 -1
  236. package/src/effect/BucketQueue.ts +0 -49
  237. package/src/effect/Scheduler.ts +0 -13
  238. package/src/effect/ServiceContext.ts +0 -108
  239. package/src/guards.ts +0 -23
  240. package/src/node/ChildProcessRunner/ChildProcessRunner.ts +0 -148
  241. package/src/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.ts +0 -311
  242. package/src/node/ChildProcessRunner/ChildProcessRunnerTest/schema.ts +0 -78
  243. package/src/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.ts +0 -65
  244. package/src/node/ChildProcessRunner/ChildProcessWorker.ts +0 -169
  245. package/src/object/omit.ts +0 -17
  246. package/src/object/pick.ts +0 -27
  247. package/src/time.ts +0 -25
@@ -1,13 +1,4 @@
1
- import * as Cause from 'effect/Cause'
2
- import * as Context from 'effect/Context'
3
- import * as Effect from 'effect/Effect'
4
- import type * as Exit from 'effect/Exit'
5
- import type * as Fiber from 'effect/Fiber'
6
- import * as Graph from 'effect/Graph'
7
- import * as Option from 'effect/Option'
8
- import * as RuntimeFlags from 'effect/RuntimeFlags'
9
- import * as Scope from 'effect/Scope'
10
- import type * as Tracer from 'effect/Tracer'
1
+ import { Cause, Context, Effect, type Exit, type Fiber, Graph, Option, Scope, Tracer } from 'effect'
11
2
 
12
3
  /**
13
4
  * How to use:
@@ -47,7 +38,7 @@ const ensureSpan = (traceId: string, spanId: string): [MutableSpanGraph, number]
47
38
  let nodeId = info.nodeIdBySpanId.get(spanId)
48
39
  if (nodeId === undefined) {
49
40
  nodeId = Graph.addNode(info.graph, {
50
- span: { _tag: 'ExternalSpan', spanId, traceId, sampled: false, context: Context.empty() },
41
+ span: { _tag: 'ExternalSpan', spanId, traceId, sampled: false, annotations: Context.empty() },
51
42
  events: [],
52
43
  exitTag: undefined,
53
44
  })
@@ -88,7 +79,7 @@ const addEvent = (traceId: string, spanId: string, event: SpanEvent) => {
88
79
  const addNodeExit = (traceId: string, spanId: string, exit: Exit.Exit<any, any>) => {
89
80
  const [mutableGraph, nodeId] = ensureSpan(traceId, spanId)
90
81
  Graph.updateNode(mutableGraph, nodeId, (previousInfo) => {
91
- const isInterruptedOnly = exit._tag === 'Failure' && Cause.isInterruptedOnly(exit.cause)
82
+ const isInterruptedOnly = exit._tag === 'Failure' && Cause.hasInterruptsOnly(exit.cause)
92
83
  return {
93
84
  ...previousInfo,
94
85
  exitTag: isInterruptedOnly === true ? ('Interrupted' as const) : exit._tag,
@@ -136,7 +127,7 @@ const createPropertyInterceptor = <T extends object, K extends keyof T>(
136
127
  type EffectDevtoolsHookEvent =
137
128
  | {
138
129
  _tag: 'FiberAllocated'
139
- fiber: Fiber.RuntimeFiber<any, any>
130
+ fiber: Fiber.Fiber<any, any>
140
131
  }
141
132
  | {
142
133
  _tag: 'ScopeAllocated'
@@ -144,45 +135,62 @@ type EffectDevtoolsHookEvent =
144
135
  }
145
136
 
146
137
  type GlobalWithFiberCurrent = {
147
- 'effect/FiberCurrent': Fiber.RuntimeFiber<any, any> | undefined
138
+ ['~effect/Fiber/currentFiber']: Fiber.Fiber<any, any> | undefined
148
139
  'effect/DevtoolsHook'?: {
149
140
  onEvent: (event: EffectDevtoolsHookEvent) => void
150
141
  }
151
142
  }
152
143
 
144
+ type MutableTracer = {
145
+ span: Tracer.Tracer['span']
146
+ context?: Tracer.Tracer['context']
147
+ }
148
+
149
+ type EvaluatablePrimitive<X> = Tracer.EffectPrimitive<X> & {
150
+ readonly ['~effect/Effect/evaluate']: (fiber: Fiber.Fiber<any, any>) => X
151
+ }
152
+
153
153
  const patchedTracer = new WeakSet<Tracer.Tracer>()
154
- const ensureTracerPatched = (currentTracer: Tracer.Tracer) => {
155
- if (patchedTracer.has(currentTracer) === true) {
154
+ const ensureTracerPatched = (tracer: Tracer.Tracer) => {
155
+ if (patchedTracer.has(tracer) === true) {
156
156
  return
157
157
  }
158
- patchedTracer.add(currentTracer)
158
+ patchedTracer.add(tracer)
159
+
160
+ // Effect v4 exposes the tracer context as readonly and caches it on fibers, so keep mutation localized here.
161
+ const mutableTracer = tracer as MutableTracer
159
162
 
160
- const oldSpanConstructor = currentTracer.span
161
- currentTracer.span = function (...args) {
162
- const span = oldSpanConstructor.apply(this, args)
163
+ const oldSpanConstructor: Tracer.Tracer['span'] = tracer.span
164
+ mutableTracer.span = function (this: Tracer.Tracer, options: Parameters<Tracer.Tracer['span']>[0]): Tracer.Span {
165
+ const span = oldSpanConstructor.call(this, options)
163
166
  addNode(span)
164
167
 
165
168
  const oldSpanEnd = span.end
166
- span.end = function (endTime, exit, ...args) {
167
- oldSpanEnd.apply(this, [endTime, exit, ...args])
169
+ span.end = function (this: Tracer.Span, endTime, exit) {
170
+ oldSpanEnd.call(this, endTime, exit)
168
171
  addNodeExit(this.traceId, this.spanId, exit)
169
172
  }
170
173
 
171
174
  const oldSpanEvent = span.event
172
- span.event = function (name, startTime, attributes, ...args) {
173
- oldSpanEvent.apply(this, [name, startTime, attributes, ...args])
175
+ span.event = function (this: Tracer.Span, name, startTime, attributes) {
176
+ oldSpanEvent.call(this, name, startTime, attributes)
174
177
  addEvent(this.traceId, this.spanId, { name, startTime, attributes: attributes ?? {} })
175
178
  }
176
179
 
177
180
  return span
178
181
  }
179
182
 
180
- const oldContext = currentTracer.context
181
- currentTracer.context = function (f, fiber, ...args) {
182
- const context = oldContext.apply(this, [f, fiber, ...args])
183
+ const oldContext = tracer.context
184
+ mutableTracer.context = function <X>(
185
+ this: Tracer.Tracer,
186
+ primitive: Tracer.EffectPrimitive<X>,
187
+ fiber: Fiber.Fiber<any, any>,
188
+ ) {
183
189
  ensureFiberPatched(fiber)
184
- // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Effect Tracer.context return type is opaque; patching requires cast
185
- return context as any
190
+ if (oldContext !== undefined) {
191
+ return oldContext(primitive, fiber)
192
+ }
193
+ return (primitive as EvaluatablePrimitive<X>)['~effect/Effect/evaluate'](fiber)
186
194
  }
187
195
  }
188
196
 
@@ -190,7 +198,7 @@ interface ScopeImpl extends Scope.Scope {
190
198
  readonly state:
191
199
  | {
192
200
  readonly _tag: 'Open'
193
- readonly finalizers: Map<{}, Scope.Scope.Finalizer>
201
+ readonly finalizers: Map<{}, (exit: Exit.Exit<unknown, unknown>) => Effect.Effect<unknown>>
194
202
  }
195
203
  | {
196
204
  readonly _tag: 'Closed'
@@ -200,10 +208,10 @@ interface ScopeImpl extends Scope.Scope {
200
208
 
201
209
  const knownScopes = new Map<
202
210
  ScopeImpl,
203
- { id: number; allocationFiber: Fiber.RuntimeFiber<any, any> | undefined; allocationSpan: Tracer.AnySpan | undefined }
211
+ { id: number; allocationFiber: Fiber.Fiber<any, any> | undefined; allocationSpan: Tracer.AnySpan | undefined }
204
212
  >()
205
213
  let lastScopeId = 0
206
- const ensureScopePatched = (scope: ScopeImpl, allocationFiber: Fiber.RuntimeFiber<any, any> | undefined) => {
214
+ const ensureScopePatched = (scope: ScopeImpl, allocationFiber: Fiber.Fiber<any, any> | undefined) => {
207
215
  if (scope.state._tag === 'Closed') return
208
216
  if (knownScopes.has(scope) === true) return
209
217
  const id = lastScopeId++
@@ -233,12 +241,12 @@ const cleanupScopes = () => {
233
241
  }
234
242
  }
235
243
 
236
- const knownFibers = new Set<Fiber.RuntimeFiber<any, any>>()
237
- const ensureFiberPatched = (fiber: Fiber.RuntimeFiber<any, any>) => {
244
+ const knownFibers = new Set<Fiber.Fiber<any, any>>()
245
+ const ensureFiberPatched = (fiber: Fiber.Fiber<any, any>) => {
238
246
  // patch tracer
239
- ensureTracerPatched(fiber.currentTracer)
247
+ ensureTracerPatched(fiber.getRef(Tracer.Tracer))
240
248
  // patch scope
241
- const currentScope = Context.getOrElse(fiber.currentContext, Scope.Scope, () => undefined)
249
+ const currentScope = Context.getOrElse(fiber.context, Scope.Scope, () => undefined)
242
250
  // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- casting Scope to ScopeImpl; internal Effect type not publicly exported
243
251
  if (currentScope !== undefined) ensureScopePatched(currentScope as any as ScopeImpl, undefined)
244
252
  // patch fiber
@@ -251,18 +259,18 @@ const ensureFiberPatched = (fiber: Fiber.RuntimeFiber<any, any>) => {
251
259
  }
252
260
 
253
261
  let patchScopeClose = false
254
- let onFiberResumed: undefined | ((fiber: Fiber.RuntimeFiber<any, any>) => void)
255
- let onFiberSuspended: undefined | ((fiber: Fiber.RuntimeFiber<any, any>) => void)
256
- let onFiberCompleted: undefined | ((fiber: Fiber.RuntimeFiber<any, any>, exit: Exit.Exit<any, any>) => void)
262
+ let onFiberResumed: undefined | ((fiber: Fiber.Fiber<any, any>) => void)
263
+ let onFiberSuspended: undefined | ((fiber: Fiber.Fiber<any, any>) => void)
264
+ let onFiberCompleted: undefined | ((fiber: Fiber.Fiber<any, any>, exit: Exit.Exit<any, any>) => void)
257
265
  export const attachSlowDebugInstrumentation = (options: {
258
266
  /** If set to true, the scope prototype will be patched to attach a span to visualize pending scope closing */
259
267
  readonly patchScopeClose?: boolean
260
268
  /** An optional callback that will be called when any fiber resumes performing a run loop */
261
- readonly onFiberResumed?: (fiber: Fiber.RuntimeFiber<any, any>) => void
269
+ readonly onFiberResumed?: (fiber: Fiber.Fiber<any, any>) => void
262
270
  /** An optional callback that will be called when any fiber stops performing a run loop */
263
- readonly onFiberSuspended?: (fiber: Fiber.RuntimeFiber<any, any>) => void
271
+ readonly onFiberSuspended?: (fiber: Fiber.Fiber<any, any>) => void
264
272
  /** An optional callback that will be called when any fiber completes with a exit */
265
- readonly onFiberCompleted?: (fiber: Fiber.RuntimeFiber<any, any>, exit: Exit.Exit<any, any>) => void
273
+ readonly onFiberCompleted?: (fiber: Fiber.Fiber<any, any>, exit: Exit.Exit<any, any>) => void
266
274
  }): void => {
267
275
  // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- accessing Effect's global fiber tracking via well-known symbol keys
268
276
  const _globalThis = globalThis as any as GlobalWithFiberCurrent
@@ -275,9 +283,9 @@ export const attachSlowDebugInstrumentation = (options: {
275
283
  onFiberResumed = options.onFiberResumed
276
284
  onFiberSuspended = options.onFiberSuspended
277
285
  onFiberCompleted = options.onFiberCompleted
278
- let lastFiber: undefined | Fiber.RuntimeFiber<any, any>
286
+ let lastFiber: undefined | Fiber.Fiber<any, any>
279
287
  // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- accessing Effect's global fiber tracking via well-known symbol keys
280
- createPropertyInterceptor(globalThis as any as GlobalWithFiberCurrent, 'effect/FiberCurrent', (value) => {
288
+ createPropertyInterceptor(globalThis as any as GlobalWithFiberCurrent, '~effect/Fiber/currentFiber', (value) => {
281
289
  if (value !== undefined && knownFibers.has(value) === true) onFiberResumed?.(value)
282
290
  if (value !== undefined) ensureFiberPatched(value)
283
291
  if (value == null && lastFiber !== undefined && knownFibers.has(lastFiber) === true) onFiberSuspended?.(lastFiber)
@@ -289,7 +297,7 @@ export const attachSlowDebugInstrumentation = (options: {
289
297
  switch (event._tag) {
290
298
  case 'ScopeAllocated':
291
299
  // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- casting Scope to ScopeImpl; internal Effect type not publicly exported
292
- ensureScopePatched(event.scope as any as ScopeImpl, _globalThis['effect/FiberCurrent'])
300
+ ensureScopePatched(event.scope as any as ScopeImpl, _globalThis['~effect/Fiber/currentFiber'])
293
301
  break
294
302
  case 'FiberAllocated':
295
303
  ensureFiberPatched(event.fiber)
@@ -327,9 +335,9 @@ const getSpanDuration = (span: Tracer.AnySpan): string => {
327
335
  }
328
336
 
329
337
  const filterGraphKeepAncestors = <N, E>(
330
- graph: Graph.Graph<N, E>,
338
+ graph: Graph.Graph<N, E, 'directed'>,
331
339
  predicate: (nodeData: N, nodeId: number) => boolean,
332
- ): Graph.Graph<N, E> => {
340
+ ): Graph.Graph<N, E, 'directed'> => {
333
341
  // Find all root nodes (nodes with no incoming edges)
334
342
  const rootNodes = Array.from(Graph.indices(Graph.externals(graph, { direction: 'incoming' })))
335
343
  const shouldInclude = new Set<number>()
@@ -351,14 +359,15 @@ const filterGraphKeepAncestors = <N, E>(
351
359
 
352
360
  // Create a filtered copy of the graph
353
361
  return Graph.mutate(graph, (mutable) => {
354
- for (const [nodeId] of mutable.nodes) {
362
+ const nodeIds = Array.from(Graph.indices(Graph.nodes(mutable)))
363
+ for (const nodeId of nodeIds) {
355
364
  if (shouldInclude.has(nodeId) === true) continue
356
365
  Graph.removeNode(mutable, nodeId)
357
366
  }
358
367
  })
359
368
  }
360
369
 
361
- const renderSpanNode = (graph: Graph.Graph<GraphNodeInfo, void>, nodeId: number): string[] => {
370
+ const renderSpanNode = (graph: Graph.Graph<GraphNodeInfo, void, 'directed'>, nodeId: number): string[] => {
362
371
  const node = Graph.getNode(graph, nodeId)
363
372
  if (Option.isNone(node) === true) return []
364
373
  const info = node.value
@@ -371,17 +380,17 @@ const renderSpanNode = (graph: Graph.Graph<GraphNodeInfo, void>, nodeId: number)
371
380
  .filter(
372
381
  (fiber) => fiber.currentSpan?.spanId === info.span.spanId && fiber.currentSpan?.traceId === info.span.traceId,
373
382
  )
374
- .map((fiber) => `#${fiber.id().id}`)
383
+ .map((fiber) => `#${fiber.id}`)
375
384
  .join(', ')
376
385
  const runningOnFibers = fiberIds.length > 0 ? ` [fibers ${fiberIds}]` : ''
377
386
 
378
387
  return [` ${status} ${name}${durationStr}${runningOnFibers}`]
379
388
  }
380
389
 
381
- const renderTree = <N, E, T extends Graph.Kind>(
382
- graph: Graph.Graph<N, E, T>,
390
+ const renderTree = <N, E>(
391
+ graph: Graph.Graph<N, E, 'directed'>,
383
392
  nodeIds: Array<number>,
384
- renderNode: (graph: Graph.Graph<N, E, T>, nodeId: number) => string[],
393
+ renderNode: (graph: Graph.Graph<N, E, 'directed'>, nodeId: number) => string[],
385
394
  ): string[] => {
386
395
  let lines: string[] = []
387
396
  for (let childIndex = 0; childIndex < nodeIds.length; childIndex++) {
@@ -422,9 +431,7 @@ export const logDebug = (options: LogDebugOptions = {}) => {
422
431
  // fibers
423
432
  lines = [...lines, 'Active Fibers:']
424
433
  for (const fiber of knownFibers) {
425
- // oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- accessing fiber.currentRuntimeFlags; internal Effect runtime property
426
- const interruptible = RuntimeFlags.interruptible((fiber as any).currentRuntimeFlags)
427
- lines = [...lines, `- #${fiber.id().id}${interruptible === false ? ' [uninterruptible]' : ''}`]
434
+ lines = [...lines, `- #${fiber.id}`]
428
435
  }
429
436
  if (knownFibers.size === 0) {
430
437
  lines = [...lines, '- No active effect fibers']
@@ -451,12 +458,12 @@ export const logDebug = (options: LogDebugOptions = {}) => {
451
458
  lines = [...lines, 'Open Scopes:']
452
459
  for (const [scope, info] of knownScopes) {
453
460
  const fiberIds = Array.from(knownFibers)
454
- .filter((fiber) => Context.getOrElse(fiber.currentContext, Scope.Scope, () => undefined) === scope)
455
- .map((fiber) => `#${fiber.id().id}`)
461
+ .filter((fiber) => Context.getOrElse(fiber.context, Scope.Scope, () => undefined) === scope)
462
+ .map((fiber) => `#${fiber.id}`)
456
463
  .join(', ')
457
464
  const usedByFibers = fiberIds.length > 0 ? ` [used by: ${fiberIds}]` : ''
458
465
  const allocationFiber =
459
- info.allocationFiber !== undefined ? ` [allocated in fiber #${info.allocationFiber.id().id}]` : ''
466
+ info.allocationFiber !== undefined ? ` [allocated in fiber #${info.allocationFiber.id}]` : ''
460
467
  const allocationSpan =
461
468
  info.allocationSpan !== undefined ? ` [allocated in span: ${getSpanName(info.allocationSpan)}]` : ''
462
469
  lines = [...lines, `- #${info.id}${usedByFibers}${allocationFiber}${allocationSpan}`]
@@ -0,0 +1,117 @@
1
+ import { describe, expect, expectTypeOf, it } from '@effect/vitest'
2
+ import { Cause, Effect } from 'effect'
3
+
4
+ import { trySyncOrPromiseOrEffect } from './Effect.ts'
5
+
6
+ interface RequiredService {
7
+ readonly RequiredService: unique symbol
8
+ }
9
+
10
+ declare const contextualEffect: Effect.Effect<number, 'effect-error', RequiredService>
11
+
12
+ describe('trySyncOrPromiseOrEffect', () => {
13
+ it.effect('returns a plain value', () =>
14
+ Effect.gen(function* () {
15
+ const result = yield* trySyncOrPromiseOrEffect(() => 42 as const)
16
+
17
+ expect(result).toBe(42)
18
+ }),
19
+ )
20
+
21
+ it.effect('evaluates the operation lazily for each execution', () =>
22
+ Effect.gen(function* () {
23
+ let executions = 0
24
+ const effect = trySyncOrPromiseOrEffect(() => ++executions)
25
+
26
+ expect(executions).toBe(0)
27
+ expect(yield* effect).toBe(1)
28
+ expect(yield* effect).toBe(2)
29
+ }),
30
+ )
31
+
32
+ it.effect('maps a synchronous throw to an UnknownError', () =>
33
+ Effect.gen(function* () {
34
+ const thrown = new Error('thrown')
35
+ const failure = yield* trySyncOrPromiseOrEffect(() => {
36
+ throw thrown
37
+ }).pipe(Effect.flip)
38
+
39
+ expect(failure).toBeInstanceOf(Cause.UnknownError)
40
+ if (failure instanceof Cause.UnknownError) {
41
+ expect(failure.cause).toBe(thrown)
42
+ }
43
+ }),
44
+ )
45
+
46
+ it.effect('awaits a resolving Promise', () =>
47
+ Effect.gen(function* () {
48
+ const result = yield* trySyncOrPromiseOrEffect(() => Promise.resolve('resolved'))
49
+
50
+ expect(result).toBe('resolved')
51
+ }),
52
+ )
53
+
54
+ it.effect('maps a rejected Promise to an UnknownError', () =>
55
+ Effect.gen(function* () {
56
+ const rejected = new Error('rejected')
57
+ const failure = yield* trySyncOrPromiseOrEffect(() => Promise.reject(rejected)).pipe(Effect.flip)
58
+
59
+ expect(failure).toBeInstanceOf(Cause.UnknownError)
60
+ if (failure instanceof Cause.UnknownError) {
61
+ expect(failure.cause).toBe(rejected)
62
+ }
63
+ }),
64
+ )
65
+
66
+ it.effect('maps a throwing Promise-like then getter to an UnknownError', () =>
67
+ Effect.gen(function* () {
68
+ const thrown = new Error('throwing then getter')
69
+ const thenable = {
70
+ // oxlint-disable-next-line eslint-plugin-unicorn(no-thenable) -- intentionally exercises Promise-like classification
71
+ get then(): PromiseLike<never>['then'] {
72
+ throw thrown
73
+ },
74
+ } satisfies PromiseLike<never>
75
+
76
+ const failure = yield* trySyncOrPromiseOrEffect(() => thenable).pipe(Effect.flip)
77
+
78
+ expect(failure).toBeInstanceOf(Cause.UnknownError)
79
+ if (failure instanceof Cause.UnknownError) {
80
+ expect(failure.cause).toBe(thrown)
81
+ }
82
+ }),
83
+ )
84
+
85
+ it.effect('executes and returns the value of a returned Effect', () =>
86
+ Effect.gen(function* () {
87
+ const result = yield* trySyncOrPromiseOrEffect(() => Effect.succeed('effect-value'))
88
+
89
+ expect(result).toBe('effect-value')
90
+ }),
91
+ )
92
+
93
+ it.effect('preserves a returned Effect failure', () =>
94
+ Effect.gen(function* () {
95
+ const expected = { _tag: 'ExpectedError' as const }
96
+ const failure = yield* trySyncOrPromiseOrEffect(() => Effect.fail(expected)).pipe(Effect.flip)
97
+
98
+ expect(failure).toBe(expected)
99
+ }),
100
+ )
101
+
102
+ it('preserves returned Effect success, error, and requirements types', () => {
103
+ const normalized = trySyncOrPromiseOrEffect(() => contextualEffect)
104
+
105
+ expectTypeOf(normalized).toEqualTypeOf<
106
+ Effect.Effect<number, 'effect-error' | Cause.UnknownError, RequiredService>
107
+ >()
108
+ })
109
+
110
+ it('returns an Effect when the operation only throws', () => {
111
+ const normalized = trySyncOrPromiseOrEffect((): never => {
112
+ throw new Error('thrown')
113
+ })
114
+
115
+ expectTypeOf(normalized).toEqualTypeOf<Effect.Effect<never, Cause.UnknownError>>()
116
+ })
117
+ })