@livestore/utils 0.4.0-dev.22 → 0.4.0-dev.23
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.
- package/dist/.tsbuildinfo +1 -0
- package/dist/NoopTracer.d.ts.map +1 -1
- package/dist/NoopTracer.js +11 -3
- package/dist/NoopTracer.js.map +1 -1
- package/dist/binary.js +1 -1
- package/dist/binary.js.map +1 -1
- package/dist/browser/Opfs/Opfs.d.ts +3 -3
- package/dist/browser/Opfs/Opfs.d.ts.map +1 -1
- package/dist/browser/Opfs/Opfs.js +1 -1
- package/dist/browser/Opfs/Opfs.js.map +1 -1
- package/dist/browser/Opfs/debug-utils.d.ts.map +1 -1
- package/dist/browser/Opfs/debug-utils.js +2 -2
- package/dist/browser/Opfs/debug-utils.js.map +1 -1
- package/dist/browser/Opfs/utils.d.ts.map +1 -1
- package/dist/browser/Opfs/utils.js +10 -10
- package/dist/browser/Opfs/utils.js.map +1 -1
- package/dist/browser/QuotaExceededError.d.ts.map +1 -1
- package/dist/browser/QuotaExceededError.js.map +1 -1
- package/dist/browser/WebChannelBrowser.d.ts +1 -1
- package/dist/browser/WebChannelBrowser.d.ts.map +1 -1
- package/dist/browser/WebError.d.ts +50 -54
- package/dist/browser/WebError.d.ts.map +1 -1
- package/dist/browser/WebError.js +25 -23
- package/dist/browser/WebError.js.map +1 -1
- package/dist/browser/WebLock.js +9 -9
- package/dist/browser/WebLock.js.map +1 -1
- package/dist/browser/detect.js +6 -6
- package/dist/browser/detect.js.map +1 -1
- package/dist/cuid/cuid.browser.js +1 -1
- package/dist/cuid/cuid.browser.js.map +1 -1
- package/dist/cuid/cuid.node.js +1 -1
- package/dist/cuid/cuid.node.js.map +1 -1
- package/dist/effect/BucketQueue.d.ts +1 -1
- package/dist/effect/BucketQueue.d.ts.map +1 -1
- package/dist/effect/BucketQueue.js.map +1 -1
- package/dist/effect/Debug.d.ts +2 -2
- package/dist/effect/Debug.d.ts.map +1 -1
- package/dist/effect/Debug.js +69 -61
- package/dist/effect/Debug.js.map +1 -1
- package/dist/effect/Effect.d.ts +72 -12
- package/dist/effect/Effect.d.ts.map +1 -1
- package/dist/effect/Effect.js +96 -12
- package/dist/effect/Effect.js.map +1 -1
- package/dist/effect/Error.js +1 -1
- package/dist/effect/Error.js.map +1 -1
- package/dist/effect/Logger.js +2 -2
- package/dist/effect/Logger.js.map +1 -1
- package/dist/effect/RpcClient.d.ts.map +1 -1
- package/dist/effect/RpcClient.js +4 -4
- package/dist/effect/RpcClient.js.map +1 -1
- package/dist/effect/Schema/debug-diff.js +5 -4
- package/dist/effect/Schema/debug-diff.js.map +1 -1
- package/dist/effect/Schema/index.d.ts +5 -3
- package/dist/effect/Schema/index.d.ts.map +1 -1
- package/dist/effect/Schema/index.js +1 -1
- package/dist/effect/Schema/index.js.map +1 -1
- package/dist/effect/ServiceContext.js +6 -6
- package/dist/effect/ServiceContext.js.map +1 -1
- package/dist/effect/Stream.test.js +3 -3
- package/dist/effect/Stream.test.js.map +1 -1
- package/dist/effect/SubscriptionRef.d.ts +4 -4
- package/dist/effect/SubscriptionRef.d.ts.map +1 -1
- package/dist/effect/WebChannel/WebChannel.d.ts +2 -2
- package/dist/effect/WebChannel/WebChannel.d.ts.map +1 -1
- package/dist/effect/WebChannel/WebChannel.js +4 -4
- package/dist/effect/WebChannel/WebChannel.js.map +1 -1
- package/dist/effect/WebChannel/broadcastChannelWithAck.js +4 -4
- package/dist/effect/WebChannel/broadcastChannelWithAck.js.map +1 -1
- package/dist/effect/WebChannel/common.d.ts +1 -1
- package/dist/effect/WebChannel/common.d.ts.map +1 -1
- package/dist/effect/WebChannel/common.js +2 -2
- package/dist/effect/WebChannel/common.js.map +1 -1
- package/dist/effect/WebSocket.js +3 -3
- package/dist/effect/WebSocket.js.map +1 -1
- package/dist/effect/mod.d.ts +1 -1
- package/dist/effect/mod.d.ts.map +1 -1
- package/dist/effect/mod.js +1 -1
- package/dist/effect/mod.js.map +1 -1
- package/dist/effect/spanEvent.d.ts +12 -0
- package/dist/effect/spanEvent.d.ts.map +1 -0
- package/dist/effect/spanEvent.js +12 -0
- package/dist/effect/spanEvent.js.map +1 -0
- package/dist/effect/spanEvent.test.d.ts +2 -0
- package/dist/effect/spanEvent.test.d.ts.map +1 -0
- package/dist/effect/spanEvent.test.js +82 -0
- package/dist/effect/spanEvent.test.js.map +1 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +1 -1
- package/dist/env.js.map +1 -1
- package/dist/fast-deep-equal.js +9 -9
- package/dist/fast-deep-equal.js.map +1 -1
- package/dist/global.d.ts.map +1 -1
- package/dist/global.js.map +1 -1
- package/dist/misc.d.ts +9 -1
- package/dist/misc.d.ts.map +1 -1
- package/dist/misc.js +11 -3
- package/dist/misc.js.map +1 -1
- package/dist/mod.d.ts +1 -1
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +12 -12
- package/dist/mod.js.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunner.d.ts.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunner.js +15 -9
- package/dist/node/ChildProcessRunner/ChildProcessRunner.js.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts +8 -0
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.d.ts.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js +10 -6
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.js.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js +2 -2
- package/dist/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.js.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessWorker.d.ts.map +1 -1
- package/dist/node/ChildProcessRunner/ChildProcessWorker.js +4 -4
- package/dist/node/ChildProcessRunner/ChildProcessWorker.js.map +1 -1
- package/dist/node/mod.d.ts.map +1 -1
- package/dist/node/mod.js +1 -1
- package/dist/node/mod.js.map +1 -1
- package/dist/object/index.d.ts.map +1 -1
- package/dist/object/index.js.map +1 -1
- package/dist/object/omit.js +1 -1
- package/dist/object/omit.js.map +1 -1
- package/dist/object/stringify-object.js +2 -2
- package/dist/object/stringify-object.js.map +1 -1
- package/dist/object/stringify-object.test.js.map +1 -1
- package/dist/qr.js +11 -11
- package/dist/qr.js.map +1 -1
- package/dist/set.js +1 -1
- package/dist/set.js.map +1 -1
- package/dist/time.js +1 -1
- package/dist/time.js.map +1 -1
- package/package.json +65 -51
- package/src/NoopTracer.ts +17 -8
- package/src/binary.ts +1 -1
- package/src/browser/Opfs/Opfs.ts +12 -4
- package/src/browser/Opfs/debug-utils.ts +8 -6
- package/src/browser/Opfs/utils.ts +11 -10
- package/src/browser/QuotaExceededError.ts +0 -2
- package/src/browser/WebChannelBrowser.ts +1 -1
- package/src/browser/WebError.ts +100 -86
- package/src/browser/WebLock.ts +15 -15
- package/src/browser/detect.ts +6 -6
- package/src/cuid/cuid.browser.ts +1 -1
- package/src/cuid/cuid.node.ts +1 -1
- package/src/effect/BucketQueue.ts +1 -1
- package/src/effect/Debug.ts +67 -55
- package/src/effect/Effect.ts +118 -36
- package/src/effect/Error.ts +1 -1
- package/src/effect/Logger.ts +2 -2
- package/src/effect/RpcClient.ts +7 -6
- package/src/effect/Schema/debug-diff.ts +6 -5
- package/src/effect/Schema/index.ts +9 -6
- package/src/effect/ServiceContext.ts +6 -6
- package/src/effect/Stream.test.ts +5 -4
- package/src/effect/SubscriptionRef.ts +5 -5
- package/src/effect/WebChannel/WebChannel.ts +6 -6
- package/src/effect/WebChannel/broadcastChannelWithAck.ts +4 -4
- package/src/effect/WebChannel/common.ts +4 -4
- package/src/effect/WebSocket.ts +3 -3
- package/src/effect/mod.ts +1 -0
- package/src/effect/spanEvent.test.ts +95 -0
- package/src/effect/spanEvent.ts +15 -0
- package/src/env.ts +2 -1
- package/src/fast-deep-equal.ts +9 -9
- package/src/global.ts +0 -2
- package/src/misc.ts +12 -4
- package/src/mod.ts +11 -11
- package/src/node/ChildProcessRunner/ChildProcessRunner.ts +23 -10
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/ChildProcessRunner.test.ts +11 -7
- package/src/node/ChildProcessRunner/ChildProcessRunnerTest/serializedWorker.ts +10 -11
- package/src/node/ChildProcessRunner/ChildProcessWorker.ts +5 -4
- package/src/node/mod.ts +3 -1
- package/src/object/index.ts +1 -1
- package/src/object/omit.ts +1 -1
- package/src/object/stringify-object.test.ts +1 -0
- package/src/object/stringify-object.ts +2 -2
- package/src/qr.ts +11 -11
- package/src/set.ts +1 -1
- package/src/time.ts +1 -1
- package/dist/.tsbuildinfo.json +0 -1
package/src/effect/Debug.ts
CHANGED
|
@@ -35,7 +35,7 @@ export type MutableSpanGraphInfo = {
|
|
|
35
35
|
|
|
36
36
|
const graphByTraceId = new Map<string, MutableSpanGraphInfo>()
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
const ensureSpan = (traceId: string, spanId: string): [MutableSpanGraph, number] => {
|
|
39
39
|
let info = graphByTraceId.get(traceId)
|
|
40
40
|
if (info === undefined) {
|
|
41
41
|
info = {
|
|
@@ -56,20 +56,20 @@ function ensureSpan(traceId: string, spanId: string): [MutableSpanGraph, number]
|
|
|
56
56
|
return [info.graph, nodeId]
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
const sortSpan = (
|
|
60
60
|
prev: Tracer.AnySpan,
|
|
61
61
|
next: Tracer.AnySpan,
|
|
62
|
-
): [info: Tracer.AnySpan, isUpgrade: boolean, timingUpdated: boolean] {
|
|
62
|
+
): [info: Tracer.AnySpan, isUpgrade: boolean, timingUpdated: boolean] => {
|
|
63
63
|
if (prev._tag === 'ExternalSpan' && next._tag === 'Span') return [next, true, true]
|
|
64
64
|
if (prev._tag === 'Span' && next._tag === 'Span' && next.status._tag === 'Ended') return [next, false, true]
|
|
65
65
|
return [prev, false, false]
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
const addNode = (span: Tracer.AnySpan) => {
|
|
69
69
|
const [mutableGraph, nodeId] = ensureSpan(span.traceId, span.spanId)
|
|
70
70
|
Graph.updateNode(mutableGraph, nodeId, (previousInfo) => {
|
|
71
71
|
const [latestInfo, upgraded] = sortSpan(previousInfo.span, span)
|
|
72
|
-
if (upgraded && latestInfo._tag === 'Span' && Option.isSome(latestInfo.parent)) {
|
|
72
|
+
if (upgraded === true && latestInfo._tag === 'Span' && Option.isSome(latestInfo.parent) === true) {
|
|
73
73
|
const parentNodeId = addNode(latestInfo.parent.value)
|
|
74
74
|
Graph.addEdge(mutableGraph, parentNodeId, nodeId, undefined)
|
|
75
75
|
}
|
|
@@ -78,30 +78,30 @@ function addNode(span: Tracer.AnySpan) {
|
|
|
78
78
|
return nodeId
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
const addEvent = (traceId: string, spanId: string, event: SpanEvent) => {
|
|
82
82
|
const [mutableGraph, nodeId] = ensureSpan(traceId, spanId)
|
|
83
83
|
Graph.updateNode(mutableGraph, nodeId, (previousInfo) => {
|
|
84
84
|
return { ...previousInfo, events: [...previousInfo.events, event] }
|
|
85
85
|
})
|
|
86
86
|
return nodeId
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
const addNodeExit = (traceId: string, spanId: string, exit: Exit.Exit<any, any>) => {
|
|
89
89
|
const [mutableGraph, nodeId] = ensureSpan(traceId, spanId)
|
|
90
90
|
Graph.updateNode(mutableGraph, nodeId, (previousInfo) => {
|
|
91
91
|
const isInterruptedOnly = exit._tag === 'Failure' && Cause.isInterruptedOnly(exit.cause)
|
|
92
92
|
return {
|
|
93
93
|
...previousInfo,
|
|
94
|
-
exitTag: isInterruptedOnly ? ('Interrupted' as const) : exit._tag,
|
|
94
|
+
exitTag: isInterruptedOnly === true ? ('Interrupted' as const) : exit._tag,
|
|
95
95
|
}
|
|
96
96
|
})
|
|
97
97
|
return nodeId
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
const createPropertyInterceptor = <T extends object, K extends keyof T>(
|
|
101
101
|
obj: T,
|
|
102
102
|
property: K,
|
|
103
103
|
interceptor: (value: T[K]) => void,
|
|
104
|
-
): void {
|
|
104
|
+
): void => {
|
|
105
105
|
const descriptor = Object.getOwnPropertyDescriptor(obj, property)
|
|
106
106
|
|
|
107
107
|
const previousSetter = descriptor?.set
|
|
@@ -109,19 +109,19 @@ function createPropertyInterceptor<T extends object, K extends keyof T>(
|
|
|
109
109
|
let currentValue: T[K]
|
|
110
110
|
const previousGetter = descriptor?.get
|
|
111
111
|
|
|
112
|
-
if (
|
|
112
|
+
if (previousGetter == null) {
|
|
113
113
|
currentValue = obj[property]
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
Object.defineProperty(obj, property, {
|
|
117
117
|
get(): T[K] {
|
|
118
|
-
if (previousGetter) {
|
|
118
|
+
if (previousGetter !== undefined) {
|
|
119
119
|
return previousGetter.call(obj)
|
|
120
120
|
}
|
|
121
121
|
return currentValue
|
|
122
122
|
},
|
|
123
123
|
set(value: T[K]) {
|
|
124
|
-
if (previousSetter) {
|
|
124
|
+
if (previousSetter !== undefined) {
|
|
125
125
|
previousSetter.call(obj, value)
|
|
126
126
|
} else {
|
|
127
127
|
currentValue = value
|
|
@@ -151,8 +151,8 @@ type GlobalWithFiberCurrent = {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
const patchedTracer = new WeakSet<Tracer.Tracer>()
|
|
154
|
-
|
|
155
|
-
if (patchedTracer.has(currentTracer)) {
|
|
154
|
+
const ensureTracerPatched = (currentTracer: Tracer.Tracer) => {
|
|
155
|
+
if (patchedTracer.has(currentTracer) === true) {
|
|
156
156
|
return
|
|
157
157
|
}
|
|
158
158
|
patchedTracer.add(currentTracer)
|
|
@@ -181,6 +181,7 @@ function ensureTracerPatched(currentTracer: Tracer.Tracer) {
|
|
|
181
181
|
currentTracer.context = function (f, fiber, ...args) {
|
|
182
182
|
const context = oldContext.apply(this, [f, fiber, ...args])
|
|
183
183
|
ensureFiberPatched(fiber)
|
|
184
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Effect Tracer.context return type is opaque; patching requires cast
|
|
184
185
|
return context as any
|
|
185
186
|
}
|
|
186
187
|
}
|
|
@@ -202,14 +203,16 @@ const knownScopes = new Map<
|
|
|
202
203
|
{ id: number; allocationFiber: Fiber.RuntimeFiber<any, any> | undefined; allocationSpan: Tracer.AnySpan | undefined }
|
|
203
204
|
>()
|
|
204
205
|
let lastScopeId = 0
|
|
205
|
-
|
|
206
|
+
const ensureScopePatched = (scope: ScopeImpl, allocationFiber: Fiber.RuntimeFiber<any, any> | undefined) => {
|
|
206
207
|
if (scope.state._tag === 'Closed') return
|
|
207
|
-
if (knownScopes.has(scope)) return
|
|
208
|
+
if (knownScopes.has(scope) === true) return
|
|
208
209
|
const id = lastScopeId++
|
|
209
|
-
if (patchScopeClose) {
|
|
210
|
+
if (patchScopeClose === true) {
|
|
211
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- patching Scope.close; ScopeImpl is an internal interface not exported by Effect
|
|
210
212
|
const oldClose = (scope as any).close
|
|
213
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- patching Scope.close; ScopeImpl is an internal interface not exported by Effect
|
|
211
214
|
;(scope as any).close = function (...args: any[]) {
|
|
212
|
-
return oldClose.apply(this
|
|
215
|
+
return oldClose.apply(this, args).pipe(
|
|
213
216
|
Effect.withSpan(`scope.${id}.closeRunFinalizers`),
|
|
214
217
|
Effect.ensuring(
|
|
215
218
|
Effect.sync(() => {
|
|
@@ -231,14 +234,15 @@ const cleanupScopes = () => {
|
|
|
231
234
|
}
|
|
232
235
|
|
|
233
236
|
const knownFibers = new Set<Fiber.RuntimeFiber<any, any>>()
|
|
234
|
-
|
|
237
|
+
const ensureFiberPatched = (fiber: Fiber.RuntimeFiber<any, any>) => {
|
|
235
238
|
// patch tracer
|
|
236
239
|
ensureTracerPatched(fiber.currentTracer)
|
|
237
240
|
// patch scope
|
|
238
241
|
const currentScope = Context.getOrElse(fiber.currentContext, Scope.Scope, () => undefined)
|
|
239
|
-
|
|
242
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- casting Scope to ScopeImpl; internal Effect type not publicly exported
|
|
243
|
+
if (currentScope !== undefined) ensureScopePatched(currentScope as any as ScopeImpl, undefined)
|
|
240
244
|
// patch fiber
|
|
241
|
-
if (knownFibers.has(fiber)) return
|
|
245
|
+
if (knownFibers.has(fiber) === true) return
|
|
242
246
|
knownFibers.add(fiber)
|
|
243
247
|
fiber.addObserver((exit) => {
|
|
244
248
|
knownFibers.delete(fiber)
|
|
@@ -250,7 +254,7 @@ let patchScopeClose = false
|
|
|
250
254
|
let onFiberResumed: undefined | ((fiber: Fiber.RuntimeFiber<any, any>) => void)
|
|
251
255
|
let onFiberSuspended: undefined | ((fiber: Fiber.RuntimeFiber<any, any>) => void)
|
|
252
256
|
let onFiberCompleted: undefined | ((fiber: Fiber.RuntimeFiber<any, any>, exit: Exit.Exit<any, any>) => void)
|
|
253
|
-
export
|
|
257
|
+
export const attachSlowDebugInstrumentation = (options: {
|
|
254
258
|
/** If set to true, the scope prototype will be patched to attach a span to visualize pending scope closing */
|
|
255
259
|
readonly patchScopeClose?: boolean
|
|
256
260
|
/** An optional callback that will be called when any fiber resumes performing a run loop */
|
|
@@ -259,9 +263,10 @@ export function attachSlowDebugInstrumentation(options: {
|
|
|
259
263
|
readonly onFiberSuspended?: (fiber: Fiber.RuntimeFiber<any, any>) => void
|
|
260
264
|
/** An optional callback that will be called when any fiber completes with a exit */
|
|
261
265
|
readonly onFiberCompleted?: (fiber: Fiber.RuntimeFiber<any, any>, exit: Exit.Exit<any, any>) => void
|
|
262
|
-
}) {
|
|
266
|
+
}): void => {
|
|
267
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- accessing Effect's global fiber tracking via well-known symbol keys
|
|
263
268
|
const _globalThis = globalThis as any as GlobalWithFiberCurrent
|
|
264
|
-
if (_globalThis['effect/DevtoolsHook']) {
|
|
269
|
+
if (_globalThis['effect/DevtoolsHook'] !== undefined) {
|
|
265
270
|
return console.error(
|
|
266
271
|
'attachDebugInstrumentation has already been called! To show the tree, call attachDebugInstrumentation() in the root/main file of your program to ensure it is loaded as soon as possible.',
|
|
267
272
|
)
|
|
@@ -271,10 +276,11 @@ export function attachSlowDebugInstrumentation(options: {
|
|
|
271
276
|
onFiberSuspended = options.onFiberSuspended
|
|
272
277
|
onFiberCompleted = options.onFiberCompleted
|
|
273
278
|
let lastFiber: undefined | Fiber.RuntimeFiber<any, any>
|
|
279
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- accessing Effect's global fiber tracking via well-known symbol keys
|
|
274
280
|
createPropertyInterceptor(globalThis as any as GlobalWithFiberCurrent, 'effect/FiberCurrent', (value) => {
|
|
275
|
-
if (value && knownFibers.has(value)) onFiberResumed?.(value)
|
|
276
|
-
if (value) ensureFiberPatched(value)
|
|
277
|
-
if (
|
|
281
|
+
if (value !== undefined && knownFibers.has(value) === true) onFiberResumed?.(value)
|
|
282
|
+
if (value !== undefined) ensureFiberPatched(value)
|
|
283
|
+
if (value == null && lastFiber !== undefined && knownFibers.has(lastFiber) === true) onFiberSuspended?.(lastFiber)
|
|
278
284
|
lastFiber = value
|
|
279
285
|
})
|
|
280
286
|
_globalThis['effect/DevtoolsHook'] = {
|
|
@@ -282,6 +288,7 @@ export function attachSlowDebugInstrumentation(options: {
|
|
|
282
288
|
console.log('onEvent', event)
|
|
283
289
|
switch (event._tag) {
|
|
284
290
|
case 'ScopeAllocated':
|
|
291
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- casting Scope to ScopeImpl; internal Effect type not publicly exported
|
|
285
292
|
ensureScopePatched(event.scope as any as ScopeImpl, _globalThis['effect/FiberCurrent'])
|
|
286
293
|
break
|
|
287
294
|
case 'FiberAllocated':
|
|
@@ -292,7 +299,7 @@ export function attachSlowDebugInstrumentation(options: {
|
|
|
292
299
|
}
|
|
293
300
|
}
|
|
294
301
|
|
|
295
|
-
|
|
302
|
+
const formatDuration = (startTime: bigint, endTime: bigint | undefined): string => {
|
|
296
303
|
if (endTime === undefined) return '[running]'
|
|
297
304
|
const durationMs = Number(endTime - startTime) / 1000000 // Convert nanoseconds to milliseconds
|
|
298
305
|
if (durationMs < 1000) return `${durationMs.toFixed(0)}ms`
|
|
@@ -300,12 +307,12 @@ function formatDuration(startTime: bigint, endTime: bigint | undefined): string
|
|
|
300
307
|
return `${(durationMs / 60000).toFixed(2)}m`
|
|
301
308
|
}
|
|
302
309
|
|
|
303
|
-
|
|
310
|
+
const getSpanName = (span: Tracer.AnySpan): string => {
|
|
304
311
|
if (span._tag === 'ExternalSpan') return `[external] ${span.spanId}`
|
|
305
312
|
return span.name
|
|
306
313
|
}
|
|
307
314
|
|
|
308
|
-
|
|
315
|
+
const getSpanStatus = (info: GraphNodeInfo): string => {
|
|
309
316
|
if (info.span._tag === 'ExternalSpan') return '?'
|
|
310
317
|
if (info.exitTag === 'Success') return '✓'
|
|
311
318
|
if (info.exitTag === 'Failure') return '✗'
|
|
@@ -313,16 +320,16 @@ function getSpanStatus(info: GraphNodeInfo): string {
|
|
|
313
320
|
return '⋮'
|
|
314
321
|
}
|
|
315
322
|
|
|
316
|
-
|
|
323
|
+
const getSpanDuration = (span: Tracer.AnySpan): string => {
|
|
317
324
|
if (span._tag === 'ExternalSpan') return ''
|
|
318
325
|
const endTime = span.status._tag === 'Ended' ? span.status.endTime : undefined
|
|
319
326
|
return formatDuration(span.status.startTime, endTime)
|
|
320
327
|
}
|
|
321
328
|
|
|
322
|
-
|
|
329
|
+
const filterGraphKeepAncestors = <N, E>(
|
|
323
330
|
graph: Graph.Graph<N, E>,
|
|
324
331
|
predicate: (nodeData: N, nodeId: number) => boolean,
|
|
325
|
-
): Graph.Graph<N, E> {
|
|
332
|
+
): Graph.Graph<N, E> => {
|
|
326
333
|
// Find all root nodes (nodes with no incoming edges)
|
|
327
334
|
const rootNodes = Array.from(Graph.indices(Graph.externals(graph, { direction: 'incoming' })))
|
|
328
335
|
const shouldInclude = new Set<number>()
|
|
@@ -330,35 +337,35 @@ function filterGraphKeepAncestors<N, E>(
|
|
|
330
337
|
// Use postorder DFS to evaluate children before parents
|
|
331
338
|
for (const nodeId of Graph.indices(Graph.dfsPostOrder(graph, { start: rootNodes, direction: 'outgoing' }))) {
|
|
332
339
|
const node = Graph.getNode(graph, nodeId)
|
|
333
|
-
if (Option.isNone(node)) continue
|
|
340
|
+
if (Option.isNone(node) === true) continue
|
|
334
341
|
|
|
335
342
|
const matchesPredicate = predicate(node.value, nodeId)
|
|
336
|
-
if (matchesPredicate) {
|
|
343
|
+
if (matchesPredicate === true) {
|
|
337
344
|
shouldInclude.add(nodeId)
|
|
338
345
|
} else {
|
|
339
346
|
const children = Graph.neighborsDirected(graph, nodeId, 'outgoing')
|
|
340
347
|
const hasMatchingChildren = children.some((childId) => shouldInclude.has(childId))
|
|
341
|
-
if (hasMatchingChildren) shouldInclude.add(nodeId)
|
|
348
|
+
if (hasMatchingChildren === true) shouldInclude.add(nodeId)
|
|
342
349
|
}
|
|
343
350
|
}
|
|
344
351
|
|
|
345
352
|
// Create a filtered copy of the graph
|
|
346
353
|
return Graph.mutate(graph, (mutable) => {
|
|
347
354
|
for (const [nodeId] of mutable.nodes) {
|
|
348
|
-
if (shouldInclude.has(nodeId)) continue
|
|
355
|
+
if (shouldInclude.has(nodeId) === true) continue
|
|
349
356
|
Graph.removeNode(mutable, nodeId)
|
|
350
357
|
}
|
|
351
358
|
})
|
|
352
359
|
}
|
|
353
360
|
|
|
354
|
-
|
|
361
|
+
const renderSpanNode = (graph: Graph.Graph<GraphNodeInfo, void>, nodeId: number): string[] => {
|
|
355
362
|
const node = Graph.getNode(graph, nodeId)
|
|
356
|
-
if (Option.isNone(node)) return []
|
|
363
|
+
if (Option.isNone(node) === true) return []
|
|
357
364
|
const info = node.value
|
|
358
365
|
const status = getSpanStatus(info)
|
|
359
366
|
const name = getSpanName(info.span)
|
|
360
367
|
const duration = getSpanDuration(info.span)
|
|
361
|
-
const durationStr = duration ? ` ${duration}` : ''
|
|
368
|
+
const durationStr = duration !== undefined ? ` ${duration}` : ''
|
|
362
369
|
|
|
363
370
|
const fiberIds = Array.from(knownFibers)
|
|
364
371
|
.filter(
|
|
@@ -371,11 +378,11 @@ function renderSpanNode(graph: Graph.Graph<GraphNodeInfo, void, 'directed'>, nod
|
|
|
371
378
|
return [` ${status} ${name}${durationStr}${runningOnFibers}`]
|
|
372
379
|
}
|
|
373
380
|
|
|
374
|
-
|
|
381
|
+
const renderTree = <N, E, T extends Graph.Kind>(
|
|
375
382
|
graph: Graph.Graph<N, E, T>,
|
|
376
383
|
nodeIds: Array<number>,
|
|
377
384
|
renderNode: (graph: Graph.Graph<N, E, T>, nodeId: number) => string[],
|
|
378
|
-
): string[] {
|
|
385
|
+
): string[] => {
|
|
379
386
|
let lines: string[] = []
|
|
380
387
|
for (let childIndex = 0; childIndex < nodeIds.length; childIndex++) {
|
|
381
388
|
const isLastChild = childIndex === nodeIds.length - 1
|
|
@@ -386,9 +393,9 @@ function renderTree<N, E, T extends Graph.Kind>(
|
|
|
386
393
|
...lines,
|
|
387
394
|
...childLines.map((l, lineIndex) => {
|
|
388
395
|
if (lineIndex === 0) {
|
|
389
|
-
return (isLastChild ? ' └─' : ' ├─') + l
|
|
396
|
+
return (isLastChild === true ? ' └─' : ' ├─') + l
|
|
390
397
|
}
|
|
391
|
-
return (isLastChild ? ' ' : ' │') + l
|
|
398
|
+
return (isLastChild === true ? ' ' : ' │') + l
|
|
392
399
|
}),
|
|
393
400
|
]
|
|
394
401
|
}
|
|
@@ -402,8 +409,9 @@ export interface LogDebugOptions {
|
|
|
402
409
|
}
|
|
403
410
|
|
|
404
411
|
export const logDebug = (options: LogDebugOptions = {}) => {
|
|
412
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- accessing Effect's global fiber tracking via well-known symbol keys
|
|
405
413
|
const _globalThis = globalThis as any as GlobalWithFiberCurrent
|
|
406
|
-
if (
|
|
414
|
+
if (_globalThis['effect/DevtoolsHook'] == null) {
|
|
407
415
|
return console.error(
|
|
408
416
|
'attachDebugInstrumentation has not been called! To show the tree, call attachDebugInstrumentation() in the root/main file of your program to ensure it is loaded as soon as possible.',
|
|
409
417
|
)
|
|
@@ -414,8 +422,9 @@ export const logDebug = (options: LogDebugOptions = {}) => {
|
|
|
414
422
|
// fibers
|
|
415
423
|
lines = [...lines, 'Active Fibers:']
|
|
416
424
|
for (const fiber of knownFibers) {
|
|
425
|
+
// oxlint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- accessing fiber.currentRuntimeFlags; internal Effect runtime property
|
|
417
426
|
const interruptible = RuntimeFlags.interruptible((fiber as any).currentRuntimeFlags)
|
|
418
|
-
lines = [...lines, `- #${fiber.id().id}${
|
|
427
|
+
lines = [...lines, `- #${fiber.id().id}${interruptible === false ? ' [uninterruptible]' : ''}`]
|
|
419
428
|
}
|
|
420
429
|
if (knownFibers.size === 0) {
|
|
421
430
|
lines = [...lines, '- No active effect fibers']
|
|
@@ -425,12 +434,13 @@ export const logDebug = (options: LogDebugOptions = {}) => {
|
|
|
425
434
|
// spans
|
|
426
435
|
for (const [traceId, info] of graphByTraceId) {
|
|
427
436
|
const graph = Graph.endMutation(info.graph)
|
|
428
|
-
const filteredGraph =
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
437
|
+
const filteredGraph =
|
|
438
|
+
options.regex !== undefined
|
|
439
|
+
? filterGraphKeepAncestors(graph, (nodeData, _nodeId) => {
|
|
440
|
+
const name = getSpanName(nodeData.span)
|
|
441
|
+
return options.regex!.test(name)
|
|
442
|
+
})
|
|
443
|
+
: graph
|
|
434
444
|
const filteredRootNodes = Array.from(Graph.indices(Graph.externals(filteredGraph, { direction: 'incoming' })))
|
|
435
445
|
|
|
436
446
|
lines = [...lines, `Spans Trace ${traceId}:`, ...renderTree(filteredGraph, filteredRootNodes, renderSpanNode)]
|
|
@@ -445,8 +455,10 @@ export const logDebug = (options: LogDebugOptions = {}) => {
|
|
|
445
455
|
.map((fiber) => `#${fiber.id().id}`)
|
|
446
456
|
.join(', ')
|
|
447
457
|
const usedByFibers = fiberIds.length > 0 ? ` [used by: ${fiberIds}]` : ''
|
|
448
|
-
const allocationFiber =
|
|
449
|
-
|
|
458
|
+
const allocationFiber =
|
|
459
|
+
info.allocationFiber !== undefined ? ` [allocated in fiber #${info.allocationFiber.id().id}]` : ''
|
|
460
|
+
const allocationSpan =
|
|
461
|
+
info.allocationSpan !== undefined ? ` [allocated in span: ${getSpanName(info.allocationSpan)}]` : ''
|
|
450
462
|
lines = [...lines, `- #${info.id}${usedByFibers}${allocationFiber}${allocationSpan}`]
|
|
451
463
|
}
|
|
452
464
|
if (knownScopes.size === 0) {
|
package/src/effect/Effect.ts
CHANGED
|
@@ -6,9 +6,6 @@ import {
|
|
|
6
6
|
Duration,
|
|
7
7
|
Effect,
|
|
8
8
|
Fiber,
|
|
9
|
-
FiberRef,
|
|
10
|
-
HashSet,
|
|
11
|
-
Logger,
|
|
12
9
|
pipe,
|
|
13
10
|
Scope,
|
|
14
11
|
type Stream,
|
|
@@ -18,10 +15,11 @@ import { log } from 'effect/Console'
|
|
|
18
15
|
import { dual, type LazyArg } from 'effect/Function'
|
|
19
16
|
import type { Predicate, Refinement } from 'effect/Predicate'
|
|
20
17
|
|
|
21
|
-
import { isPromise } from '../mod.ts'
|
|
18
|
+
import { isDevEnv, isPromise, objectToString } from '../mod.ts'
|
|
22
19
|
import { UnknownError } from './Error.ts'
|
|
23
20
|
|
|
24
21
|
export * from 'effect/Effect'
|
|
22
|
+
export { spanEvent } from './spanEvent.ts'
|
|
25
23
|
|
|
26
24
|
// export const log = <A>(message: A, ...rest: any[]): Effect.Effect<void> =>
|
|
27
25
|
// Effect.sync(() => {
|
|
@@ -57,16 +55,16 @@ export type SyncOrPromiseOrEffect<TResult, TError = never, TContext = never> =
|
|
|
57
55
|
|
|
58
56
|
export const tryAll = <Res>(
|
|
59
57
|
fn: () => Res,
|
|
60
|
-
): Res extends Effect.Effect<infer A, infer E
|
|
61
|
-
? Effect.Effect<A, E | UnknownException
|
|
58
|
+
): Res extends Effect.Effect<infer A, infer E>
|
|
59
|
+
? Effect.Effect<A, E | UnknownException>
|
|
62
60
|
: Res extends Promise<infer A>
|
|
63
|
-
? Effect.Effect<A, UnknownException
|
|
64
|
-
: Effect.Effect<Res, UnknownException
|
|
61
|
+
? Effect.Effect<A, UnknownException>
|
|
62
|
+
: Effect.Effect<Res, UnknownException> =>
|
|
65
63
|
Effect.try(() => fn()).pipe(
|
|
66
64
|
Effect.andThen((fnRes) =>
|
|
67
|
-
Effect.isEffect(fnRes)
|
|
65
|
+
Effect.isEffect(fnRes) === true
|
|
68
66
|
? (fnRes as any as Effect.Effect<any>)
|
|
69
|
-
: isPromise(fnRes)
|
|
67
|
+
: isPromise(fnRes) === true
|
|
70
68
|
? Effect.promise(() => fnRes)
|
|
71
69
|
: Effect.succeed(fnRes),
|
|
72
70
|
),
|
|
@@ -89,7 +87,7 @@ export const logBefore =
|
|
|
89
87
|
export const tapCauseLogPretty = <R, E, A>(eff: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
|
|
90
88
|
Effect.tapErrorCause(eff, (cause) =>
|
|
91
89
|
Effect.gen(function* () {
|
|
92
|
-
if (Cause.isInterruptedOnly(cause)) {
|
|
90
|
+
if (Cause.isInterruptedOnly(cause) === true) {
|
|
93
91
|
// console.log('interrupted', Cause.pretty(err), err)
|
|
94
92
|
return
|
|
95
93
|
}
|
|
@@ -107,6 +105,47 @@ export const tapCauseLogPretty = <R, E, A>(eff: Effect.Effect<A, E, R>): Effect.
|
|
|
107
105
|
}),
|
|
108
106
|
)
|
|
109
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Creates a defect, pausing at a breakpoint in development.
|
|
110
|
+
*
|
|
111
|
+
* @param msg - The error message to include in the defect.
|
|
112
|
+
* @param args - Arbitrary arguments available for inspection during debugging.
|
|
113
|
+
*
|
|
114
|
+
* @see {@link shouldNeverHappen} for the non-Effect equivalent that throws synchronously.
|
|
115
|
+
* @see {@link orDieDebugger}
|
|
116
|
+
*/
|
|
117
|
+
export const dieDebugger = (msg: string, ...args: ReadonlyArray<unknown>): Effect.Effect<never> =>
|
|
118
|
+
Effect.suspend(() => {
|
|
119
|
+
if (isDevEnv() === true) {
|
|
120
|
+
// oxlint-disable-next-line eslint(no-debugger) -- intentional breakpoint during development
|
|
121
|
+
debugger
|
|
122
|
+
void args // Keeps the variable in scope so it's inspectable when the debugger pauses
|
|
123
|
+
}
|
|
124
|
+
return Effect.dieMessage(msg)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Converts a failure into a defect, pausing at a breakpoint in development.
|
|
129
|
+
*
|
|
130
|
+
* @param self - The effect on which to apply the operation.
|
|
131
|
+
*
|
|
132
|
+
* @see {@link Effect.orDie}
|
|
133
|
+
* @see {@link dieDebugger}
|
|
134
|
+
*/
|
|
135
|
+
export const orDieDebugger = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, never, R> =>
|
|
136
|
+
Effect.matchEffect(self, {
|
|
137
|
+
onFailure: (error) =>
|
|
138
|
+
// Keep the debugger hook so that `debugger` runs only when the wrapped effect actually fails, not while building the wrapper.
|
|
139
|
+
Effect.dieSync(() => {
|
|
140
|
+
if (isDevEnv() === true) {
|
|
141
|
+
// oxlint-disable-next-line eslint(no-debugger) -- intentional breakpoint for impossible states during development
|
|
142
|
+
debugger
|
|
143
|
+
}
|
|
144
|
+
return error
|
|
145
|
+
}),
|
|
146
|
+
onSuccess: Effect.succeed,
|
|
147
|
+
})
|
|
148
|
+
|
|
110
149
|
export const ignoreIf: {
|
|
111
150
|
<E, EB extends E>(
|
|
112
151
|
refinement: Refinement<NoInfer<E>, EB>,
|
|
@@ -124,11 +163,11 @@ export const ignoreIf: {
|
|
|
124
163
|
export const eventListener = <TEvent = unknown>(
|
|
125
164
|
target: Stream.EventListener<TEvent>,
|
|
126
165
|
type: string,
|
|
127
|
-
handler: (event: TEvent) => Effect.Effect<void
|
|
166
|
+
handler: (event: TEvent) => Effect.Effect<void>,
|
|
128
167
|
options?: { once?: boolean },
|
|
129
168
|
) =>
|
|
130
169
|
Effect.gen(function* () {
|
|
131
|
-
const runtime = yield* Effect.runtime
|
|
170
|
+
const runtime = yield* Effect.runtime()
|
|
132
171
|
|
|
133
172
|
const handlerFn = (event: TEvent) => handler(event).pipe(Effect.provide(runtime), Effect.runFork)
|
|
134
173
|
|
|
@@ -137,16 +176,11 @@ export const eventListener = <TEvent = unknown>(
|
|
|
137
176
|
yield* Effect.addFinalizer(() => Effect.sync(() => target.removeEventListener(type, handlerFn)))
|
|
138
177
|
})
|
|
139
178
|
|
|
140
|
-
export const spanEvent = (message: any, attributes?: Record<string, any>) =>
|
|
141
|
-
Effect.locallyWith(Effect.log(message).pipe(Effect.annotateLogs(attributes ?? {})), FiberRef.currentLoggers, () =>
|
|
142
|
-
HashSet.make(Logger.tracerLogger),
|
|
143
|
-
)
|
|
144
|
-
|
|
145
179
|
export const logWarnIfTakesLongerThan =
|
|
146
180
|
({ label, duration }: { label: string; duration: Duration.DurationInput }) =>
|
|
147
181
|
<R, E, A>(eff: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
|
|
148
182
|
Effect.gen(function* () {
|
|
149
|
-
const runtime = yield* Effect.runtime
|
|
183
|
+
const runtime = yield* Effect.runtime()
|
|
150
184
|
|
|
151
185
|
let tookLongerThanTimer = false
|
|
152
186
|
|
|
@@ -154,7 +188,7 @@ export const logWarnIfTakesLongerThan =
|
|
|
154
188
|
Effect.tap(() => {
|
|
155
189
|
tookLongerThanTimer = true
|
|
156
190
|
// TODO include span info
|
|
157
|
-
return Effect.logWarning(`${label}: Took longer than ${duration}ms`)
|
|
191
|
+
return Effect.logWarning(`${label}: Took longer than ${objectToString(duration)}ms`)
|
|
158
192
|
}),
|
|
159
193
|
Effect.provide(runtime),
|
|
160
194
|
Effect.runFork,
|
|
@@ -169,13 +203,14 @@ export const logWarnIfTakesLongerThan =
|
|
|
169
203
|
|
|
170
204
|
yield* Fiber.interrupt(timeoutFiber)
|
|
171
205
|
|
|
172
|
-
if (tookLongerThanTimer) {
|
|
206
|
+
if (tookLongerThanTimer === true) {
|
|
173
207
|
yield* Effect.logWarning(`${label}: Interrupted after ${end - start}ms`)
|
|
174
208
|
}
|
|
175
209
|
}),
|
|
176
210
|
),
|
|
177
211
|
)
|
|
178
212
|
|
|
213
|
+
// eslint-disable-next-line overeng/explicit-boolean-compare -- mutated in forked fiber; TS can't see the mutation
|
|
179
214
|
if (tookLongerThanTimer) {
|
|
180
215
|
const end = Date.now()
|
|
181
216
|
yield* Effect.logWarning(`${label}: Actual duration: ${end - start}ms`)
|
|
@@ -208,19 +243,61 @@ export const debugLogEnv = (msg?: string): Effect.Effect<Context.Context<never>>
|
|
|
208
243
|
Effect.tap((env) => log(msg ?? 'debugLogEnv', env)),
|
|
209
244
|
)
|
|
210
245
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
246
|
+
/**
|
|
247
|
+
* Enforces a time limit on an effect, triggering a defect on timeout.
|
|
248
|
+
*
|
|
249
|
+
* @remarks
|
|
250
|
+
*
|
|
251
|
+
* This function allows you to enforce a time limit on the execution of an
|
|
252
|
+
* effect. If the effect does not complete within the given duration, it dies
|
|
253
|
+
* with a {@link Cause.TimeoutException} as an unchecked defect. Unlike
|
|
254
|
+
* {@link Effect.timeout}, which adds `TimeoutException` to the error channel,
|
|
255
|
+
* this function keeps the error channel unchanged by treating the timeout as
|
|
256
|
+
* a defect.
|
|
257
|
+
*
|
|
258
|
+
* The returned effect will either:
|
|
259
|
+
* - Succeed with the original effect's result if it completes within the
|
|
260
|
+
* specified duration.
|
|
261
|
+
* - Die with a {@link Cause.TimeoutException} defect if the time limit is exceeded.
|
|
262
|
+
*
|
|
263
|
+
* @see {@link timeoutOrDieMessage} for a version with a custom message.
|
|
264
|
+
* @see {@link Effect.timeout} for a version that raises a `TimeoutException` as a typed error.
|
|
265
|
+
* @see {@link Effect.timeoutFailCause} for a version that raises a custom defect.
|
|
266
|
+
*/
|
|
267
|
+
export const timeoutOrDie = (duration: Duration.DurationInput) =>
|
|
268
|
+
<A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
|
|
269
|
+
Effect.timeoutFailCause(self, {
|
|
270
|
+
duration,
|
|
271
|
+
onTimeout: () => Cause.die(new Cause.TimeoutException())
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Enforces a time limit on an effect, triggering a defect with a custom
|
|
276
|
+
* message on timeout.
|
|
277
|
+
*
|
|
278
|
+
* @remarks
|
|
279
|
+
*
|
|
280
|
+
* This function behaves like {@link timeoutOrDie}, but allows you to provide
|
|
281
|
+
* a custom message for the {@link Cause.TimeoutException} defect. This is useful
|
|
282
|
+
* for adding context about which operation timed out, making it easier to
|
|
283
|
+
* diagnose issues in logs or error reports.
|
|
284
|
+
*
|
|
285
|
+
* The returned effect will either:
|
|
286
|
+
* - Succeed with the original effect's result if it completes within the
|
|
287
|
+
* specified duration.
|
|
288
|
+
* - Die with a {@link Cause.TimeoutException} defect containing the provided
|
|
289
|
+
* message if the time limit is exceeded.
|
|
290
|
+
*
|
|
291
|
+
* @see {@link timeoutOrDie} for a version without a custom message.
|
|
292
|
+
* @see {@link Effect.timeout} for a version that raises a `TimeoutException` as a typed error.
|
|
293
|
+
* @see {@link Effect.timeoutFailCause} for a version that raises a custom defect.
|
|
294
|
+
*/
|
|
295
|
+
export const timeoutOrDieMessage = (duration: Duration.DurationInput, message: string) =>
|
|
296
|
+
<A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
|
|
297
|
+
Effect.timeoutFailCause(self, {
|
|
298
|
+
duration,
|
|
299
|
+
onTimeout: () => Cause.die(new Cause.TimeoutException(message))
|
|
300
|
+
})
|
|
224
301
|
|
|
225
302
|
export const toForkedDeferred = <R, E, A>(
|
|
226
303
|
eff: Effect.Effect<A, E, R>,
|
|
@@ -274,7 +351,12 @@ const getSpanTrace = () => {
|
|
|
274
351
|
|
|
275
352
|
const logSpanTrace = () => console.log(getSpanTrace())
|
|
276
353
|
|
|
277
|
-
|
|
354
|
+
declare global {
|
|
355
|
+
/** Debug helper: returns the current Effect span trace */
|
|
356
|
+
var getSpanTrace: () => string
|
|
357
|
+
/** Debug helper: logs the current Effect span trace */
|
|
358
|
+
var logSpanTrace: () => void
|
|
359
|
+
}
|
|
360
|
+
|
|
278
361
|
globalThis.getSpanTrace = getSpanTrace
|
|
279
|
-
// @ts-expect-error TODO fix types
|
|
280
362
|
globalThis.logSpanTrace = logSpanTrace
|
package/src/effect/Error.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Schema } from 'effect'
|
|
2
2
|
|
|
3
|
-
export class UnknownError extends Schema.TaggedError<UnknownError>()('UnknownError', {
|
|
3
|
+
export class UnknownError extends Schema.TaggedError<UnknownError>('~@livestore/utils/UnknownError')('UnknownError', {
|
|
4
4
|
cause: Schema.Any,
|
|
5
5
|
payload: Schema.optional(Schema.Any),
|
|
6
6
|
}) {}
|
package/src/effect/Logger.ts
CHANGED
|
@@ -23,7 +23,7 @@ export const consoleLogger = (threadName: string) =>
|
|
|
23
23
|
const consoleFn =
|
|
24
24
|
logLevel === LogLevel.Debug
|
|
25
25
|
? // Cloudflare Workers doesn't support console.debug 🤷
|
|
26
|
-
isCloudflareWorker
|
|
26
|
+
isCloudflareWorker === true
|
|
27
27
|
? console.log
|
|
28
28
|
: console.debug
|
|
29
29
|
: logLevel === LogLevel.Info
|
|
@@ -34,7 +34,7 @@ export const consoleLogger = (threadName: string) =>
|
|
|
34
34
|
|
|
35
35
|
const annotationsObj = Object.fromEntries(HashMap.entries(annotations))
|
|
36
36
|
|
|
37
|
-
const messages = Array.isArray(message) ? message : [message]
|
|
37
|
+
const messages = Array.isArray(message) === true ? message : [message]
|
|
38
38
|
if (Cause.isEmpty(cause) === false) {
|
|
39
39
|
messages.push(Cause.pretty(cause, { renderErrorCause: true }))
|
|
40
40
|
}
|