@clayroach/effect 3.19.14-source-capture.7 → 3.19.14-source-trace.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 (106) hide show
  1. package/SourceLocation/package.json +6 -0
  2. package/dist/cjs/Effect.js +2 -28
  3. package/dist/cjs/Effect.js.map +1 -1
  4. package/dist/cjs/FiberRef.js +12 -1
  5. package/dist/cjs/FiberRef.js.map +1 -1
  6. package/dist/cjs/Layer.js +2 -24
  7. package/dist/cjs/Layer.js.map +1 -1
  8. package/dist/cjs/RuntimeFlags.js +1 -29
  9. package/dist/cjs/RuntimeFlags.js.map +1 -1
  10. package/dist/cjs/SourceLocation.js +60 -0
  11. package/dist/cjs/SourceLocation.js.map +1 -0
  12. package/dist/cjs/Tracer.js +1 -15
  13. package/dist/cjs/Tracer.js.map +1 -1
  14. package/dist/cjs/Utils.js +1 -1
  15. package/dist/cjs/Utils.js.map +1 -1
  16. package/dist/cjs/index.js +3 -1
  17. package/dist/cjs/index.js.map +1 -1
  18. package/dist/cjs/internal/clock.js +1 -1
  19. package/dist/cjs/internal/clock.js.map +1 -1
  20. package/dist/cjs/internal/core.js +17 -50
  21. package/dist/cjs/internal/core.js.map +1 -1
  22. package/dist/cjs/internal/effect/circular.js +18 -30
  23. package/dist/cjs/internal/effect/circular.js.map +1 -1
  24. package/dist/cjs/internal/fiberRuntime.js +16 -65
  25. package/dist/cjs/internal/fiberRuntime.js.map +1 -1
  26. package/dist/cjs/internal/layer/circular.js +1 -5
  27. package/dist/cjs/internal/layer/circular.js.map +1 -1
  28. package/dist/cjs/internal/layer.js +1 -3
  29. package/dist/cjs/internal/layer.js.map +1 -1
  30. package/dist/cjs/internal/logger.js +25 -2
  31. package/dist/cjs/internal/logger.js.map +1 -1
  32. package/dist/cjs/internal/runtimeFlags.js +2 -11
  33. package/dist/cjs/internal/runtimeFlags.js.map +1 -1
  34. package/dist/cjs/internal/tracer.js +1 -114
  35. package/dist/cjs/internal/tracer.js.map +1 -1
  36. package/dist/dts/Config.d.ts +2 -2
  37. package/dist/dts/Config.d.ts.map +1 -1
  38. package/dist/dts/Effect.d.ts +8 -29
  39. package/dist/dts/Effect.d.ts.map +1 -1
  40. package/dist/dts/FiberRef.d.ts +12 -0
  41. package/dist/dts/FiberRef.d.ts.map +1 -1
  42. package/dist/dts/Layer.d.ts +0 -22
  43. package/dist/dts/Layer.d.ts.map +1 -1
  44. package/dist/dts/RuntimeFlags.d.ts +0 -28
  45. package/dist/dts/RuntimeFlags.d.ts.map +1 -1
  46. package/dist/dts/SourceLocation.d.ts +88 -0
  47. package/dist/dts/SourceLocation.d.ts.map +1 -0
  48. package/dist/dts/Tracer.d.ts +0 -15
  49. package/dist/dts/Tracer.d.ts.map +1 -1
  50. package/dist/dts/index.d.ts +6 -0
  51. package/dist/dts/index.d.ts.map +1 -1
  52. package/dist/dts/internal/core.d.ts.map +1 -1
  53. package/dist/dts/internal/layer.d.ts.map +1 -1
  54. package/dist/dts/internal/runtimeFlags.d.ts.map +1 -1
  55. package/dist/esm/Effect.js +0 -26
  56. package/dist/esm/Effect.js.map +1 -1
  57. package/dist/esm/FiberRef.js +11 -0
  58. package/dist/esm/FiberRef.js.map +1 -1
  59. package/dist/esm/Layer.js +0 -22
  60. package/dist/esm/Layer.js.map +1 -1
  61. package/dist/esm/RuntimeFlags.js +0 -28
  62. package/dist/esm/RuntimeFlags.js.map +1 -1
  63. package/dist/esm/SourceLocation.js +51 -0
  64. package/dist/esm/SourceLocation.js.map +1 -0
  65. package/dist/esm/Tracer.js +0 -14
  66. package/dist/esm/Tracer.js.map +1 -1
  67. package/dist/esm/Utils.js +1 -1
  68. package/dist/esm/Utils.js.map +1 -1
  69. package/dist/esm/index.js +6 -0
  70. package/dist/esm/index.js.map +1 -1
  71. package/dist/esm/internal/clock.js +1 -1
  72. package/dist/esm/internal/clock.js.map +1 -1
  73. package/dist/esm/internal/core.js +12 -45
  74. package/dist/esm/internal/core.js.map +1 -1
  75. package/dist/esm/internal/effect/circular.js +18 -30
  76. package/dist/esm/internal/effect/circular.js.map +1 -1
  77. package/dist/esm/internal/fiberRuntime.js +13 -60
  78. package/dist/esm/internal/fiberRuntime.js.map +1 -1
  79. package/dist/esm/internal/layer/circular.js +0 -4
  80. package/dist/esm/internal/layer/circular.js.map +1 -1
  81. package/dist/esm/internal/layer.js +0 -2
  82. package/dist/esm/internal/layer.js.map +1 -1
  83. package/dist/esm/internal/logger.js +25 -2
  84. package/dist/esm/internal/logger.js.map +1 -1
  85. package/dist/esm/internal/runtimeFlags.js +1 -9
  86. package/dist/esm/internal/runtimeFlags.js.map +1 -1
  87. package/dist/esm/internal/tracer.js +0 -111
  88. package/dist/esm/internal/tracer.js.map +1 -1
  89. package/package.json +12 -1
  90. package/src/Config.ts +2 -2
  91. package/src/Effect.ts +8 -30
  92. package/src/FiberRef.ts +13 -0
  93. package/src/Layer.ts +0 -23
  94. package/src/RuntimeFlags.ts +0 -32
  95. package/src/SourceLocation.ts +108 -0
  96. package/src/Tracer.ts +0 -16
  97. package/src/index.ts +7 -0
  98. package/src/internal/config.ts +2 -2
  99. package/src/internal/core.ts +22 -106
  100. package/src/internal/effect/circular.ts +6 -16
  101. package/src/internal/fiberRuntime.ts +15 -88
  102. package/src/internal/layer/circular.ts +0 -14
  103. package/src/internal/layer.ts +0 -4
  104. package/src/internal/logger.ts +41 -4
  105. package/src/internal/runtimeFlags.ts +1 -11
  106. package/src/internal/tracer.ts +0 -143
@@ -1969,31 +1969,20 @@ export const all = <
1969
1969
  arg: Arg,
1970
1970
  options?: O
1971
1971
  ): Effect.All.Return<Arg, O> => {
1972
- // Capture stack trace early (while user code is on stack)
1973
- const rawStack = new Error().stack ?? ""
1974
-
1975
1972
  const [effects, reconcile] = allResolveInput(arg)
1976
- const count = Array.isArray(effects) ? effects.length : undefined
1977
-
1978
- let result: Effect.Effect<any, any, any>
1979
1973
 
1980
1974
  if (options?.mode === "validate") {
1981
- result = allValidate(effects, reconcile, options) as any
1975
+ return allValidate(effects, reconcile, options) as any
1982
1976
  } else if (options?.mode === "either") {
1983
- result = allEither(effects, reconcile, options) as any
1984
- } else {
1985
- result = options?.discard !== true && reconcile._tag === "Some"
1986
- ? core.map(
1987
- forEach(effects, identity, options as any),
1988
- reconcile.value
1989
- ) as any
1990
- : forEach(effects, identity, options as any) as any
1977
+ return allEither(effects, reconcile, options) as any
1991
1978
  }
1992
1979
 
1993
- // Set operation metadata in trace field for OpSupervision
1994
- ;(result as any).trace = core.makeOperationMeta("all", rawStack, count)
1995
-
1996
- return result as Effect.All.Return<Arg, O>
1980
+ return options?.discard !== true && reconcile._tag === "Some"
1981
+ ? core.map(
1982
+ forEach(effects, identity, options as any),
1983
+ reconcile.value
1984
+ ) as any
1985
+ : forEach(effects, identity, options as any) as any
1997
1986
  }
1998
1987
 
1999
1988
  /* @internal */
@@ -2136,12 +2125,8 @@ export const forEach: {
2136
2125
  readonly discard?: boolean | undefined
2137
2126
  readonly concurrentFinalizers?: boolean | undefined
2138
2127
  }
2139
- ) => {
2140
- // Capture stack trace early (while user code is on stack)
2141
- const rawStack = new Error().stack ?? ""
2142
- const count = Array.isArray(self) ? self.length : undefined
2143
-
2144
- const result = core.withFiberRuntime<A | void, E, R>((r) => {
2128
+ ) =>
2129
+ core.withFiberRuntime<A | void, E, R>((r) => {
2145
2130
  const isRequestBatchingEnabled = options?.batching === true ||
2146
2131
  (options?.batching === "inherit" && r.getFiberRef(core.currentRequestBatching))
2147
2132
 
@@ -2182,13 +2167,7 @@ export const forEach: {
2182
2167
  forEachParN(self, n, (a, i) => restore(f(a, i)), isRequestBatchingEnabled)
2183
2168
  )
2184
2169
  )
2185
- })
2186
-
2187
- // Set operation metadata in trace field for OpSupervision
2188
- ;(result as any).trace = core.makeOperationMeta("forEach", rawStack, count)
2189
-
2190
- return result
2191
- })
2170
+ }))
2192
2171
 
2193
2172
  /* @internal */
2194
2173
  export const forEachParUnbounded = <A, B, E, R>(
@@ -2418,34 +2397,12 @@ export const forEachParN = <A, B, E, R>(
2418
2397
  })
2419
2398
 
2420
2399
  /* @internal */
2421
- export const fork = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<Fiber.RuntimeFiber<A, E>, never, R> => {
2422
- // Capture stack trace immediately while user code is on stack
2423
- // Creating Error object is cheap; parsing is delayed until we know capture is enabled
2424
- const rawStack = new Error().stack ?? ""
2425
-
2426
- const result: Effect.Effect<Fiber.RuntimeFiber<A, E>, never, R> = core.withFiberRuntime((state, status) => {
2427
- // Check if capture is enabled, then parse the pre-captured stack if needed
2428
- const capturedLocation = state.getFiberRef(core.currentCaptureStackTraces) && rawStack
2429
- ? tracer.parseSourceLocationFromStack(rawStack)
2430
- : undefined
2431
-
2432
- const fiber = unsafeForkWithLocation(self, state, status.runtimeFlags, null, capturedLocation)
2433
- return core.succeed(fiber)
2434
- })
2435
-
2436
- // Set operation metadata in trace field for OpSupervision
2437
- ;(result as any).trace = core.makeOperationMeta("fork", rawStack, 1)
2438
-
2439
- return result
2440
- }
2400
+ export const fork = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<Fiber.RuntimeFiber<A, E>, never, R> =>
2401
+ core.withFiberRuntime((state, status) => core.succeed(unsafeFork(self, state, status.runtimeFlags)))
2441
2402
 
2442
2403
  /* @internal */
2443
- export const forkDaemon = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<Fiber.RuntimeFiber<A, E>, never, R> => {
2444
- const rawStack = new Error().stack ?? ""
2445
- const result = forkWithScopeOverride(self, fiberScope.globalScope)
2446
- ;(result as any).trace = core.makeOperationMeta("forkDaemon", rawStack, 1)
2447
- return result
2448
- }
2404
+ export const forkDaemon = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<Fiber.RuntimeFiber<A, E>, never, R> =>
2405
+ forkWithScopeOverride(self, fiberScope.globalScope)
2449
2406
 
2450
2407
  /* @internal */
2451
2408
  export const forkWithErrorHandler = dual<
@@ -2479,19 +2436,6 @@ export const unsafeFork = <A, E, R, E2, B>(
2479
2436
  return childFiber
2480
2437
  }
2481
2438
 
2482
- /** @internal */
2483
- export const unsafeForkWithLocation = <A, E, R, E2, B>(
2484
- effect: Effect.Effect<A, E, R>,
2485
- parentFiber: FiberRuntime<B, E2>,
2486
- parentRuntimeFlags: RuntimeFlags.RuntimeFlags,
2487
- overrideScope: fiberScope.FiberScope | null = null,
2488
- capturedLocation: tracer.SourceLocation | undefined = undefined
2489
- ): FiberRuntime<A, E> => {
2490
- const childFiber = unsafeMakeChildFiberWithLocation(effect, parentFiber, parentRuntimeFlags, overrideScope, capturedLocation)
2491
- childFiber.resume(effect)
2492
- return childFiber
2493
- }
2494
-
2495
2439
  /** @internal */
2496
2440
  export const unsafeForkUnstarted = <A, E, R, E2, B>(
2497
2441
  effect: Effect.Effect<A, E, R>,
@@ -2509,28 +2453,11 @@ export const unsafeMakeChildFiber = <A, E, R, E2, B>(
2509
2453
  parentFiber: FiberRuntime<B, E2>,
2510
2454
  parentRuntimeFlags: RuntimeFlags.RuntimeFlags,
2511
2455
  overrideScope: fiberScope.FiberScope | null = null
2512
- ): FiberRuntime<A, E> => {
2513
- return unsafeMakeChildFiberWithLocation(effect, parentFiber, parentRuntimeFlags, overrideScope, undefined)
2514
- }
2515
-
2516
- /** @internal */
2517
- export const unsafeMakeChildFiberWithLocation = <A, E, R, E2, B>(
2518
- effect: Effect.Effect<A, E, R>,
2519
- parentFiber: FiberRuntime<B, E2>,
2520
- parentRuntimeFlags: RuntimeFlags.RuntimeFlags,
2521
- overrideScope: fiberScope.FiberScope | null = null,
2522
- capturedLocation: tracer.SourceLocation | undefined = undefined
2523
2456
  ): FiberRuntime<A, E> => {
2524
2457
  const childId = FiberId.unsafeMake()
2525
2458
  const parentFiberRefs = parentFiber.getFiberRefs()
2526
2459
  const childFiberRefs = fiberRefs.forkAs(parentFiberRefs, childId)
2527
2460
  const childFiber = new FiberRuntime<A, E>(childId, childFiberRefs, parentRuntimeFlags)
2528
-
2529
- // Set pre-captured source location if enabled
2530
- if (capturedLocation && parentFiber.getFiberRef(core.currentCaptureStackTraces)) {
2531
- childFiber.setFiberRef(core.currentSourceLocation, capturedLocation)
2532
- }
2533
-
2534
2461
  const childContext = fiberRefs.getOrDefault(
2535
2462
  childFiberRefs,
2536
2463
  core.currentContext as unknown as FiberRef.FiberRef<Context.Context<R>>
@@ -131,13 +131,6 @@ export const enableOpSupervision: Layer.Layer<never> = layer.scopedDiscard(
131
131
  )
132
132
  )
133
133
 
134
- /** @internal */
135
- export const enableOperationTracing: Layer.Layer<never> = layer.scopedDiscard(
136
- fiberRuntime.withRuntimeFlagsScoped(
137
- runtimeFlagsPatch.enable(runtimeFlags.OperationTracing)
138
- )
139
- )
140
-
141
134
  /** @internal */
142
135
  export const enableRuntimeMetrics: Layer.Layer<never> = layer.scopedDiscard(
143
136
  fiberRuntime.withRuntimeFlagsScoped(
@@ -173,13 +166,6 @@ export const disableOpSupervision: Layer.Layer<never> = layer.scopedDiscard(
173
166
  )
174
167
  )
175
168
 
176
- /** @internal */
177
- export const disableOperationTracing: Layer.Layer<never> = layer.scopedDiscard(
178
- fiberRuntime.withRuntimeFlagsScoped(
179
- runtimeFlagsPatch.disable(runtimeFlags.OperationTracing)
180
- )
181
- )
182
-
183
169
  /** @internal */
184
170
  export const disableRuntimeMetrics: Layer.Layer<never> = layer.scopedDiscard(
185
171
  fiberRuntime.withRuntimeFlagsScoped(
@@ -963,10 +963,6 @@ export const scopedContext = <A, E, R>(
963
963
  return scoped
964
964
  }
965
965
 
966
- /** @internal */
967
- export const enableSourceCapture: Layer.Layer<never> =
968
- fiberRefLocallyScoped(core.currentCaptureStackTraces, true)
969
-
970
966
  /** @internal */
971
967
  export const scope: Layer.Layer<Scope.Scope> = scopedContext(
972
968
  core.map(
@@ -11,7 +11,9 @@ import type * as Logger from "../Logger.js"
11
11
  import type * as LogLevel from "../LogLevel.js"
12
12
  import * as Option from "../Option.js"
13
13
  import { pipeArguments } from "../Pipeable.js"
14
+ import * as SourceLocation from "../SourceLocation.js"
14
15
  import * as Cause from "./cause.js"
16
+ import * as core from "./core.js"
15
17
  import * as defaultServices from "./defaultServices.js"
16
18
  import { consoleTag } from "./defaultServices/console.js"
17
19
  import * as fiberId_ from "./fiberId.js"
@@ -178,7 +180,7 @@ const textOnly = /^[^\s"=]*$/
178
180
  */
179
181
  const format = (quoteValue: (s: string) => string, whitespace?: number | string | undefined) =>
180
182
  (
181
- { annotations, cause, date, fiberId, logLevel, message, spans }: Logger.Logger.Options<unknown>
183
+ { annotations, cause, context, date, fiberId, logLevel, message, spans }: Logger.Logger.Options<unknown>
182
184
  ): string => {
183
185
  const formatValue = (value: string): string => value.match(textOnly) ? value : quoteValue(value)
184
186
  const format = (label: string, value: string): string => `${logSpan_.formatLabel(label)}=${formatValue(value)}`
@@ -188,6 +190,12 @@ const format = (quoteValue: (s: string) => string, whitespace?: number | string
188
190
  out += append("level", logLevel.label)
189
191
  out += append("fiber", fiberId_.threadName(fiberId))
190
192
 
193
+ // Include source trace if available
194
+ const sourceTrace = FiberRefs.getOrDefault(context, core.currentSourceTrace)
195
+ if (sourceTrace !== undefined) {
196
+ out += append("source", SourceLocation.format(sourceTrace))
197
+ }
198
+
191
199
  const messages = Arr.ensure(message)
192
200
  for (let i = 0; i < messages.length; i++) {
193
201
  out += append("message", Inspectable.toStringUnknown(messages[i], whitespace))
@@ -226,8 +234,11 @@ export const structuredLogger = makeLogger<unknown, {
226
234
  readonly cause: string | undefined
227
235
  readonly annotations: Record<string, unknown>
228
236
  readonly spans: Record<string, number>
237
+ readonly source:
238
+ | { readonly path: string; readonly line: number; readonly column: number; readonly label?: string }
239
+ | undefined
229
240
  }>(
230
- ({ annotations, cause, date, fiberId, logLevel, message, spans }) => {
241
+ ({ annotations, cause, context, date, fiberId, logLevel, message, spans }) => {
231
242
  const now = date.getTime()
232
243
  const annotationsObj: Record<string, unknown> = {}
233
244
  const spansObj: Record<string, number> = {}
@@ -245,15 +256,41 @@ export const structuredLogger = makeLogger<unknown, {
245
256
  }
246
257
 
247
258
  const messageArr = Arr.ensure(message)
248
- return {
259
+ const sourceTrace = FiberRefs.getOrDefault(context, core.currentSourceTrace)
260
+
261
+ const result: {
262
+ message: unknown
263
+ logLevel: string
264
+ timestamp: string
265
+ cause: string | undefined
266
+ annotations: Record<string, unknown>
267
+ spans: Record<string, number>
268
+ fiberId: string
269
+ source: { path: string; line: number; column: number; label?: string } | undefined
270
+ } = {
249
271
  message: messageArr.length === 1 ? structuredMessage(messageArr[0]) : messageArr.map(structuredMessage),
250
272
  logLevel: logLevel.label,
251
273
  timestamp: date.toISOString(),
252
274
  cause: Cause.isEmpty(cause) ? undefined : Cause.pretty(cause, { renderErrorCause: true }),
253
275
  annotations: annotationsObj,
254
276
  spans: spansObj,
255
- fiberId: fiberId_.threadName(fiberId)
277
+ fiberId: fiberId_.threadName(fiberId),
278
+ source: undefined
256
279
  }
280
+
281
+ if (sourceTrace !== undefined) {
282
+ const sourceObj: { path: string; line: number; column: number; label?: string } = {
283
+ path: sourceTrace.path,
284
+ line: sourceTrace.line,
285
+ column: sourceTrace.column
286
+ }
287
+ if (sourceTrace.label !== undefined) {
288
+ sourceObj.label = sourceTrace.label
289
+ }
290
+ result.source = sourceObj
291
+ }
292
+
293
+ return result
257
294
  }
258
295
  )
259
296
 
@@ -23,9 +23,6 @@ export const WindDown: RuntimeFlags.RuntimeFlag = 1 << 4 as RuntimeFlags.Runtime
23
23
  /** @internal */
24
24
  export const CooperativeYielding: RuntimeFlags.RuntimeFlag = 1 << 5 as RuntimeFlags.RuntimeFlag
25
25
 
26
- /** @internal */
27
- export const OperationTracing: RuntimeFlags.RuntimeFlag = 1 << 6 as RuntimeFlags.RuntimeFlag
28
-
29
26
  /** @internal */
30
27
  export const allFlags: ReadonlyArray<RuntimeFlags.RuntimeFlag> = [
31
28
  None,
@@ -33,8 +30,7 @@ export const allFlags: ReadonlyArray<RuntimeFlags.RuntimeFlag> = [
33
30
  OpSupervision,
34
31
  RuntimeMetrics,
35
32
  WindDown,
36
- CooperativeYielding,
37
- OperationTracing
33
+ CooperativeYielding
38
34
  ]
39
35
 
40
36
  const print = (flag: RuntimeFlags.RuntimeFlag) => {
@@ -51,9 +47,6 @@ const print = (flag: RuntimeFlags.RuntimeFlag) => {
51
47
  case OpSupervision: {
52
48
  return "OpSupervision"
53
49
  }
54
- case OperationTracing: {
55
- return "OperationTracing"
56
- }
57
50
  case Interruption: {
58
51
  return "Interruption"
59
52
  }
@@ -118,9 +111,6 @@ export const none: RuntimeFlags.RuntimeFlags = make(None)
118
111
  /** @internal */
119
112
  export const opSupervision = (self: RuntimeFlags.RuntimeFlags): boolean => isEnabled(self, OpSupervision)
120
113
 
121
- /** @internal */
122
- export const operationTracing = (self: RuntimeFlags.RuntimeFlags): boolean => isEnabled(self, OperationTracing)
123
-
124
114
  /** @internal */
125
115
  export const render = (self: RuntimeFlags.RuntimeFlags): string => {
126
116
  const active: Array<string> = []
@@ -3,12 +3,9 @@
3
3
  */
4
4
  import * as Context from "../Context.js"
5
5
  import type * as Exit from "../Exit.js"
6
- import type * as FiberRef from "../FiberRef.js"
7
6
  import { constFalse } from "../Function.js"
8
- import { globalValue } from "../GlobalValue.js"
9
7
  import type * as Option from "../Option.js"
10
8
  import type * as Tracer from "../Tracer.js"
11
- import * as core from "./core.js"
12
9
 
13
10
  /** @internal */
14
11
  export const TracerTypeId: Tracer.TracerTypeId = Symbol.for("effect/Tracer") as Tracer.TracerTypeId
@@ -151,143 +148,3 @@ export const addSpanStackTrace = (options: Tracer.SpanOptions | undefined): Trac
151
148
  export const DisablePropagation = Context.Reference<Tracer.DisablePropagation>()("effect/Tracer/DisablePropagation", {
152
149
  defaultValue: constFalse
153
150
  })
154
-
155
- // -----------------------------------------------------------------------------
156
- // Source Location Capture
157
- // -----------------------------------------------------------------------------
158
-
159
- /**
160
- * Represents a source code location captured from a stack trace.
161
- * @internal
162
- */
163
- export interface SourceLocation {
164
- readonly file: string
165
- readonly line: number
166
- readonly column: number
167
- readonly functionName?: string
168
- }
169
-
170
- // Cache for source locations: raw frame string -> SourceLocation
171
- // Maximum cache size to prevent unbounded memory growth in long-running services
172
- const MAX_SOURCE_LOCATION_CACHE_SIZE = 1000
173
- const sourceLocationCache = new Map<string, SourceLocation>()
174
-
175
- /**
176
- * Evicts the oldest cache entry if at capacity (FIFO eviction).
177
- * Maps maintain insertion order, so the first key is the oldest.
178
- * @internal
179
- */
180
- const evictOldestCacheEntry = (): void => {
181
- if (sourceLocationCache.size >= MAX_SOURCE_LOCATION_CACHE_SIZE) {
182
- const firstKey = sourceLocationCache.keys().next().value
183
- if (firstKey !== undefined) {
184
- sourceLocationCache.delete(firstKey)
185
- }
186
- }
187
- }
188
-
189
- /**
190
- * Parses source location from a pre-captured stack trace string with caching.
191
- * This is used when the stack was captured earlier (while user code was on stack)
192
- * but parsing is delayed until we know capture is enabled.
193
- *
194
- * @internal
195
- */
196
- export const parseSourceLocationFromStack = (stack: string): SourceLocation | undefined => {
197
- const lines = stack.split("\n")
198
- // Find first non-internal frame (skip Error, fork, unsafeMakeChildFiber, etc.)
199
- const userFrame = findUserFrame(lines)
200
- if (!userFrame) return undefined
201
-
202
- const cacheKey = userFrame.raw // Use raw frame string as key
203
-
204
- const cached = sourceLocationCache.get(cacheKey)
205
- if (cached) return cached
206
-
207
- const parsed = parseStackFrame(userFrame.raw)
208
- if (parsed) {
209
- evictOldestCacheEntry() // Ensure cache doesn't grow unbounded
210
- sourceLocationCache.set(cacheKey, parsed)
211
- }
212
- return parsed
213
- }
214
-
215
- /**
216
- * Captures the source location from the current stack trace with caching.
217
- * Uses the raw stack frame string as the cache key for fast lookups.
218
- *
219
- * Note: Uses the current Error.stackTraceLimit value (typically 10-15).
220
- * If capturing deeply nested call sites, configure Error.stackTraceLimit
221
- * globally before importing Effect (e.g., Error.stackTraceLimit = 25).
222
- *
223
- * @internal
224
- */
225
- export const captureSourceLocationCached = (): SourceLocation | undefined => {
226
- const traceError = new Error()
227
- if (!traceError.stack) return undefined
228
- return parseSourceLocationFromStack(traceError.stack)
229
- }
230
-
231
- const findUserFrame = (stack: Array<string>): { raw: string; index: number } | undefined => {
232
- // Skip frames from Effect internals
233
- for (let i = 1; i < stack.length; i++) {
234
- const frame = stack[i]
235
- if (
236
- frame &&
237
- !isInternalFrame(frame)
238
- ) {
239
- return { raw: frame.trim(), index: i }
240
- }
241
- }
242
- return undefined
243
- }
244
-
245
- const isInternalFrame = (frame: string): boolean => {
246
- // Skip internal directories
247
- if (frame.includes("/internal/")) return true
248
- // Skip Effect core source files
249
- if (frame.includes("/packages/effect/src/")) return true
250
- if (frame.includes("/effect/dist/")) return true
251
- // Skip node_modules (for published effect packages)
252
- if (frame.includes("node_modules/effect/")) return true
253
- if (frame.includes("node_modules/@effect/")) return true
254
- // Skip specific internal functions
255
- if (frame.includes("fiberRuntime")) return true
256
- if (frame.includes("captureSourceLocation")) return true
257
- if (frame.includes("effect_internal_function")) return true
258
- return false
259
- }
260
-
261
- const parseStackFrame = (frame: string): SourceLocation | undefined => {
262
- // Parse "at functionName (file:line:col)" or "at file:line:col"
263
- const match = frame.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?/)
264
- if (!match) return undefined
265
-
266
- return {
267
- functionName: match[1],
268
- file: match[2],
269
- line: parseInt(match[3], 10),
270
- column: parseInt(match[4], 10)
271
- }
272
- }
273
-
274
- // -----------------------------------------------------------------------------
275
- // OTel Context Propagation
276
- // -----------------------------------------------------------------------------
277
-
278
- /**
279
- * FiberRef for propagating OpenTelemetry span context through Effect's fiber hierarchy.
280
- *
281
- * When fibers are forked, they inherit this FiberRef's value from their parent.
282
- * This allows supervisors to maintain correct parent-child span relationships
283
- * even when the OTel AsyncLocalStorage context is lost due to Effect's fiber scheduler.
284
- *
285
- * The value is typed as `unknown` to avoid a direct dependency on @opentelemetry/api.
286
- * Consumers should cast to `OtelApi.Context` when using.
287
- *
288
- * @internal
289
- */
290
- export const currentOtelSpanContext: FiberRef.FiberRef<unknown> = globalValue(
291
- "effect/Tracer/currentOtelSpanContext",
292
- () => core.fiberRefUnsafeMake<unknown>(undefined)
293
- )