effect 3.1.5 → 3.2.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 (115) hide show
  1. package/dist/cjs/Array.js +139 -2
  2. package/dist/cjs/Array.js.map +1 -1
  3. package/dist/cjs/Cause.js +8 -1
  4. package/dist/cjs/Cause.js.map +1 -1
  5. package/dist/cjs/Chunk.js +18 -1
  6. package/dist/cjs/Chunk.js.map +1 -1
  7. package/dist/cjs/Config.js.map +1 -1
  8. package/dist/cjs/Data.js +11 -8
  9. package/dist/cjs/Data.js.map +1 -1
  10. package/dist/cjs/Effect.js +106 -18
  11. package/dist/cjs/Effect.js.map +1 -1
  12. package/dist/cjs/Stream.js +19 -1
  13. package/dist/cjs/Stream.js.map +1 -1
  14. package/dist/cjs/Tracer.js.map +1 -1
  15. package/dist/cjs/internal/cause.js +55 -48
  16. package/dist/cjs/internal/cause.js.map +1 -1
  17. package/dist/cjs/internal/channel.js +11 -1
  18. package/dist/cjs/internal/channel.js.map +1 -1
  19. package/dist/cjs/internal/core-effect.js +51 -9
  20. package/dist/cjs/internal/core-effect.js.map +1 -1
  21. package/dist/cjs/internal/core.js +8 -4
  22. package/dist/cjs/internal/core.js.map +1 -1
  23. package/dist/cjs/internal/fiberRuntime.js +27 -14
  24. package/dist/cjs/internal/fiberRuntime.js.map +1 -1
  25. package/dist/cjs/internal/layer/circular.js +4 -1
  26. package/dist/cjs/internal/layer/circular.js.map +1 -1
  27. package/dist/cjs/internal/layer.js +11 -1
  28. package/dist/cjs/internal/layer.js.map +1 -1
  29. package/dist/cjs/internal/runtime.js +9 -4
  30. package/dist/cjs/internal/runtime.js.map +1 -1
  31. package/dist/cjs/internal/schedule.js +2 -2
  32. package/dist/cjs/internal/schedule.js.map +1 -1
  33. package/dist/cjs/internal/stream.js +27 -9
  34. package/dist/cjs/internal/stream.js.map +1 -1
  35. package/dist/cjs/internal/tracer.js +31 -1
  36. package/dist/cjs/internal/tracer.js.map +1 -1
  37. package/dist/cjs/internal/version.js +1 -1
  38. package/dist/dts/Array.d.ts +199 -0
  39. package/dist/dts/Array.d.ts.map +1 -1
  40. package/dist/dts/Cause.d.ts +15 -0
  41. package/dist/dts/Cause.d.ts.map +1 -1
  42. package/dist/dts/Chunk.d.ts +20 -0
  43. package/dist/dts/Chunk.d.ts.map +1 -1
  44. package/dist/dts/Config.d.ts +6 -2
  45. package/dist/dts/Config.d.ts.map +1 -1
  46. package/dist/dts/Data.d.ts +46 -13
  47. package/dist/dts/Data.d.ts.map +1 -1
  48. package/dist/dts/Effect.d.ts +122 -15
  49. package/dist/dts/Effect.d.ts.map +1 -1
  50. package/dist/dts/Stream.d.ts +23 -1
  51. package/dist/dts/Stream.d.ts.map +1 -1
  52. package/dist/dts/Tracer.d.ts +1 -0
  53. package/dist/dts/Tracer.d.ts.map +1 -1
  54. package/dist/dts/internal/core-effect.d.ts +7 -1
  55. package/dist/dts/internal/core-effect.d.ts.map +1 -1
  56. package/dist/dts/internal/core.d.ts.map +1 -1
  57. package/dist/dts/internal/stream.d.ts.map +1 -1
  58. package/dist/esm/Array.js +182 -0
  59. package/dist/esm/Array.js.map +1 -1
  60. package/dist/esm/Cause.js +7 -0
  61. package/dist/esm/Cause.js.map +1 -1
  62. package/dist/esm/Chunk.js +16 -0
  63. package/dist/esm/Chunk.js.map +1 -1
  64. package/dist/esm/Config.js.map +1 -1
  65. package/dist/esm/Data.js +11 -8
  66. package/dist/esm/Data.js.map +1 -1
  67. package/dist/esm/Effect.js +103 -15
  68. package/dist/esm/Effect.js.map +1 -1
  69. package/dist/esm/Stream.js +18 -0
  70. package/dist/esm/Stream.js.map +1 -1
  71. package/dist/esm/Tracer.js.map +1 -1
  72. package/dist/esm/internal/cause.js +54 -47
  73. package/dist/esm/internal/cause.js.map +1 -1
  74. package/dist/esm/internal/channel.js +10 -1
  75. package/dist/esm/internal/channel.js.map +1 -1
  76. package/dist/esm/internal/core-effect.js +47 -7
  77. package/dist/esm/internal/core-effect.js.map +1 -1
  78. package/dist/esm/internal/core.js +7 -3
  79. package/dist/esm/internal/core.js.map +1 -1
  80. package/dist/esm/internal/fiberRuntime.js +26 -14
  81. package/dist/esm/internal/fiberRuntime.js.map +1 -1
  82. package/dist/esm/internal/layer/circular.js +4 -1
  83. package/dist/esm/internal/layer/circular.js.map +1 -1
  84. package/dist/esm/internal/layer.js +10 -1
  85. package/dist/esm/internal/layer.js.map +1 -1
  86. package/dist/esm/internal/runtime.js +9 -4
  87. package/dist/esm/internal/runtime.js.map +1 -1
  88. package/dist/esm/internal/schedule.js +2 -2
  89. package/dist/esm/internal/schedule.js.map +1 -1
  90. package/dist/esm/internal/stream.js +23 -7
  91. package/dist/esm/internal/stream.js.map +1 -1
  92. package/dist/esm/internal/tracer.js +29 -0
  93. package/dist/esm/internal/tracer.js.map +1 -1
  94. package/dist/esm/internal/version.js +1 -1
  95. package/package.json +1 -1
  96. package/src/Array.ts +214 -0
  97. package/src/Cause.ts +17 -0
  98. package/src/Chunk.ts +30 -0
  99. package/src/Config.ts +8 -6
  100. package/src/Data.ts +121 -48
  101. package/src/Effect.ts +126 -15
  102. package/src/Stream.ts +31 -1
  103. package/src/Tracer.ts +1 -0
  104. package/src/internal/cause.ts +70 -52
  105. package/src/internal/channel.ts +32 -14
  106. package/src/internal/core-effect.ts +74 -25
  107. package/src/internal/core.ts +8 -3
  108. package/src/internal/fiberRuntime.ts +22 -11
  109. package/src/internal/layer/circular.ts +4 -2
  110. package/src/internal/layer.ts +37 -14
  111. package/src/internal/runtime.ts +10 -5
  112. package/src/internal/schedule.ts +2 -2
  113. package/src/internal/stream.ts +37 -13
  114. package/src/internal/tracer.ts +21 -0
  115. package/src/internal/version.ts +1 -1
package/src/Effect.ts CHANGED
@@ -4130,11 +4130,44 @@ export declare namespace Repeat {
4130
4130
  }
4131
4131
 
4132
4132
  /**
4133
- * Returns a new effect that repeats this effect according to the specified
4134
- * schedule or until the first failure. Scheduled recurrences are in addition
4135
- * to the first execution, so that `io.repeat(Schedule.once)` yields an effect
4136
- * that executes `io`, and then if that succeeds, executes `io` an additional
4137
- * time.
4133
+ * The `repeat` function returns a new effect that repeats the given effect
4134
+ * according to a specified schedule or until the first failure. The scheduled
4135
+ * recurrences are in addition to the initial execution, so `Effect.repeat(action,
4136
+ * Schedule.once)` executes `action` once initially, and if it succeeds, repeats it
4137
+ * an additional time.
4138
+ *
4139
+ * @example
4140
+ * // Success Example
4141
+ * import { Effect, Schedule, Console } from "effect"
4142
+ *
4143
+ * const action = Console.log("success")
4144
+ * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis")
4145
+ * const program = Effect.repeat(action, policy)
4146
+ *
4147
+ * Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`))
4148
+ *
4149
+ * @example
4150
+ * // Failure Example
4151
+ * import { Effect, Schedule } from "effect"
4152
+ *
4153
+ * let count = 0
4154
+ *
4155
+ * // Define an async effect that simulates an action with possible failures
4156
+ * const action = Effect.async<string, string>((resume) => {
4157
+ * if (count > 1) {
4158
+ * console.log("failure")
4159
+ * resume(Effect.fail("Uh oh!"))
4160
+ * } else {
4161
+ * count++
4162
+ * console.log("success")
4163
+ * resume(Effect.succeed("yay!"))
4164
+ * }
4165
+ * })
4166
+ *
4167
+ * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis")
4168
+ * const program = Effect.repeat(action, policy)
4169
+ *
4170
+ * Effect.runPromiseExit(program).then(console.log)
4138
4171
  *
4139
4172
  * @since 2.0.0
4140
4173
  * @category repetition / recursion
@@ -4156,10 +4189,18 @@ export const repeat: {
4156
4189
  } = _schedule.repeat_combined
4157
4190
 
4158
4191
  /**
4159
- * Returns a new effect that repeats this effect the specified number of times
4160
- * or until the first failure. Repeats are in addition to the first execution,
4161
- * so that `io.repeatN(1)` yields an effect that executes `io`, and then if
4162
- * that succeeds, executes `io` an additional time.
4192
+ * The `repeatN` function returns a new effect that repeats the specified effect a
4193
+ * given number of times or until the first failure. The repeats are in addition
4194
+ * to the initial execution, so `Effect.repeatN(action, 1)` executes `action` once
4195
+ * initially and then repeats it one additional time if it succeeds.
4196
+ *
4197
+ * @example
4198
+ * import { Effect, Console } from "effect"
4199
+ *
4200
+ * const action = Console.log("success")
4201
+ * const program = Effect.repeatN(action, 2)
4202
+ *
4203
+ * Effect.runPromise(program)
4163
4204
  *
4164
4205
  * @since 2.0.0
4165
4206
  * @category repetition / recursion
@@ -4170,13 +4211,43 @@ export const repeatN: {
4170
4211
  } = effect.repeatN
4171
4212
 
4172
4213
  /**
4173
- * Returns a new effect that repeats this effect according to the specified
4174
- * schedule or until the first failure, at which point, the failure value and
4175
- * schedule output are passed to the specified handler.
4214
+ * The `repeatOrElse` function returns a new effect that repeats the specified
4215
+ * effect according to the given schedule or until the first failure. When a
4216
+ * failure occurs, the failure value and schedule output are passed to a
4217
+ * specified handler. Scheduled recurrences are in addition to the initial
4218
+ * execution, so `Effect.repeat(action, Schedule.once)` executes `action` once
4219
+ * initially and then repeats it an additional time if it succeeds.
4220
+ *
4221
+ * @example
4222
+ * import { Effect, Schedule } from "effect"
4223
+ *
4224
+ * let count = 0
4225
+ *
4226
+ * // Define an async effect that simulates an action with possible failures
4227
+ * const action = Effect.async<string, string>((resume) => {
4228
+ * if (count > 1) {
4229
+ * console.log("failure")
4230
+ * resume(Effect.fail("Uh oh!"))
4231
+ * } else {
4232
+ * count++
4233
+ * console.log("success")
4234
+ * resume(Effect.succeed("yay!"))
4235
+ * }
4236
+ * })
4237
+ *
4238
+ * const policy = Schedule.addDelay(
4239
+ * Schedule.recurs(2), // Repeat for a maximum of 2 times
4240
+ * () => "100 millis" // Add a delay of 100 milliseconds between repetitions
4241
+ * )
4176
4242
  *
4177
- * Scheduled recurrences are in addition to the first execution, so that
4178
- * `pipe(effect, Effect.repeat(Schedule.once()))` yields an effect that executes
4179
- * `effect`, and then if that succeeds, executes `effect` an additional time.
4243
+ * const program = Effect.repeatOrElse(action, policy, () =>
4244
+ * Effect.sync(() => {
4245
+ * console.log("orElse")
4246
+ * return count - 1
4247
+ * })
4248
+ * )
4249
+ *
4250
+ * Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`))
4180
4251
  *
4181
4252
  * @since 2.0.0
4182
4253
  * @category repetition / recursion
@@ -5364,6 +5435,46 @@ export const withSpan: {
5364
5435
  ): Effect<A, E, Exclude<R, Tracer.ParentSpan>>
5365
5436
  } = effect.withSpan
5366
5437
 
5438
+ /**
5439
+ * Wraps a function that returns an effect with a new span for tracing.
5440
+ *
5441
+ * @since 3.2.0
5442
+ * @category models
5443
+ */
5444
+ export interface FunctionWithSpanOptions {
5445
+ readonly name: string
5446
+ readonly attributes?: Record<string, unknown> | undefined
5447
+ readonly links?: ReadonlyArray<Tracer.SpanLink> | undefined
5448
+ readonly parent?: Tracer.AnySpan | undefined
5449
+ readonly root?: boolean | undefined
5450
+ readonly context?: Context.Context<never> | undefined
5451
+ readonly kind?: Tracer.SpanKind | undefined
5452
+ }
5453
+
5454
+ /**
5455
+ * Wraps a function that returns an effect with a new span for tracing.
5456
+ *
5457
+ * @since 3.2.0
5458
+ * @category tracing
5459
+ * @example
5460
+ * import { Effect } from "effect"
5461
+ *
5462
+ * const getTodo = Effect.functionWithSpan({
5463
+ * body: (id: number) => Effect.succeed(`Got todo ${id}!`),
5464
+ * options: (id) => ({
5465
+ * name: `getTodo-${id}`,
5466
+ * attributes: { id }
5467
+ * })
5468
+ * })
5469
+ */
5470
+ export const functionWithSpan: <Args extends Array<any>, Ret extends Effect<any, any, any>>(
5471
+ options: {
5472
+ readonly body: (...args: Args) => Ret
5473
+ readonly options: FunctionWithSpanOptions | ((...args: Args) => FunctionWithSpanOptions)
5474
+ readonly captureStackTrace?: boolean | undefined
5475
+ }
5476
+ ) => (...args: Args) => Unify.Unify<Ret> = effect.functionWithSpan
5477
+
5367
5478
  /**
5368
5479
  * Wraps the effect with a new span for tracing.
5369
5480
  *
package/src/Stream.ts CHANGED
@@ -22,6 +22,7 @@ import type { Pipeable } from "./Pipeable.js"
22
22
  import type { Predicate, Refinement } from "./Predicate.js"
23
23
  import type * as PubSub from "./PubSub.js"
24
24
  import type * as Queue from "./Queue.js"
25
+ import type { Runtime } from "./Runtime.js"
25
26
  import type * as Schedule from "./Schedule.js"
26
27
  import type * as Scope from "./Scope.js"
27
28
  import type * as Sink from "./Sink.js"
@@ -3859,7 +3860,36 @@ export const toQueueOfElements: {
3859
3860
  * @since 2.0.0
3860
3861
  * @category destructors
3861
3862
  */
3862
- export const toReadableStream: <A, E>(source: Stream<A, E>) => ReadableStream<A> = internal.toReadableStream
3863
+ export const toReadableStream: <A, E>(self: Stream<A, E>) => ReadableStream<A> = internal.toReadableStream
3864
+
3865
+ /**
3866
+ * Converts the stream to a `Effect<ReadableStream>`.
3867
+ *
3868
+ * See https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream.
3869
+ *
3870
+ * @since 2.0.0
3871
+ * @category destructors
3872
+ */
3873
+ export const toReadableStreamEffect: <A, E, R>(self: Stream<A, E, R>) => Effect.Effect<ReadableStream<A>, never, R> =
3874
+ internal.toReadableStreamEffect
3875
+
3876
+ /**
3877
+ * Converts the stream to a `ReadableStream` using the provided runtime.
3878
+ *
3879
+ * See https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream.
3880
+ *
3881
+ * @since 2.0.0
3882
+ * @category destructors
3883
+ */
3884
+ export const toReadableStreamRuntime: {
3885
+ <XR>(
3886
+ runtime: Runtime<XR>
3887
+ ): <A, E, R extends XR>(self: Stream<A, E, R>) => ReadableStream<A>
3888
+ <A, E, XR, R extends XR>(
3889
+ self: Stream<A, E, R>,
3890
+ runtime: Runtime<XR>
3891
+ ): ReadableStream<A>
3892
+ } = internal.toReadableStreamRuntime
3863
3893
 
3864
3894
  /**
3865
3895
  * Applies the transducer to the stream and emits its outputs.
package/src/Tracer.ts CHANGED
@@ -92,6 +92,7 @@ export interface SpanOptions {
92
92
  readonly root?: boolean | undefined
93
93
  readonly context?: Context.Context<never> | undefined
94
94
  readonly kind?: SpanKind | undefined
95
+ readonly captureStackTrace?: boolean | string | undefined
95
96
  }
96
97
 
97
98
  /**
@@ -10,8 +10,8 @@ import * as HashSet from "../HashSet.js"
10
10
  import { NodeInspectSymbol, toJSON } from "../Inspectable.js"
11
11
  import * as Option from "../Option.js"
12
12
  import { pipeArguments } from "../Pipeable.js"
13
- import { hasProperty, isFunction } from "../Predicate.js"
14
13
  import type { Predicate, Refinement } from "../Predicate.js"
14
+ import { hasProperty, isFunction } from "../Predicate.js"
15
15
  import type { AnySpan, Span } from "../Tracer.js"
16
16
  import type { NoInfer } from "../Types.js"
17
17
  import { getBugErrorMessage } from "./errors.js"
@@ -968,53 +968,45 @@ export const reduceWithContext = dual<
968
968
  // Pretty Printing
969
969
  // -----------------------------------------------------------------------------
970
970
 
971
- const filterStack = (stack: string) => {
972
- const lines = stack.split("\n")
973
- const out: Array<string> = []
974
- for (let i = 0; i < lines.length; i++) {
975
- out.push(lines[i].replace(/at .*effect_instruction_i.*\((.*)\)/, "at $1"))
976
- if (lines[i].includes("effect_instruction_i")) {
977
- return out.join("\n")
978
- }
979
- }
980
- return out.join("\n")
981
- }
982
-
983
971
  /** @internal */
984
972
  export const pretty = <E>(cause: Cause.Cause<E>): string => {
985
973
  if (isInterruptedOnly(cause)) {
986
974
  return "All fibers interrupted without errors."
987
975
  }
988
- const final = prettyErrors<E>(cause).map((e) => {
989
- let message = e.message
990
- if (e.stack) {
991
- message += `\r\n${filterStack(e.stack)}`
992
- }
993
- if (e.span) {
994
- let current: Span | AnySpan | undefined = e.span
995
- let i = 0
996
- while (current && current._tag === "Span" && i < 10) {
997
- message += `\r\n at ${current.name}`
998
- current = Option.getOrUndefined(current.parent)
999
- i++
976
+ return prettyErrors<E>(cause).map((e) => e.stack).join("\n")
977
+ }
978
+
979
+ class PrettyError extends globalThis.Error implements Cause.PrettyError {
980
+ span: undefined | Span = undefined
981
+ constructor(originalError: unknown) {
982
+ const prevLimit = Error.stackTraceLimit
983
+ Error.stackTraceLimit = 0
984
+ super(prettyErrorMessage(originalError))
985
+ Error.stackTraceLimit = prevLimit
986
+
987
+ this.name = originalError instanceof Error ? originalError.name : "Error"
988
+ if (typeof originalError === "object" && originalError !== null) {
989
+ if (spanSymbol in originalError) {
990
+ this.span = originalError[spanSymbol] as Span
1000
991
  }
992
+ Object.keys(originalError).forEach((key) => {
993
+ if (!(key in this)) {
994
+ // @ts-expect-error
995
+ this[key] = originalError[key]
996
+ }
997
+ })
1001
998
  }
1002
- return message
1003
- }).join("\r\n")
1004
- return final
1005
- }
999
+ this.stack = prettyErrorStack(
1000
+ this.message,
1001
+ originalError instanceof Error && originalError.stack
1002
+ ? originalError.stack
1003
+ : "",
1004
+ this.span
1005
+ )
1006
+ }
1006
1007
 
1007
- class PrettyError {
1008
- constructor(
1009
- readonly message: string,
1010
- readonly stack: string | undefined,
1011
- readonly span: Span | undefined
1012
- ) {}
1013
1008
  toJSON() {
1014
- const out: any = { message: this.message }
1015
- if (this.stack) {
1016
- out.stack = this.stack
1017
- }
1009
+ const out: any = { message: this.message, stack: this.stack }
1018
1010
  if (this.span) {
1019
1011
  out.span = this.span
1020
1012
  }
@@ -1058,29 +1050,55 @@ export const prettyErrorMessage = (u: unknown): string => {
1058
1050
  return `Error: ${JSON.stringify(u)}`
1059
1051
  }
1060
1052
 
1061
- const spanSymbol = Symbol.for("effect/SpanAnnotation")
1053
+ const locationRegex = /\((.*)\)/
1054
+
1055
+ const prettyErrorStack = (message: string, stack: string, span?: Span | undefined): string => {
1056
+ const out: Array<string> = [message]
1057
+ const lines = stack.split("\n")
1062
1058
 
1063
- const defaultRenderError = (error: unknown): PrettyError => {
1064
- const span: any = hasProperty(error, spanSymbol) && error[spanSymbol]
1065
- if (error instanceof Error) {
1066
- return new PrettyError(
1067
- prettyErrorMessage(error),
1068
- error.stack?.split("\n").filter((_) => _.match(/at (.*)/)).join("\n"),
1069
- span
1059
+ for (let i = 1; i < lines.length; i++) {
1060
+ if (lines[i].includes("effect_cutpoint") || lines[i].includes("Generator.next")) {
1061
+ break
1062
+ }
1063
+ out.push(
1064
+ lines[i].replace(/at .*effect_instruction_i.*\((.*)\)/, "at $1").replace(/EffectPrimitive\.\w+/, "<anonymous>")
1070
1065
  )
1066
+ if (lines[i].includes("effect_instruction_i")) {
1067
+ break
1068
+ }
1071
1069
  }
1072
- return new PrettyError(prettyErrorMessage(error), void 0, span)
1070
+
1071
+ if (span) {
1072
+ let current: Span | AnySpan | undefined = span
1073
+ let i = 0
1074
+ while (current && current._tag === "Span" && i < 10) {
1075
+ const stack = current.attributes.get("code.stacktrace")
1076
+ if (typeof stack === "string") {
1077
+ const locationMatch = stack.match(locationRegex)
1078
+ const location = locationMatch ? locationMatch[1] : stack.replace(/^at /, "")
1079
+ out.push(` at ${current.name} (${location})`)
1080
+ } else {
1081
+ out.push(` at ${current.name}`)
1082
+ }
1083
+ current = Option.getOrUndefined(current.parent)
1084
+ i++
1085
+ }
1086
+ }
1087
+
1088
+ return out.join("\n")
1073
1089
  }
1074
1090
 
1091
+ const spanSymbol = Symbol.for("effect/SpanAnnotation")
1092
+
1075
1093
  /** @internal */
1076
- export const prettyErrors = <E>(cause: Cause.Cause<E>): ReadonlyArray<PrettyError> =>
1094
+ export const prettyErrors = <E>(cause: Cause.Cause<E>): Array<PrettyError> =>
1077
1095
  reduceWithContext(cause, void 0, {
1078
- emptyCase: (): ReadonlyArray<PrettyError> => [],
1096
+ emptyCase: (): Array<PrettyError> => [],
1079
1097
  dieCase: (_, unknownError) => {
1080
- return [defaultRenderError(unknownError)]
1098
+ return [new PrettyError(unknownError)]
1081
1099
  },
1082
1100
  failCase: (_, error) => {
1083
- return [defaultRenderError(error)]
1101
+ return [new PrettyError(error)]
1084
1102
  },
1085
1103
  interruptCase: () => [],
1086
1104
  parallelCase: (_, l, r) => [...l, ...r],
@@ -2310,29 +2310,47 @@ export const updateService = dual<
2310
2310
  )))
2311
2311
 
2312
2312
  /** @internal */
2313
- export const withSpan = dual<
2313
+ export const withSpan: {
2314
2314
  (
2315
2315
  name: string,
2316
2316
  options?: Tracer.SpanOptions
2317
- ) => <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
2317
+ ): <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
2318
2318
  self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
2319
- ) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Exclude<Env, Tracer.ParentSpan>>,
2319
+ ) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Exclude<Env, Tracer.ParentSpan>>
2320
2320
  <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
2321
2321
  self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
2322
2322
  name: string,
2323
2323
  options?: Tracer.SpanOptions
2324
- ) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Exclude<Env, Tracer.ParentSpan>>
2325
- >(3, (self, name, options) =>
2326
- unwrapScoped(
2327
- Effect.flatMap(
2328
- Effect.context(),
2329
- (context) =>
2330
- Effect.map(
2331
- Effect.makeSpanScoped(name, options),
2332
- (span) => core.provideContext(self, Context.add(context, tracer.spanTag, span))
2333
- )
2324
+ ): Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Exclude<Env, Tracer.ParentSpan>>
2325
+ } = function() {
2326
+ const dataFirst = typeof arguments[0] !== "string"
2327
+ const name = dataFirst ? arguments[1] : arguments[0]
2328
+ const options = tracer.addSpanStackTrace(dataFirst ? arguments[2] : arguments[1])
2329
+ if (dataFirst) {
2330
+ const self = arguments[0]
2331
+ return unwrapScoped(
2332
+ Effect.flatMap(
2333
+ Effect.context(),
2334
+ (context) =>
2335
+ Effect.map(
2336
+ Effect.makeSpanScoped(name, options),
2337
+ (span) => core.provideContext(self, Context.add(context, tracer.spanTag, span))
2338
+ )
2339
+ )
2340
+ )
2341
+ }
2342
+ return (self: Effect.Effect<any, any, any>) =>
2343
+ unwrapScoped(
2344
+ Effect.flatMap(
2345
+ Effect.context(),
2346
+ (context) =>
2347
+ Effect.map(
2348
+ Effect.makeSpanScoped(name, options),
2349
+ (span) => core.provideContext(self, Context.add(context, tracer.spanTag, span))
2350
+ )
2351
+ )
2334
2352
  )
2335
- ) as any)
2353
+ } as any
2336
2354
 
2337
2355
  /** @internal */
2338
2356
  export const writeAll = <OutElem>(
@@ -26,6 +26,7 @@ import * as Ref from "../Ref.js"
26
26
  import type * as runtimeFlagsPatch from "../RuntimeFlagsPatch.js"
27
27
  import * as Tracer from "../Tracer.js"
28
28
  import type { NoInfer } from "../Types.js"
29
+ import type { Unify } from "../Unify.js"
29
30
  import { yieldWrapGet } from "../Utils.js"
30
31
  import * as internalCause from "./cause.js"
31
32
  import { clockTag } from "./clock.js"
@@ -2011,7 +2012,7 @@ const bigint0 = BigInt(0)
2011
2012
  export const unsafeMakeSpan = <XA, XE>(
2012
2013
  fiber: FiberRuntime<XA, XE>,
2013
2014
  name: string,
2014
- options?: Tracer.SpanOptions
2015
+ options: Tracer.SpanOptions
2015
2016
  ) => {
2016
2017
  const enabled = fiber.getFiberRef(core.currentTracerEnabled)
2017
2018
  if (enabled === false) {
@@ -2029,34 +2030,38 @@ export const unsafeMakeSpan = <XA, XE>(
2029
2030
  const annotationsFromEnv = FiberRefs.get(fiberRefs, core.currentTracerSpanAnnotations)
2030
2031
  const linksFromEnv = FiberRefs.get(fiberRefs, core.currentTracerSpanLinks)
2031
2032
 
2032
- const parent = options?.parent
2033
+ const parent = options.parent
2033
2034
  ? Option.some(options.parent)
2034
- : options?.root
2035
+ : options.root
2035
2036
  ? Option.none()
2036
2037
  : Context.getOption(context, internalTracer.spanTag)
2037
2038
 
2038
2039
  const links = linksFromEnv._tag === "Some" ?
2039
- options?.links !== undefined ?
2040
+ options.links !== undefined ?
2040
2041
  [
2041
2042
  ...Chunk.toReadonlyArray(linksFromEnv.value),
2042
- ...(options?.links ?? [])
2043
+ ...(options.links ?? [])
2043
2044
  ] :
2044
2045
  Chunk.toReadonlyArray(linksFromEnv.value) :
2045
- options?.links ?? Arr.empty()
2046
+ options.links ?? Arr.empty()
2046
2047
 
2047
2048
  const span = tracer.span(
2048
2049
  name,
2049
2050
  parent,
2050
- options?.context ?? Context.empty(),
2051
+ options.context ?? Context.empty(),
2051
2052
  links,
2052
2053
  timingEnabled ? clock.unsafeCurrentTimeNanos() : bigint0,
2053
- options?.kind ?? "internal"
2054
+ options.kind ?? "internal"
2054
2055
  )
2055
2056
 
2057
+ if (typeof options.captureStackTrace === "string") {
2058
+ span.attribute("code.stacktrace", options.captureStackTrace)
2059
+ }
2060
+
2056
2061
  if (annotationsFromEnv._tag === "Some") {
2057
2062
  HashMap.forEach(annotationsFromEnv.value, (value, key) => span.attribute(key, value))
2058
2063
  }
2059
- if (options?.attributes !== undefined) {
2064
+ if (options.attributes !== undefined) {
2060
2065
  Object.entries(options.attributes).forEach(([k, v]) => span.attribute(k, v))
2061
2066
  }
2062
2067
 
@@ -2067,7 +2072,10 @@ export const unsafeMakeSpan = <XA, XE>(
2067
2072
  export const makeSpan = (
2068
2073
  name: string,
2069
2074
  options?: Tracer.SpanOptions
2070
- ): Effect.Effect<Tracer.Span> => core.withFiberRuntime((fiber) => core.succeed(unsafeMakeSpan(fiber, name, options)))
2075
+ ): Effect.Effect<Tracer.Span> => {
2076
+ options = internalTracer.addSpanStackTrace(options)
2077
+ return core.withFiberRuntime((fiber) => core.succeed(unsafeMakeSpan(fiber, name, options)))
2078
+ }
2071
2079
 
2072
2080
  /* @internal */
2073
2081
  export const spanAnnotations: Effect.Effect<HashMap.HashMap<string, unknown>> = core
@@ -2092,7 +2100,7 @@ export const useSpan: {
2092
2100
  evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R>
2093
2101
  ]
2094
2102
  ) => {
2095
- const options: Tracer.SpanOptions | undefined = args.length === 1 ? undefined : args[0]
2103
+ const options = internalTracer.addSpanStackTrace(args.length === 1 ? undefined : args[0])
2096
2104
  const evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R> = args[args.length - 1]
2097
2105
 
2098
2106
  return core.withFiberRuntime<A, E, R>((fiber) => {
@@ -2118,25 +2126,66 @@ export const withParentSpan = dual<
2118
2126
  >(2, (self, span) => provideService(self, internalTracer.spanTag, span))
2119
2127
 
2120
2128
  /** @internal */
2121
- export const withSpan = dual<
2129
+ export const withSpan: {
2122
2130
  (
2123
2131
  name: string,
2124
- options?: Tracer.SpanOptions
2125
- ) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>>,
2132
+ options?: Tracer.SpanOptions | undefined
2133
+ ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>>
2126
2134
  <A, E, R>(
2127
2135
  self: Effect.Effect<A, E, R>,
2128
2136
  name: string,
2129
- options?: Tracer.SpanOptions
2130
- ) => Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>>
2131
- >(
2132
- (args) => typeof args[0] !== "string",
2133
- (self, name, options) =>
2134
- useSpan(
2135
- name,
2136
- options ?? {},
2137
- (span) => withParentSpan(self, span)
2138
- )
2139
- )
2137
+ options?: Tracer.SpanOptions | undefined
2138
+ ): Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>>
2139
+ } = function() {
2140
+ const dataFirst = typeof arguments[0] !== "string"
2141
+ const name = dataFirst ? arguments[1] : arguments[0]
2142
+ const options = internalTracer.addSpanStackTrace(dataFirst ? arguments[2] : arguments[1])
2143
+ if (dataFirst) {
2144
+ const self = arguments[0]
2145
+ return useSpan(name, options, (span) => withParentSpan(self, span))
2146
+ }
2147
+ return (self: Effect.Effect<any, any, any>) => useSpan(name, options, (span) => withParentSpan(self, span))
2148
+ } as any
2149
+
2150
+ export const functionWithSpan = <Args extends Array<any>, Ret extends Effect.Effect<any, any, any>>(
2151
+ options: {
2152
+ readonly body: (...args: Args) => Ret
2153
+ readonly options: Effect.FunctionWithSpanOptions | ((...args: Args) => Effect.FunctionWithSpanOptions)
2154
+ readonly captureStackTrace?: boolean | undefined
2155
+ }
2156
+ ): (...args: Args) => Unify<Ret> =>
2157
+ (function(this: any) {
2158
+ let captureStackTrace: string | boolean = options.captureStackTrace ?? false
2159
+ if (options.captureStackTrace !== false) {
2160
+ const limit = Error.stackTraceLimit
2161
+ Error.stackTraceLimit = 2
2162
+ const error = new Error()
2163
+ Error.stackTraceLimit = limit
2164
+ if (error.stack !== undefined) {
2165
+ const stack = error.stack.trim().split("\n")
2166
+ captureStackTrace = stack.slice(2).join("\n").trim()
2167
+ }
2168
+ }
2169
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
2170
+ const self = this
2171
+ const args = arguments
2172
+ return core.suspend(() => {
2173
+ const opts = typeof options.options === "function"
2174
+ ? options.options.apply(null, arguments as any)
2175
+ : options.options
2176
+
2177
+ return withSpan(
2178
+ core.custom(options.body, function() {
2179
+ return this.effect_instruction_i0.apply(self, args as any)
2180
+ }),
2181
+ opts.name,
2182
+ {
2183
+ ...opts,
2184
+ captureStackTrace
2185
+ }
2186
+ )
2187
+ })
2188
+ }) as any
2140
2189
 
2141
2190
  // -------------------------------------------------------------------------------------
2142
2191
  // optionality
@@ -459,6 +459,10 @@ export const as: {
459
459
  /* @internal */
460
460
  export const asVoid = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<void, E, R> => as(self, void 0)
461
461
 
462
+ function commitCallCutpoint(this: any) {
463
+ return this.effect_cutpoint()
464
+ }
465
+
462
466
  /* @internal */
463
467
  export const custom: {
464
468
  <X, A, E, R>(i0: X, body: (this: { effect_instruction_i0: X }) => Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
@@ -477,23 +481,24 @@ export const custom: {
477
481
  ): Effect.Effect<A, E, R>
478
482
  } = function() {
479
483
  const wrapper = new EffectPrimitive(OpCodes.OP_COMMIT) as any
484
+ wrapper.commit = commitCallCutpoint
480
485
  switch (arguments.length) {
481
486
  case 2: {
482
487
  wrapper.effect_instruction_i0 = arguments[0]
483
- wrapper.commit = arguments[1]
488
+ wrapper.effect_cutpoint = arguments[1]
484
489
  break
485
490
  }
486
491
  case 3: {
487
492
  wrapper.effect_instruction_i0 = arguments[0]
488
493
  wrapper.effect_instruction_i1 = arguments[1]
489
- wrapper.commit = arguments[2]
494
+ wrapper.effect_cutpoint = arguments[2]
490
495
  break
491
496
  }
492
497
  case 4: {
493
498
  wrapper.effect_instruction_i0 = arguments[0]
494
499
  wrapper.effect_instruction_i1 = arguments[1]
495
500
  wrapper.effect_instruction_i2 = arguments[2]
496
- wrapper.commit = arguments[3]
501
+ wrapper.effect_cutpoint = arguments[3]
497
502
  break
498
503
  }
499
504
  default: {