import * as Arr from "../Array.js";
import * as Context from "../Context.js";
import * as Duration from "../Duration.js";
import * as Equal from "../Equal.js";
import * as Filter from "../Filter.js";
import { formatJson } from "../Formatter.js";
import { constant, constFalse, constTrue, constUndefined, constVoid, dual, identity } from "../Function.js";
import * as Hash from "../Hash.js";
import { toJson, toStringUnknown } from "../Inspectable.js";
import * as Iterable from "../Iterable.js";
import * as Option from "../Option.js";
import * as Order from "../Order.js";
import { pipeArguments } from "../Pipeable.js";
import { hasProperty, isIterable, isString, isTagged } from "../Predicate.js";
import { currentFiberTypeId, redact } from "../Redactable.js";
import * as Result from "../Result.js";
import * as Scheduler from "../Scheduler.js";
import * as Tracer from "../Tracer.js";
import { internalCall } from "../Utils.js";
import { args, causeAnnotate, causeEmpty, causeFromReasons, CauseImpl, constEmptyAnnotations, contA, contAll, contE, evaluate, exitDie, exitFail, exitFailCause, exitSucceed, ExitTypeId, Fail, InterruptorStackTrace, isCause, isDieReason, isEffect, isFailReason, isInterruptReason, isNoSuchElementError, makePrimitive, makePrimitiveProto, NoSuchElementError, ReasonBase, StackTraceKey as CauseStackTrace, TaggedError, withFiber, Yield } from "./core.js";
import * as doNotation from "./doNotation.js";
import * as InternalMetric from "./metric.js";
import { CurrentConcurrency, CurrentErrorReporters, CurrentLogAnnotations, CurrentLogLevel, CurrentLogSpans, CurrentStackFrame, MinimumLogLevel, TracerEnabled, TracerSpanAnnotations, TracerSpanLinks, TracerTimingEnabled } from "./references.js";
import { addSpanStackTrace, makeStackCleaner } from "./tracer.js";
import { version } from "./version.js";
// ----------------------------------------------------------------------------
// Cause
// ----------------------------------------------------------------------------
/** @internal */
export class Interrupt extends ReasonBase {
  fiberId;
  constructor(fiberId, annotations = constEmptyAnnotations) {
    super("Interrupt", annotations, "Interrupted");
    this.fiberId = fiberId;
  }
  toString() {
    return `Interrupt(${this.fiberId})`;
  }
  toJSON() {
    return {
      _tag: "Interrupt",
      fiberId: this.fiberId
    };
  }
  [Equal.symbol](that) {
    return isInterruptReason(that) && this.fiberId === that.fiberId && this.annotations === that.annotations;
  }
  [Hash.symbol]() {
    return Hash.combine(Hash.string(`${this._tag}:${this.fiberId}`))(Hash.random(this.annotations));
  }
}
/** @internal */
export const makeInterruptReason = fiberId => new Interrupt(fiberId);
/** @internal */
export const causeInterrupt = fiberId => new CauseImpl([new Interrupt(fiberId)]);
/** @internal */
export const hasFails = self => self.reasons.some(isFailReason);
/** @internal */
export const findFail = self => {
  const reason = self.reasons.find(isFailReason);
  return reason ? Result.succeed(reason) : Result.fail(self);
};
/** @internal */
export const findError = self => {
  for (let i = 0; i < self.reasons.length; i++) {
    const reason = self.reasons[i];
    if (reason._tag === "Fail") {
      return Result.succeed(reason.error);
    }
  }
  return Result.fail(self);
};
/** @internal */
export const findErrorOption = /*#__PURE__*/Filter.toOption(findError);
/** @internal */
export const hasDies = self => self.reasons.some(isDieReason);
/** @internal */
export const findDie = self => {
  const reason = self.reasons.find(isDieReason);
  return reason ? Result.succeed(reason) : Result.fail(self);
};
/** @internal */
export const findDefect = self => {
  const reason = self.reasons.find(isDieReason);
  return reason ? Result.succeed(reason.defect) : Result.fail(self);
};
/** @internal */
export const hasInterrupts = self => self.reasons.some(isInterruptReason);
/** @internal */
export const findInterrupt = self => {
  const reason = self.reasons.find(isInterruptReason);
  return reason ? Result.succeed(reason) : Result.fail(self);
};
/** @internal */
export const causeFilterInterruptors = self => {
  let interruptors;
  for (let i = 0; i < self.reasons.length; i++) {
    const f = self.reasons[i];
    if (f._tag !== "Interrupt") continue;
    interruptors ??= new Set();
    if (f.fiberId !== undefined) {
      interruptors.add(f.fiberId);
    }
  }
  return interruptors ? Result.succeed(interruptors) : Result.fail(self);
};
/** @internal */
export const causeInterruptors = self => {
  const result = causeFilterInterruptors(self);
  return Result.isFailure(result) ? emptySet : result.success;
};
const emptySet = /*#__PURE__*/new Set();
/** @internal */
export const hasInterruptsOnly = self => self.reasons.length > 0 && self.reasons.every(isInterruptReason);
/** @internal */
export const reasonAnnotations = self => Context.makeUnsafe(self.annotations);
/** @internal */
export const causeAnnotations = self => {
  const map = new Map();
  for (const f of self.reasons) {
    if (f.annotations.size > 0) {
      for (const [key, value] of f.annotations) {
        map.set(key, value);
      }
    }
  }
  return Context.makeUnsafe(map);
};
/** @internal */
export const causeCombine = /*#__PURE__*/dual(2, (self, that) => {
  if (self.reasons.length === 0) {
    return that;
  } else if (that.reasons.length === 0) {
    return self;
  }
  const newCause = new CauseImpl(Arr.union(self.reasons, that.reasons));
  return Equal.equals(self, newCause) ? self : newCause;
});
/** @internal */
export const causeMap = /*#__PURE__*/dual(2, (self, f) => {
  let hasFail = false;
  const failures = self.reasons.map(failure => {
    if (isFailReason(failure)) {
      hasFail = true;
      return new Fail(f(failure.error));
    }
    return failure;
  });
  return hasFail ? causeFromReasons(failures) : self;
});
/** @internal */
export const causePartition = self => {
  const obj = {
    Fail: [],
    Die: [],
    Interrupt: []
  };
  for (let i = 0; i < self.reasons.length; i++) {
    obj[self.reasons[i]._tag].push(self.reasons[i]);
  }
  return obj;
};
/** @internal */
export const causeSquash = self => {
  const partitioned = causePartition(self);
  if (partitioned.Fail.length > 0) {
    return partitioned.Fail[0].error;
  } else if (partitioned.Die.length > 0) {
    return partitioned.Die[0].defect;
  } else if (partitioned.Interrupt.length > 0) {
    return new globalThis.Error("All fibers interrupted without error");
  }
  return new globalThis.Error("Empty cause");
};
/** @internal */
export const causePrettyErrors = self => {
  const errors = [];
  const interrupts = [];
  if (self.reasons.length === 0) return errors;
  const prevStackLimit = Error.stackTraceLimit;
  Error.stackTraceLimit = 1;
  for (const failure of self.reasons) {
    if (failure._tag === "Interrupt") {
      interrupts.push(failure);
      continue;
    }
    errors.push(causePrettyError(failure._tag === "Die" ? failure.defect : failure.error, failure.annotations));
  }
  if (errors.length === 0) {
    const cause = new Error("The fiber was interrupted by:");
    cause.name = "InterruptCause";
    cause.stack = interruptCauseStack(cause, interrupts);
    const error = new globalThis.Error("All fibers interrupted without error", {
      cause
    });
    error.name = "InterruptError";
    error.stack = `${error.name}: ${error.message}`;
    errors.push(causePrettyError(error, interrupts[0].annotations));
  }
  ;
  Error.stackTraceLimit = prevStackLimit;
  return errors;
};
/** @internal */
export const causePrettyError = (original, annotations) => {
  const kind = typeof original;
  let error;
  if (original && kind === "object") {
    error = new globalThis.Error(causePrettyMessage(original), {
      cause: original.cause ? causePrettyError(original.cause) : undefined
    });
    if (typeof original.name === "string") {
      error.name = original.name;
    }
    if (typeof original.stack === "string") {
      error.stack = cleanErrorStack(original.stack, error, annotations);
    } else {
      const stack = `${error.name}: ${error.message}`;
      error.stack = annotations ? addStackAnnotations(stack, annotations) : stack;
    }
    for (const key of Object.keys(original)) {
      if (!(key in error)) {
        ;
        error[key] = original[key];
      }
    }
  } else {
    error = new globalThis.Error(!original ? `Unknown error: ${original}` : kind === "string" ? original : formatJson(original));
  }
  return error;
};
const causePrettyMessage = u => {
  if (typeof u.message === "string") {
    return u.message;
  } else if (typeof u.toString === "function" && u.toString !== Object.prototype.toString && u.toString !== Array.prototype.toString) {
    try {
      return u.toString();
    } catch {
      // something's off, rollback to json
    }
  }
  return formatJson(u);
};
const locationRegExp = /\((.*)\)/g;
const cleanErrorStack = (stack, error, annotations) => {
  const message = `${error.name}: ${error.message}`;
  const lines = (stack.startsWith(message) ? stack.slice(message.length) : stack).split("\n");
  const out = [message];
  for (let i = 1; i < lines.length; i++) {
    if (/(?:Generator\.next|~effect\/Effect)/.test(lines[i])) {
      break;
    }
    out.push(lines[i]);
  }
  return annotations ? addStackAnnotations(out.join("\n"), annotations) : out.join("\n");
};
const addStackAnnotations = (stack, annotations) => {
  const frame = annotations?.get(CauseStackTrace.key);
  if (frame) {
    stack = `${stack}\n${currentStackTrace(frame)}`;
  }
  return stack;
};
const interruptCauseStack = (error, interrupts) => {
  const out = [`${error.name}: ${error.message}`];
  for (const current of interrupts) {
    const fiberId = current.fiberId !== undefined ? `#${current.fiberId}` : "unknown";
    const frame = current.annotations.get(InterruptorStackTrace.key);
    out.push(`    at fiber (${fiberId})`);
    if (frame) out.push(currentStackTrace(frame));
  }
  return out.join("\n");
};
const currentStackTrace = frame => {
  const out = [];
  let current = frame;
  let i = 0;
  while (current && i < 10) {
    const stack = current.stack();
    if (stack) {
      const locationMatchAll = stack.matchAll(locationRegExp);
      let match = false;
      for (const [, location] of locationMatchAll) {
        match = true;
        out.push(`    at ${current.name} (${location})`);
      }
      if (!match) {
        out.push(`    at ${current.name} (${stack.replace(/^at /, "")})`);
      }
    } else {
      out.push(`    at ${current.name}`);
    }
    current = current.parent;
    i++;
  }
  return out.join("\n");
};
/** @internal */
export const causePretty = cause => causePrettyErrors(cause).map(e => e.cause ? `${e.stack} {\n${renderErrorCause(e.cause, "  ")}\n}` : e.stack).join("\n");
const renderErrorCause = (cause, prefix) => {
  const lines = cause.stack.split("\n");
  let stack = `${prefix}[cause]: ${lines[0]}`;
  for (let i = 1, len = lines.length; i < len; i++) {
    stack += `\n${prefix}${lines[i]}`;
  }
  if (cause.cause) {
    stack += ` {\n${renderErrorCause(cause.cause, `${prefix}  `)}\n${prefix}}`;
  }
  return stack;
};
// ----------------------------------------------------------------------------
// Fiber
// ----------------------------------------------------------------------------
/** @internal */
export const FiberTypeId = `~effect/Fiber/${version}`;
const fiberVariance = {
  _A: identity,
  _E: identity
};
const fiberIdStore = {
  id: 0
};
/** @internal */
export const getCurrentFiber = () => globalThis[currentFiberTypeId];
/** @internal */
export class FiberImpl {
  constructor(context, interruptible = true) {
    this[FiberTypeId] = fiberVariance;
    this.setContext(context);
    this.id = ++fiberIdStore.id;
    this.currentOpCount = 0;
    this.currentLoopCount = 0;
    this.interruptible = interruptible;
    this._stack = [];
    this._observers = [];
    this._exit = undefined;
    this._children = undefined;
    this._interruptedCause = undefined;
    this._yielded = undefined;
  }
  [FiberTypeId];
  id;
  interruptible;
  currentOpCount;
  currentLoopCount;
  _stack;
  _observers;
  _exit;
  _currentExit;
  _children;
  _interruptedCause;
  _yielded;
  // set in setContext
  context;
  currentScheduler;
  currentTracerContext;
  currentSpan;
  currentLogLevel;
  minimumLogLevel;
  currentStackFrame;
  runtimeMetrics;
  maxOpsBeforeYield;
  currentPreventYield;
  _dispatcher = undefined;
  get currentDispatcher() {
    return this._dispatcher ??= this.currentScheduler.makeDispatcher();
  }
  getRef(ref) {
    return Context.getReferenceUnsafe(this.context, ref);
  }
  addObserver(cb) {
    if (this._exit) {
      cb(this._exit);
      return constVoid;
    }
    this._observers.push(cb);
    return () => {
      const index = this._observers.indexOf(cb);
      if (index >= 0) {
        this._observers.splice(index, 1);
      }
    };
  }
  interruptUnsafe(fiberId, annotations) {
    if (this._exit) {
      return;
    }
    let cause = causeInterrupt(fiberId);
    if (this.currentStackFrame) {
      cause = causeAnnotate(cause, Context.make(CauseStackTrace, this.currentStackFrame));
    }
    if (annotations) {
      cause = causeAnnotate(cause, annotations);
    }
    this._interruptedCause = this._interruptedCause ? causeCombine(this._interruptedCause, cause) : cause;
    if (this.interruptible) {
      this.evaluate(failCause(this._interruptedCause));
    }
  }
  pollUnsafe() {
    return this._exit;
  }
  evaluate(effect) {
    this.runtimeMetrics?.recordFiberStart(this.context);
    if (this._exit) {
      return;
    } else if (this._yielded !== undefined) {
      const yielded = this._yielded;
      this._yielded = undefined;
      yielded();
    }
    const exit = this.runLoop(effect);
    if (exit === Yield) {
      return;
    }
    // the interruptChildren middleware is added in Effect.forkChild, so it can be
    // tree-shaken if not used
    const interruptChildren = fiberMiddleware.interruptChildren && fiberMiddleware.interruptChildren(this);
    if (interruptChildren !== undefined) {
      return this.evaluate(flatMap(interruptChildren, () => exit));
    }
    this._exit = exit;
    this.runtimeMetrics?.recordFiberEnd(this.context, this._exit);
    for (let i = 0; i < this._observers.length; i++) {
      this._observers[i](exit);
    }
    this._observers.length = 0;
  }
  runLoop(effect) {
    const prevFiber = globalThis[currentFiberTypeId];
    globalThis[currentFiberTypeId] = this;
    let yielding = false;
    let current = effect;
    this.currentOpCount = 0;
    const currentLoop = ++this.currentLoopCount;
    try {
      while (true) {
        this.currentOpCount++;
        if (!yielding && !this.currentPreventYield && this.currentScheduler.shouldYield(this)) {
          yielding = true;
          const prev = current;
          current = flatMap(yieldNow, () => prev);
        }
        current = this.currentTracerContext ? this.currentTracerContext(current, this) : current[evaluate](this);
        if (currentLoop !== this.currentLoopCount) {
          // another effect has taken over the loop,
          return Yield;
        } else if (current === Yield) {
          const yielded = this._yielded;
          if (ExitTypeId in yielded) {
            this._yielded = undefined;
            return yielded;
          }
          return Yield;
        }
      }
    } catch (error) {
      if (!hasProperty(current, evaluate)) {
        return exitDie(`Fiber.runLoop: Not a valid effect: ${String(current)}`);
      }
      return this.runLoop(exitDie(error));
    } finally {
      ;
      globalThis[currentFiberTypeId] = prevFiber;
    }
  }
  getCont(symbol) {
    while (true) {
      const op = this._stack.pop();
      if (!op) return undefined;
      const cont = op[contAll] && op[contAll](this);
      if (cont) {
        ;
        cont[symbol] = cont;
        return cont;
      }
      if (op[symbol]) return op;
    }
  }
  yieldWith(value) {
    this._yielded = value;
    return Yield;
  }
  children() {
    return this._children ??= new Set();
  }
  pipe() {
    return pipeArguments(this, arguments);
  }
  setContext(context) {
    this.context = context;
    const scheduler = this.getRef(Scheduler.Scheduler);
    if (scheduler !== this.currentScheduler) {
      this.currentScheduler = scheduler;
      this._dispatcher = undefined;
    }
    this.currentSpan = context.mapUnsafe.get(Tracer.ParentSpanKey);
    this.currentLogLevel = this.getRef(CurrentLogLevel);
    this.minimumLogLevel = this.getRef(MinimumLogLevel);
    this.currentStackFrame = context.mapUnsafe.get(CurrentStackFrame.key);
    this.maxOpsBeforeYield = this.getRef(Scheduler.MaxOpsBeforeYield);
    this.currentPreventYield = this.getRef(Scheduler.PreventSchedulerYield);
    this.runtimeMetrics = context.mapUnsafe.get(InternalMetric.FiberRuntimeMetricsKey);
    const currentTracer = context.mapUnsafe.get(Tracer.TracerKey);
    this.currentTracerContext = currentTracer ? currentTracer["context"] : undefined;
  }
  get currentSpanLocal() {
    return this.currentSpan?._tag === "Span" ? this.currentSpan : undefined;
  }
}
const fiberMiddleware = {
  interruptChildren: undefined
};
const fiberStackAnnotations = fiber => {
  if (!fiber.currentStackFrame) return undefined;
  const annotations = new Map();
  annotations.set(CauseStackTrace.key, fiber.currentStackFrame);
  return Context.makeUnsafe(annotations);
};
const fiberInterruptChildren = fiber => {
  if (fiber._children === undefined || fiber._children.size === 0) {
    return undefined;
  }
  return fiberInterruptAll(fiber._children);
};
/** @internal */
export const fiberAwait = self => {
  const impl = self;
  if (impl._exit) return succeed(impl._exit);
  return callback(resume => {
    if (impl._exit) return resume(succeed(impl._exit));
    return sync(self.addObserver(exit => resume(succeed(exit))));
  });
};
/** @internal */
export const fiberAwaitAll = self => callback(resume => {
  const iter = self[Symbol.iterator]();
  const exits = [];
  let cancel = undefined;
  function loop() {
    let result = iter.next();
    while (!result.done) {
      if (result.value._exit) {
        exits.push(result.value._exit);
        result = iter.next();
        continue;
      }
      cancel = result.value.addObserver(exit => {
        exits.push(exit);
        loop();
      });
      return;
    }
    resume(succeed(exits));
  }
  loop();
  return sync(() => cancel?.());
});
/** @internal */
export const fiberJoin = self => {
  const impl = self;
  if (impl._exit) return impl._exit;
  return callback(resume => {
    if (impl._exit) return resume(impl._exit);
    return sync(self.addObserver(resume));
  });
};
/** @internal */
export const fiberJoinAll = self => callback(resume => {
  const fibers = Array.from(self);
  if (fibers.length === 0) return resume(succeed(Arr.empty()));
  const out = new Array(fibers.length);
  const cancels = Arr.empty();
  let done = 0;
  let failed = false;
  for (let i = 0; i < fibers.length; i++) {
    if (failed) break;
    cancels.push(fibers[i].addObserver(exit => {
      done++;
      if (exit._tag === "Failure") {
        failed = true;
        cancels.forEach(cancel => cancel());
        return resume(exit);
      }
      out[i] = exit.value;
      if (done === fibers.length) {
        resume(succeed(out));
      }
    }));
  }
});
/** @internal */
export const fiberInterrupt = self => withFiber(fiber => fiberInterruptAs(self, fiber.id));
/** @internal */
export const fiberInterruptAs = /*#__PURE__*/dual(args => hasProperty(args[0], FiberTypeId), (self, fiberId, annotations) => withFiber(parent => {
  let ann = fiberStackAnnotations(parent);
  ann = ann && annotations ? Context.merge(ann, annotations) : ann ?? annotations;
  self.interruptUnsafe(fiberId, ann);
  return asVoid(fiberAwait(self));
}));
/** @internal */
export const fiberInterruptAll = fibers => withFiber(parent => {
  const annotations = fiberStackAnnotations(parent);
  for (const fiber of fibers) {
    fiber.interruptUnsafe(parent.id, annotations);
  }
  return asVoid(fiberAwaitAll(fibers));
});
/** @internal */
export const fiberInterruptAllAs = /*#__PURE__*/dual(2, (fibers, fiberId) => withFiber(parent => {
  const annotations = fiberStackAnnotations(parent);
  for (const fiber of fibers) fiber.interruptUnsafe(fiberId, annotations);
  return asVoid(fiberAwaitAll(fibers));
}));
/** @internal */
export const succeed = exitSucceed;
/** @internal */
export const failCause = exitFailCause;
/** @internal */
export const fail = exitFail;
/** @internal */
export const sync = /*#__PURE__*/makePrimitive({
  op: "Sync",
  [evaluate](fiber) {
    const value = this[args]();
    const cont = fiber.getCont(contA);
    return cont ? cont[contA](value, fiber) : fiber.yieldWith(exitSucceed(value));
  }
});
/** @internal */
export const suspend = /*#__PURE__*/makePrimitive({
  op: "Suspend",
  [evaluate](_fiber) {
    return this[args]();
  }
});
/** @internal */
export const fromYieldable = yieldable => yieldable.asEffect();
/** @internal */
export const fromOption = fromYieldable;
/** @internal */
export const fromResult = fromYieldable;
/** @internal */
export const fromNullishOr = value => value == null ? fail(new NoSuchElementError()) : succeed(value);
/** @internal */
export const yieldNowWith = /*#__PURE__*/makePrimitive({
  op: "Yield",
  [evaluate](fiber) {
    let resumed = false;
    fiber.currentDispatcher.scheduleTask(() => {
      if (resumed) return;
      fiber.evaluate(exitVoid);
    }, this[args] ?? 0);
    return fiber.yieldWith(() => {
      resumed = true;
    });
  }
});
/** @internal */
export const yieldNow = /*#__PURE__*/yieldNowWith(0);
/** @internal */
export const succeedSome = a => succeed(Option.some(a));
/** @internal */
export const succeedNone = /*#__PURE__*/succeed(/*#__PURE__*/Option.none());
/** @internal */
export const failCauseSync = evaluate => suspend(() => failCause(internalCall(evaluate)));
/** @internal */
export const die = defect => exitDie(defect);
/** @internal */
export const failSync = error => suspend(() => fail(internalCall(error)));
/** @internal */
const void_ = /*#__PURE__*/succeed(void 0);
/** @internal */
export { void_ as void };
/** @internal */
const try_ = options => suspend(() => {
  try {
    return succeed(internalCall(options.try));
  } catch (err) {
    return fail(internalCall(() => options.catch(err)));
  }
});
/** @internal */
export { try_ as try };
/** @internal */
export const promise = evaluate => callbackOptions(function (resume, signal) {
  internalCall(() => evaluate(signal)).then(a => resume(succeed(a)), e => resume(die(e)));
}, evaluate.length !== 0);
/** @internal */
export const tryPromise = options => {
  const f = typeof options === "function" ? options : options.try;
  const catcher = typeof options === "function" ? cause => new UnknownError(cause, "An error occurred in Effect.tryPromise") : options.catch;
  return callbackOptions(function (resume, signal) {
    try {
      internalCall(() => f(signal)).then(a => resume(succeed(a)), e => resume(fail(internalCall(() => catcher(e)))));
    } catch (err) {
      resume(fail(internalCall(() => catcher(err))));
    }
  }, eval.length !== 0);
};
/** @internal */
export const withFiberId = f => withFiber(fiber => f(fiber.id));
/** @internal */
export const fiber = /*#__PURE__*/withFiber(succeed);
/** @internal */
export const fiberId = /*#__PURE__*/withFiberId(succeed);
const callbackOptions = /*#__PURE__*/makePrimitive({
  op: "Async",
  single: false,
  [evaluate](fiber) {
    const register = internalCall(() => this[args][0].bind(fiber.currentScheduler));
    let resumed = false;
    let yielded = false;
    const controller = this[args][1] ? new AbortController() : undefined;
    const onCancel = register(effect => {
      if (resumed) return;
      resumed = true;
      if (yielded) {
        fiber.evaluate(effect);
      } else {
        yielded = effect;
      }
    }, controller?.signal);
    if (yielded !== false) return yielded;
    yielded = true;
    fiber._yielded = () => {
      resumed = true;
    };
    if (controller === undefined && onCancel === undefined) {
      return Yield;
    }
    fiber._stack.push(asyncFinalizer(() => {
      resumed = true;
      controller?.abort();
      return onCancel ?? exitVoid;
    }));
    return Yield;
  }
});
const asyncFinalizer = /*#__PURE__*/makePrimitive({
  op: "AsyncFinalizer",
  [contAll](fiber) {
    if (fiber.interruptible) {
      fiber.interruptible = false;
      fiber._stack.push(setInterruptibleTrue);
    }
  },
  [contE](cause, _fiber) {
    return hasInterrupts(cause) ? flatMap(this[args](), () => failCause(cause)) : failCause(cause);
  }
});
/** @internal */
export const callback = register => callbackOptions(register, register.length >= 2);
/** @internal */
export const never = /*#__PURE__*/callback(constVoid);
/** @internal */
export const gen = (...args) => suspend(() => fromIteratorUnsafe(args.length === 1 ? args[0]() : args[1].call(args[0].self)));
/** @internal */
export const fnUntraced = (body, ...pipeables) => {
  const fn = pipeables.length === 0 ? function () {
    return suspend(() => fromIteratorUnsafe(body.apply(this, arguments)));
  } : function () {
    let effect = suspend(() => fromIteratorUnsafe(body.apply(this, arguments)));
    for (let i = 0; i < pipeables.length; i++) {
      effect = pipeables[i](effect, ...arguments);
    }
    return effect;
  };
  return defineFunctionLength(body.length, fn);
};
const defineFunctionLength = (length, fn) => Object.defineProperty(fn, "length", {
  value: length,
  configurable: true
});
const fnStackCleaner = /*#__PURE__*/makeStackCleaner(2);
/** @internal */
export const fn = function () {
  const nameFirst = typeof arguments[0] === "string";
  const name = nameFirst ? arguments[0] : "Effect.fn";
  const spanOptions = nameFirst ? arguments[1] : undefined;
  const prevLimit = globalThis.Error.stackTraceLimit;
  globalThis.Error.stackTraceLimit = 2;
  const defError = new globalThis.Error();
  globalThis.Error.stackTraceLimit = prevLimit;
  if (nameFirst) {
    return (body, ...pipeables) => makeFn(name, body, defError, pipeables, nameFirst, spanOptions);
  }
  return makeFn(name, arguments[0], defError, Array.prototype.slice.call(arguments, 1), nameFirst, spanOptions);
};
const makeFn = (name, bodyOrOptions, defError, pipeables, addSpan, spanOptions) => {
  const body = typeof bodyOrOptions === "function" ? bodyOrOptions : pipeables.pop().bind(bodyOrOptions.self);
  return defineFunctionLength(body.length, function (...args) {
    let result = suspend(() => {
      const iter = body.apply(this, arguments);
      return isEffect(iter) ? iter : fromIteratorUnsafe(iter);
    });
    for (let i = 0; i < pipeables.length; i++) {
      result = pipeables[i](result, ...args);
    }
    if (!isEffect(result)) {
      return result;
    }
    const prevLimit = globalThis.Error.stackTraceLimit;
    globalThis.Error.stackTraceLimit = 2;
    const callError = new globalThis.Error();
    globalThis.Error.stackTraceLimit = prevLimit;
    return updateService(addSpan ? useSpan(name, spanOptions, span => provideParentSpan(result, span)) : result, CurrentStackFrame, prev => ({
      name,
      stack: fnStackCleaner(() => callError.stack),
      parent: {
        name: `${name} (definition)`,
        stack: fnStackCleaner(() => defError.stack),
        parent: prev
      }
    }));
  });
};
/** @internal */
export const fnUntracedEager = (body, ...pipeables) => defineFunctionLength(body.length, pipeables.length === 0 ? function () {
  return fromIteratorEagerUnsafe(() => body.apply(this, arguments));
} : function () {
  let effect = fromIteratorEagerUnsafe(() => body.apply(this, arguments));
  for (const pipeable of pipeables) {
    effect = pipeable(effect);
  }
  return effect;
});
const fromIteratorEagerUnsafe = evaluate => {
  try {
    const iterator = evaluate();
    let value = undefined;
    // Try to resolve synchronously in a loop
    while (true) {
      const state = iterator.next(value);
      if (state.done) {
        return succeed(state.value);
      }
      const yieldable = state.value;
      const effect = yieldable.asEffect();
      const primitive = effect;
      if (primitive && primitive._tag === "Success") {
        value = primitive.value;
        continue;
      } else if (primitive && primitive._tag === "Failure") {
        return effect;
      } else {
        let isFirstExecution = true;
        return suspend(() => {
          if (isFirstExecution) {
            isFirstExecution = false;
            return flatMap(effect, value => fromIteratorUnsafe(iterator, value));
          } else {
            return suspend(() => fromIteratorUnsafe(evaluate()));
          }
        });
      }
    }
  } catch (error) {
    return die(error);
  }
};
const fromIteratorUnsafe = /*#__PURE__*/makePrimitive({
  op: "Iterator",
  single: false,
  [contA](value, fiber) {
    const iter = this[args][0];
    while (true) {
      const state = iter.next(value);
      if (state.done) return succeed(state.value);
      const eff = state.value.asEffect();
      if (!effectIsExit(eff)) {
        fiber._stack.push(this);
        return eff;
      } else if (eff._tag === "Failure") {
        return eff;
      }
      value = eff.value;
    }
  },
  [evaluate](fiber) {
    return this[contA](this[args][1], fiber);
  }
});
// ----------------------------------------------------------------------------
// mapping & sequencing
// ----------------------------------------------------------------------------
/** @internal */
export const as = /*#__PURE__*/dual(2, (self, value) => {
  const b = succeed(value);
  return flatMap(self, _ => b);
});
/** @internal */
export const asSome = self => map(self, Option.some);
/** @internal */
export const flip = self => matchEffect(self, {
  onFailure: succeed,
  onSuccess: fail
});
/** @internal */
export const andThen = /*#__PURE__*/dual(2, (self, f) => flatMap(self, a => isEffect(f) ? f : internalCall(() => f(a))));
/** @internal */
export const tap = /*#__PURE__*/dual(2, (self, f) => flatMap(self, a => as(isEffect(f) ? f : internalCall(() => f(a)), a)));
/** @internal */
export const asVoid = self => flatMap(self, _ => exitVoid);
/** @internal */
export const sandbox = self => catchCause(self, fail);
/** @internal */
export const raceAll = (all, options) => withFiber(parent => callback(resume => {
  const effects = Arr.fromIterable(all);
  const len = effects.length;
  let doneCount = 0;
  let done = false;
  const fibers = new Set();
  const failures = [];
  const onExit = (exit, fiber, i) => {
    doneCount++;
    if (exit._tag === "Failure") {
      failures.push(...exit.cause.reasons);
      if (doneCount >= len) {
        resume(failCause(causeFromReasons(failures)));
      }
      return;
    }
    const isWinner = !done;
    done = true;
    resume(fibers.size === 0 ? exit : flatMap(uninterruptible(fiberInterruptAll(fibers)), () => exit));
    if (isWinner && options?.onWinner) {
      options.onWinner({
        fiber,
        index: i,
        parentFiber: parent
      });
    }
  };
  for (let i = 0; i < len; i++) {
    const fiber = forkUnsafe(parent, effects[i], true, true, false);
    fibers.add(fiber);
    fiber.addObserver(exit => {
      fibers.delete(fiber);
      onExit(exit, fiber, i);
    });
    if (done) break;
  }
  return fiberInterruptAll(fibers);
}));
/** @internal */
export const raceAllFirst = (all, options) => withFiber(parent => callback(resume => {
  let done = false;
  const fibers = new Set();
  const onExit = exit => {
    done = true;
    resume(fibers.size === 0 ? exit : flatMap(uninterruptible(fiberInterruptAll(fibers)), () => exit));
  };
  let i = 0;
  for (const effect of all) {
    if (done) break;
    const index = i++;
    const fiber = forkUnsafe(parent, effect, true, true, false);
    fibers.add(fiber);
    fiber.addObserver(exit => {
      fibers.delete(fiber);
      const isWinner = !done;
      onExit(exit);
      if (isWinner && options?.onWinner) {
        options.onWinner({
          fiber,
          index,
          parentFiber: parent
        });
      }
    });
  }
  return fiberInterruptAll(fibers);
}));
/** @internal */
export const race = /*#__PURE__*/dual(args => isEffect(args[1]), (self, that, options) => raceAll([self, that], options));
/** @internal */
export const raceFirst = /*#__PURE__*/dual(args => isEffect(args[1]), (self, that, options) => raceAllFirst([self, that], options));
/** @internal */
export const flatMap = /*#__PURE__*/dual(2, (self, f) => {
  const onSuccess = Object.create(OnSuccessProto);
  onSuccess[args] = self;
  onSuccess[contA] = f.length !== 1 ? a => f(a) : f;
  return onSuccess;
});
const OnSuccessProto = /*#__PURE__*/makePrimitiveProto({
  op: "OnSuccess",
  [evaluate](fiber) {
    fiber._stack.push(this);
    return this[args];
  }
});
/** @internal */
export const matchCauseEffectEager = /*#__PURE__*/dual(2, (self, options) => {
  if (effectIsExit(self)) {
    return self._tag === "Success" ? options.onSuccess(self.value) : options.onFailure(self.cause);
  }
  return matchCauseEffect(self, options);
});
/** @internal */
export const effectIsExit = effect => ExitTypeId in effect;
/** @internal */
export const flatMapEager = /*#__PURE__*/dual(2, (self, f) => {
  if (effectIsExit(self)) {
    return self._tag === "Success" ? f(self.value) : self;
  }
  return flatMap(self, f);
});
// ----------------------------------------------------------------------------
// mapping & sequencing
// ----------------------------------------------------------------------------
/** @internal */
export const flatten = self => flatMap(self, identity);
/** @internal */
export const map = /*#__PURE__*/dual(2, (self, f) => flatMap(self, a => succeed(internalCall(() => f(a)))));
/** @internal */
export const mapEager = /*#__PURE__*/dual(2, (self, f) => effectIsExit(self) ? exitMap(self, f) : map(self, f));
/** @internal */
export const mapErrorEager = /*#__PURE__*/dual(2, (self, f) => effectIsExit(self) ? exitMapError(self, f) : mapError(self, f));
/** @internal */
export const mapBothEager = /*#__PURE__*/dual(2, (self, options) => effectIsExit(self) ? exitMapBoth(self, options) : mapBoth(self, options));
/** @internal */
export const catchEager = /*#__PURE__*/dual(2, (self, f) => {
  if (effectIsExit(self)) {
    if (self._tag === "Success") return self;
    const error = findError(self.cause);
    if (Result.isFailure(error)) return self;
    return f(error.success);
  }
  return catch_(self, f);
});
// ----------------------------------------------------------------------------
// Exit
// ----------------------------------------------------------------------------
/** @internal */
export const exitInterrupt = fiberId => exitFailCause(causeInterrupt(fiberId));
/** @internal */
export const exitIsSuccess = self => self._tag === "Success";
/** @internal */
export const exitFilterSuccess = self => self._tag === "Success" ? Result.succeed(self) : Result.fail(self);
/** @internal */
export const exitFilterValue = self => self._tag === "Success" ? Result.succeed(self.value) : Result.fail(self);
/** @internal */
export const exitIsFailure = self => self._tag === "Failure";
/** @internal */
export const exitFilterFailure = self => self._tag === "Failure" ? Result.succeed(self) : Result.fail(self);
/** @internal */
export const exitFilterCause = self => self._tag === "Failure" ? Result.succeed(self.cause) : Result.fail(self);
/** @internal */
export const exitFindError = /*#__PURE__*/Filter.composePassthrough(exitFilterCause, findError);
/** @internal */
export const exitFindDefect = /*#__PURE__*/Filter.composePassthrough(exitFilterCause, findDefect);
/** @internal */
export const exitHasInterrupts = self => self._tag === "Failure" && hasInterrupts(self.cause);
/** @internal */
export const exitHasDies = self => self._tag === "Failure" && hasDies(self.cause);
/** @internal */
export const exitHasFails = self => self._tag === "Failure" && hasFails(self.cause);
/** @internal */
export const exitVoid = /*#__PURE__*/exitSucceed(void 0);
/** @internal */
export const exitMap = /*#__PURE__*/dual(2, (self, f) => self._tag === "Success" ? exitSucceed(f(self.value)) : self);
/** @internal */
export const exitMapError = /*#__PURE__*/dual(2, (self, f) => {
  if (self._tag === "Success") return self;
  const error = findError(self.cause);
  if (Result.isFailure(error)) return self;
  return exitFail(f(error.success));
});
/** @internal */
export const exitMapBoth = /*#__PURE__*/dual(2, (self, options) => {
  if (self._tag === "Success") return exitSucceed(options.onSuccess(self.value));
  const error = findError(self.cause);
  if (Result.isFailure(error)) return self;
  return exitFail(options.onFailure(error.success));
});
/** @internal */
export const exitAs = /*#__PURE__*/dual(2, (self, b) => exitIsSuccess(self) ? exitSucceed(b) : self);
/** @internal */
export const exitZipRight = /*#__PURE__*/dual(2, (self, that) => exitIsSuccess(self) ? that : self);
/** @internal */
export const exitMatch = /*#__PURE__*/dual(2, (self, options) => exitIsSuccess(self) ? options.onSuccess(self.value) : options.onFailure(self.cause));
/** @internal */
export const exitAsVoid = /*#__PURE__*/exitAs(void 0);
/** @internal */
export const exitAsVoidAll = exits => {
  const failures = [];
  for (const exit of exits) {
    if (exit._tag === "Failure") {
      failures.push(...exit.cause.reasons);
    }
  }
  return failures.length === 0 ? exitVoid : exitFailCause(causeFromReasons(failures));
};
/** @internal */
export const exitGetSuccess = self => exitIsSuccess(self) ? Option.some(self.value) : Option.none();
/** @internal */
export const exitGetCause = self => exitIsFailure(self) ? Option.some(self.cause) : Option.none();
/** @internal */
export const exitFindErrorOption = self => {
  const error = exitFindError(self);
  return Result.isFailure(error) ? Option.none() : Option.some(error.success);
};
// ----------------------------------------------------------------------------
// environment
// ----------------------------------------------------------------------------
/** @internal */
export const service = fromYieldable;
/** @internal */
export const serviceOption = service => withFiber(fiber => succeed(Context.getOption(fiber.context, service)));
/** @internal */
export const serviceOptional = service => withFiber(fiber => fiber.context.mapUnsafe.has(service.key) ? succeed(Context.getUnsafe(fiber.context, service)) : fail(new NoSuchElementError()));
/** @internal */
export const updateContext = /*#__PURE__*/dual(2, (self, f) => withFiber(fiber => {
  const prevContext = fiber.context;
  const nextContext = f(prevContext);
  if (prevContext === nextContext) return self;
  fiber.setContext(nextContext);
  return onExitPrimitive(self, () => {
    fiber.setContext(prevContext);
    return undefined;
  });
}));
/** @internal */
export const updateService = /*#__PURE__*/dual(3, (self, service, f) => updateContext(self, s => {
  const prev = Context.getUnsafe(s, service);
  const next = f(prev);
  if (prev === next) return s;
  return Context.add(s, service, next);
}));
/** @internal */
export const context = () => getContext;
const getContext = /*#__PURE__*/withFiber(fiber => succeed(fiber.context));
/** @internal */
export const contextWith = f => withFiber(fiber => f(fiber.context));
/** @internal */
export const provideContext = /*#__PURE__*/dual(2, (self, context) => {
  if (effectIsExit(self)) return self;
  return updateContext(self, Context.merge(context));
});
/** @internal */
export const provideService = function () {
  if (arguments.length === 1) {
    return dual(2, (self, impl) => provideServiceImpl(self, arguments[0], impl));
  }
  return dual(3, (self, service, impl) => provideServiceImpl(self, service, impl)).apply(this, arguments);
};
const provideServiceImpl = (self, service, implementation) => updateContext(self, s => {
  const prev = s.mapUnsafe.get(service.key);
  if (prev === implementation) return s;
  return Context.add(s, service, implementation);
});
/** @internal */
export const provideServiceEffect = /*#__PURE__*/dual(3, (self, service, acquire) => flatMap(acquire, implementation => provideService(self, service, implementation)));
/** @internal */
export const withConcurrency = /*#__PURE__*/provideService(CurrentConcurrency);
// ----------------------------------------------------------------------------
// zipping
// ----------------------------------------------------------------------------
/** @internal */
export const zip = /*#__PURE__*/dual(args => isEffect(args[1]), (self, that, options) => zipWith(self, that, (a, a2) => [a, a2], options));
/** @internal */
export const zipWith = /*#__PURE__*/dual(args => isEffect(args[1]), (self, that, f, options) => options?.concurrent
// Use `all` exclusively for concurrent cases, as it introduces additional overhead due to the management of concurrency
? map(all([self, that], {
  concurrency: 2
}), ([a, a2]) => internalCall(() => f(a, a2))) : flatMap(self, a => map(that, a2 => internalCall(() => f(a, a2)))));
// ----------------------------------------------------------------------------
// filtering & conditionals
// ----------------------------------------------------------------------------
/* @internal */
export const filterOrFail = /*#__PURE__*/dual(args => isEffect(args[0]), (self, predicate, orFailWith) => filterOrElse(self, predicate, orFailWith ? a => fail(orFailWith(a)) : () => fail(new NoSuchElementError())));
/** @internal */
export const when = /*#__PURE__*/dual(2, (self, condition) => flatMap(condition, pass => pass ? asSome(self) : succeedNone));
// ----------------------------------------------------------------------------
// repetition
// ----------------------------------------------------------------------------
/** @internal */
export const replicate = /*#__PURE__*/dual(2, (self, n) => Array.from({
  length: n
}, () => self));
/** @internal */
export const replicateEffect = /*#__PURE__*/dual(args => isEffect(args[0]), (self, n, options) => all(replicate(self, n), options));
/** @internal */
export const forever = /*#__PURE__*/dual(args => isEffect(args[0]), (self, options) => whileLoop({
  while: constTrue,
  body: constant(options?.disableYield ? self : flatMap(self, _ => yieldNow)),
  step: constVoid
}));
// ----------------------------------------------------------------------------
// error handling
// ----------------------------------------------------------------------------
/** @internal */
export const catchCause = /*#__PURE__*/dual(2, (self, f) => {
  const onFailure = Object.create(OnFailureProto);
  onFailure[args] = self;
  onFailure[contE] = f.length !== 1 ? cause => f(cause) : f;
  return onFailure;
});
const OnFailureProto = /*#__PURE__*/makePrimitiveProto({
  op: "OnFailure",
  [evaluate](fiber) {
    fiber._stack.push(this);
    return this[args];
  }
});
/** @internal */
export const catchCauseIf = /*#__PURE__*/dual(3, (self, predicate, f) => catchCause(self, cause => {
  if (!predicate(cause)) {
    return failCause(cause);
  }
  return internalCall(() => f(cause));
}));
/** @internal */
export const catchCauseFilter = /*#__PURE__*/dual(3, (self, filter, f) => catchCause(self, cause => {
  const eb = filter(cause);
  return Result.isFailure(eb) ? failCause(eb.failure) : internalCall(() => f(eb.success, cause));
}));
/** @internal */
export const catch_ = /*#__PURE__*/dual(2, (self, f) => catchCauseFilter(self, findError, e => f(e)));
/** @internal */
export const catchNoSuchElement = self => matchEffect(self, {
  onFailure: error => isNoSuchElementError(error) ? succeedNone : fail(error),
  onSuccess: succeedSome
});
/** @internal */
export const catchDefect = /*#__PURE__*/dual(2, (self, f) => catchCauseFilter(self, findDefect, f));
/** @internal */
export const tapCause = /*#__PURE__*/dual(2, (self, f) => catchCause(self, cause => andThen(internalCall(() => f(cause)), failCause(cause))));
/** @internal */
export const tapCauseIf = /*#__PURE__*/dual(3, (self, predicate, f) => catchCauseIf(self, predicate, cause => andThen(internalCall(() => f(cause)), failCause(cause))));
/** @internal */
export const tapCauseFilter = /*#__PURE__*/dual(3, (self, filter, f) => catchCause(self, cause => {
  const result = filter(cause);
  if (Result.isFailure(result)) {
    return failCause(cause);
  }
  return andThen(internalCall(() => f(result.success, cause)), failCause(cause));
}));
/** @internal */
export const tapError = /*#__PURE__*/dual(2, (self, f) => tapCauseFilter(self, findError, e => f(e)));
/** @internal */
export const tapErrorTag = /*#__PURE__*/dual(3, (self, k, f) => {
  const predicate = Array.isArray(k) ? e => hasProperty(e, "_tag") && k.includes(e._tag) : isTagged(k);
  return tapError(self, error => predicate(error) ? f(error) : void_);
});
/** @internal */
export const tapDefect = /*#__PURE__*/dual(2, (self, f) => tapCauseFilter(self, findDefect, _ => f(_)));
/** @internal */
export const catchIf = /*#__PURE__*/dual(args => isEffect(args[0]), (self, predicate, f, orElse) => catchCause(self, cause => {
  const error = findError(cause);
  if (Result.isFailure(error)) return failCause(error.failure);
  if (!predicate(error.success)) {
    return orElse ? internalCall(() => orElse(error.success)) : failCause(cause);
  }
  return internalCall(() => f(error.success));
}));
/** @internal */
export const catchFilter = /*#__PURE__*/dual(args => isEffect(args[0]), (self, filter, f, orElse) => catchCause(self, cause => {
  const error = findError(cause);
  if (Result.isFailure(error)) return failCause(error.failure);
  const result = filter(error.success);
  if (Result.isFailure(result)) {
    return orElse ? internalCall(() => orElse(result.failure)) : failCause(cause);
  }
  return internalCall(() => f(result.success));
}));
/** @internal */
export const catchTag = /*#__PURE__*/dual(args => isEffect(args[0]), (self, k, f, orElse) => {
  const pred = Array.isArray(k) ? e => hasProperty(e, "_tag") && k.includes(e._tag) : isTagged(k);
  return catchIf(self, pred, f, orElse);
});
/** @internal */
export const catchTags = /*#__PURE__*/dual(args => isEffect(args[0]), (self, cases, orElse) => {
  let keys;
  return catchFilter(self, e => {
    keys ??= Object.keys(cases);
    return hasProperty(e, "_tag") && isString(e["_tag"]) && keys.includes(e["_tag"]) ? Result.succeed(e) : Result.fail(e);
  }, e => internalCall(() => cases[e["_tag"]](e)), orElse);
});
/** @internal */
export const catchReason = /*#__PURE__*/dual(args => isEffect(args[0]), (self, errorTag, reasonTag, f, orElse) => catchIf(self, e => isTagged(e, errorTag) && hasProperty(e, "reason"), e => {
  const reason = e.reason;
  if (isTagged(reason, reasonTag)) return f(reason, e);
  return orElse ? internalCall(() => orElse(reason, e)) : fail(e);
}));
/** @internal */
export const catchReasons = /*#__PURE__*/dual(args => isEffect(args[0]), (self, errorTag, cases, orElse) => {
  let keys;
  return catchIf(self, e => isTagged(e, errorTag) && hasProperty(e, "reason") && hasProperty(e.reason, "_tag") && isString(e.reason._tag), e => {
    const reason = e.reason;
    keys ??= Object.keys(cases);
    if (keys.includes(reason._tag)) {
      return internalCall(() => cases[reason._tag](reason, e));
    }
    return orElse ? internalCall(() => orElse(reason, e)) : fail(e);
  });
});
/** @internal */
export const unwrapReason = /*#__PURE__*/dual(2, (self, errorTag) => catchFilter(self, e => {
  if (isTagged(e, errorTag) && hasProperty(e, "reason")) {
    return Result.succeed(e.reason);
  }
  return Result.fail(e);
}, fail));
/** @internal */
export const mapErrorCause = /*#__PURE__*/dual(2, (self, f) => catchCause(self, cause => failCauseSync(() => f(cause))));
/** @internal */
export const mapError = /*#__PURE__*/dual(2, (self, f) => catch_(self, error => failSync(() => f(error))));
/* @internal */
export const mapBoth = /*#__PURE__*/dual(2, (self, options) => matchEffect(self, {
  onFailure: e => failSync(() => options.onFailure(e)),
  onSuccess: a => sync(() => options.onSuccess(a))
}));
/** @internal */
export const orDie = self => catch_(self, die);
/** @internal */
export const orElseSucceed = /*#__PURE__*/dual(2, (self, f) => catch_(self, _ => sync(f)));
/** @internal */
export const eventually = self => catch_(self, _ => flatMap(yieldNow, () => eventually(self)));
/** @internal */
export const ignore = /*#__PURE__*/dual(args => isEffect(args[0]), (self, options) => {
  if (!options?.log) {
    return matchEffect(self, {
      onFailure: _ => void_,
      onSuccess: _ => void_
    });
  }
  const logEffect = logWithLevel(options.log === true ? undefined : options.log);
  return matchCauseEffect(self, {
    onFailure(cause) {
      const failure = findFail(cause);
      return Result.isFailure(failure) ? failCause(failure.failure) : options.message === undefined ? logEffect(cause) : logEffect(options.message, cause);
    },
    onSuccess: _ => void_
  });
});
/** @internal */
export const ignoreCause = /*#__PURE__*/dual(args => isEffect(args[0]), (self, options) => {
  if (!options?.log) {
    return matchCauseEffect(self, {
      onFailure: _ => void_,
      onSuccess: _ => void_
    });
  }
  const logEffect = logWithLevel(options.log === true ? undefined : options.log);
  return matchCauseEffect(self, {
    onFailure: cause => options.message === undefined ? logEffect(cause) : logEffect(options.message, cause),
    onSuccess: _ => void_
  });
});
/** @internal */
export const option = self => match(self, {
  onFailure: Option.none,
  onSuccess: Option.some
});
/** @internal */
export const result = self => matchEager(self, {
  onFailure: Result.fail,
  onSuccess: Result.succeed
});
// ----------------------------------------------------------------------------
// pattern matching
// ----------------------------------------------------------------------------
/** @internal */
export const matchCauseEffect = /*#__PURE__*/dual(2, (self, options) => {
  const primitive = Object.create(OnSuccessAndFailureProto);
  primitive[args] = self;
  primitive[contA] = options.onSuccess.length !== 1 ? a => options.onSuccess(a) : options.onSuccess;
  primitive[contE] = options.onFailure.length !== 1 ? cause => options.onFailure(cause) : options.onFailure;
  return primitive;
});
const OnSuccessAndFailureProto = /*#__PURE__*/makePrimitiveProto({
  op: "OnSuccessAndFailure",
  [evaluate](fiber) {
    fiber._stack.push(this);
    return this[args];
  }
});
/** @internal */
export const matchCause = /*#__PURE__*/dual(2, (self, options) => matchCauseEffect(self, {
  onFailure: cause => sync(() => options.onFailure(cause)),
  onSuccess: value => sync(() => options.onSuccess(value))
}));
/** @internal */
export const matchEffect = /*#__PURE__*/dual(2, (self, options) => matchCauseEffect(self, {
  onFailure: cause => {
    const fail = cause.reasons.find(isFailReason);
    return fail ? internalCall(() => options.onFailure(fail.error)) : failCause(cause);
  },
  onSuccess: options.onSuccess
}));
/** @internal */
export const match = /*#__PURE__*/dual(2, (self, options) => matchEffect(self, {
  onFailure: error => sync(() => options.onFailure(error)),
  onSuccess: value => sync(() => options.onSuccess(value))
}));
/** @internal */
export const matchEager = /*#__PURE__*/dual(2, (self, options) => {
  if (effectIsExit(self)) {
    if (self._tag === "Success") return exitSucceed(options.onSuccess(self.value));
    const error = findError(self.cause);
    if (Result.isFailure(error)) return self;
    return exitSucceed(options.onFailure(error.success));
  }
  return match(self, options);
});
/** @internal */
export const matchCauseEager = /*#__PURE__*/dual(2, (self, options) => {
  if (effectIsExit(self)) {
    if (self._tag === "Success") return exitSucceed(options.onSuccess(self.value));
    return exitSucceed(options.onFailure(self.cause));
  }
  return matchCause(self, options);
});
/** @internal */
export const exit = self => effectIsExit(self) ? exitSucceed(self) : exitPrimitive(self);
const exitPrimitive = /*#__PURE__*/makePrimitive({
  op: "Exit",
  [evaluate](fiber) {
    fiber._stack.push(this);
    return this[args];
  },
  [contA](value, _, exit) {
    return succeed(exit ?? exitSucceed(value));
  },
  [contE](cause, _, exit) {
    return succeed(exit ?? exitFailCause(cause));
  }
});
// ----------------------------------------------------------------------------
// Condition checking
// ----------------------------------------------------------------------------
/** @internal */
export const isFailure = /*#__PURE__*/matchEager({
  onFailure: () => true,
  onSuccess: () => false
});
/** @internal */
export const isSuccess = /*#__PURE__*/matchEager({
  onFailure: () => false,
  onSuccess: () => true
});
// ----------------------------------------------------------------------------
// delays & timeouts
// ----------------------------------------------------------------------------
/** @internal */
export const delay = /*#__PURE__*/dual(2, (self, duration) => andThen(sleep(duration), self));
/** @internal */
export const timeoutOrElse = /*#__PURE__*/dual(2, (self, options) => raceFirst(self, flatMap(sleep(options.duration), options.orElse)));
/** @internal */
export const timeout = /*#__PURE__*/dual(2, (self, duration) => timeoutOrElse(self, {
  duration,
  orElse: () => fail(new TimeoutError())
}));
/** @internal */
export const timeoutOption = /*#__PURE__*/dual(2, (self, duration) => raceFirst(asSome(self), as(sleep(duration), Option.none())));
/** @internal */
export const timed = self => clockWith(clock => {
  const start = clock.currentTimeNanosUnsafe();
  return map(self, a => [Duration.nanos(clock.currentTimeNanosUnsafe() - start), a]);
});
// ----------------------------------------------------------------------------
// resources & finalization
// ----------------------------------------------------------------------------
/** @internal */
export const ScopeTypeId = "~effect/Scope";
/** @internal */
export const ScopeCloseableTypeId = "~effect/Scope/Closeable";
/** @internal */
export const scopeTag = /*#__PURE__*/Context.Service("effect/Scope");
/** @internal */
export const scopeClose = (self, exit_) => suspend(() => scopeCloseUnsafe(self, exit_) ?? void_);
/** @internal */
export const scopeCloseUnsafe = (self, exit_) => {
  if (self.state._tag === "Closed") return;
  const closed = {
    _tag: "Closed",
    exit: exit_
  };
  if (self.state._tag === "Empty") {
    self.state = closed;
    return;
  }
  const {
    finalizers
  } = self.state;
  self.state = closed;
  if (finalizers.size === 0) {
    return;
  } else if (finalizers.size === 1) {
    return finalizers.values().next().value(exit_);
  }
  return scopeCloseFinalizers(self, finalizers, exit_);
};
const scopeCloseFinalizers = /*#__PURE__*/fnUntraced(function* (self, finalizers, exit_) {
  let exits = [];
  const fibers = [];
  const arr = Array.from(finalizers.values());
  const parent = getCurrentFiber();
  for (let i = arr.length - 1; i >= 0; i--) {
    const finalizer = arr[i];
    if (self.strategy === "sequential") {
      exits.push(yield* exit(finalizer(exit_)));
    } else {
      fibers.push(forkUnsafe(parent, finalizer(exit_), true, true, "inherit"));
    }
  }
  if (fibers.length > 0) {
    exits = yield* fiberAwaitAll(fibers);
  }
  return yield* exitAsVoidAll(exits);
});
/** @internal */
export const scopeFork = (scope, finalizerStrategy) => sync(() => scopeForkUnsafe(scope, finalizerStrategy));
/** @internal */
export const scopeForkUnsafe = (scope, finalizerStrategy) => {
  const newScope = scopeMakeUnsafe(finalizerStrategy);
  if (scope.state._tag === "Closed") {
    newScope.state = scope.state;
    return newScope;
  }
  const key = {};
  scopeAddFinalizerUnsafe(scope, key, exit => scopeClose(newScope, exit));
  scopeAddFinalizerUnsafe(newScope, key, _ => sync(() => scopeRemoveFinalizerUnsafe(scope, key)));
  return newScope;
};
/** @internal */
export const scopeAddFinalizerExit = (scope, finalizer) => {
  return suspend(() => {
    if (scope.state._tag === "Closed") {
      return finalizer(scope.state.exit);
    }
    scopeAddFinalizerUnsafe(scope, {}, finalizer);
    return void_;
  });
};
/** @internal */
export const scopeAddFinalizer = (scope, finalizer) => scopeAddFinalizerExit(scope, constant(finalizer));
/** @internal */
export const scopeAddFinalizerUnsafe = (scope, key, finalizer) => {
  if (scope.state._tag === "Empty") {
    scope.state = {
      _tag: "Open",
      finalizers: new Map([[key, finalizer]])
    };
  } else if (scope.state._tag === "Open") {
    scope.state.finalizers.set(key, finalizer);
  }
};
/** @internal */
export const scopeRemoveFinalizerUnsafe = (scope, key) => {
  if (scope.state._tag === "Open") {
    scope.state.finalizers.delete(key);
  }
};
/** @internal */
export const scopeMakeUnsafe = (finalizerStrategy = "sequential") => ({
  [ScopeCloseableTypeId]: ScopeCloseableTypeId,
  [ScopeTypeId]: ScopeTypeId,
  strategy: finalizerStrategy,
  state: constScopeEmpty
});
const constScopeEmpty = {
  _tag: "Empty"
};
/** @internal */
export const scopeMake = finalizerStrategy => sync(() => scopeMakeUnsafe(finalizerStrategy));
/** @internal */
export const scope = /*#__PURE__*/scopeTag.asEffect();
/** @internal */
export const provideScope = /*#__PURE__*/provideService(scopeTag);
/** @internal */
export const scoped = self => withFiber(fiber => {
  const prev = fiber.context;
  const scope = scopeMakeUnsafe();
  fiber.setContext(Context.add(fiber.context, scopeTag, scope));
  return onExitPrimitive(self, exit => {
    fiber.setContext(prev);
    return scopeCloseUnsafe(scope, exit);
  });
});
/** @internal */
export const scopeUse = /*#__PURE__*/dual(2, (self, scope) => onExit(provideScope(self, scope), exit => suspend(() => scopeCloseUnsafe(scope, exit) ?? void_)));
/** @internal */
export const scopedWith = f => suspend(() => {
  const scope = scopeMakeUnsafe();
  return onExit(f(scope), exit => suspend(() => scopeCloseUnsafe(scope, exit) ?? void_));
});
/** @internal */
export const acquireRelease = (acquire, release, options) => contextWith(context => uninterruptibleMask(restore => flatMap(scope, scope => tap(options?.interruptible ? restore(acquire) : acquire, a => scopeAddFinalizerExit(scope, exit => provideContext(release(a, exit), context))))));
/** @internal */
export const addFinalizer = finalizer => flatMap(scope, scope => contextWith(context => scopeAddFinalizerExit(scope, exit => provideContext(finalizer(exit), context))));
/** @internal */
export const onExitPrimitive = /*#__PURE__*/makePrimitive({
  op: "OnExit",
  single: false,
  [evaluate](fiber) {
    fiber._stack.push(this);
    return this[args][0];
  },
  [contAll](fiber) {
    if (fiber.interruptible && this[args][2] !== true) {
      fiber._stack.push(setInterruptibleTrue);
      fiber.interruptible = false;
    }
  },
  [contA](value, _, exit) {
    exit ??= exitSucceed(value);
    const eff = this[args][1](exit);
    return eff ? flatMap(eff, _ => exit) : exit;
  },
  [contE](cause, _, exit) {
    exit ??= exitFailCause(cause);
    const eff = this[args][1](exit);
    return eff ? flatMap(eff, _ => exit) : exit;
  }
});
/** @internal */
export const onExit = /*#__PURE__*/dual(2, onExitPrimitive);
/** @internal */
export const ensuring = /*#__PURE__*/dual(2, (self, finalizer) => onExit(self, _ => finalizer));
/** @internal */
export const onExitIf = /*#__PURE__*/dual(3, (self, predicate, f) => onExit(self, exit => {
  if (!predicate(exit)) {
    return void_;
  }
  return f(exit);
}));
/** @internal */
export const onExitFilter = /*#__PURE__*/dual(3, (self, filter, f) => onExit(self, exit => {
  const b = filter(exit);
  return Result.isFailure(b) ? void_ : f(b.success, exit);
}));
/** @internal */
export const onError = /*#__PURE__*/dual(2, (self, f) => onExitFilter(self, exitFilterCause, f));
/** @internal */
export const onErrorIf = /*#__PURE__*/dual(3, (self, predicate, f) => onExitIf(self, exit => {
  if (exit._tag !== "Failure") {
    return false;
  }
  return predicate(exit.cause);
}, exit => f(exit.cause)));
/** @internal */
export const onErrorFilter = /*#__PURE__*/dual(3, (self, filter, f) => onExit(self, exit => {
  if (exit._tag !== "Failure") {
    return void_;
  }
  const result = filter(exit.cause);
  return Result.isFailure(result) ? void_ : f(result.success, exit.cause);
}));
/** @internal */
export const onInterrupt = /*#__PURE__*/dual(2, (self, finalizer) => onErrorFilter(causeFilterInterruptors, finalizer)(self));
/** @internal */
export const acquireUseRelease = (acquire, use, release) => uninterruptibleMask(restore => flatMap(acquire, a => onExitPrimitive(restore(use(a)), exit => release(a, exit), true)));
// ----------------------------------------------------------------------------
// Caching
// ----------------------------------------------------------------------------
/** @internal */
export const cachedInvalidateWithTTL = /*#__PURE__*/dual(2, (self, ttl) => sync(() => {
  const ttlMillis = Duration.toMillis(Duration.fromInputUnsafe(ttl));
  const isFinite = Number.isFinite(ttlMillis);
  const latch = makeLatchUnsafe(false);
  let expiresAt = 0;
  let running = false;
  let exit;
  const wait = flatMap(latch.await, () => exit);
  return [withFiber(fiber => {
    const clock = fiber.getRef(ClockRef);
    const now = isFinite ? clock.currentTimeMillisUnsafe() : 0;
    if (running || now < expiresAt) return exit ?? wait;
    running = true;
    latch.closeUnsafe();
    exit = undefined;
    return onExit(self, exit_ => sync(() => {
      running = false;
      expiresAt = clock.currentTimeMillisUnsafe() + ttlMillis;
      exit = exit_;
      latch.openUnsafe();
    }));
  }), sync(() => {
    expiresAt = 0;
    latch.closeUnsafe();
    exit = undefined;
  })];
}));
/** @internal */
export const cachedWithTTL = /*#__PURE__*/dual(2, (self, timeToLive) => map(cachedInvalidateWithTTL(self, timeToLive), tuple => tuple[0]));
/** @internal */
export const cached = self => cachedWithTTL(self, Duration.infinity);
// ----------------------------------------------------------------------------
// interruption
// ----------------------------------------------------------------------------
/** @internal */
export const interrupt = /*#__PURE__*/withFiber(fiber => failCause(causeInterrupt(fiber.id)));
/** @internal */
export const uninterruptible = self => withFiber(fiber => {
  if (!fiber.interruptible) return self;
  fiber.interruptible = false;
  fiber._stack.push(setInterruptibleTrue);
  return self;
});
const setInterruptible = /*#__PURE__*/makePrimitive({
  op: "SetInterruptible",
  [contAll](fiber) {
    fiber.interruptible = this[args];
    if (fiber._interruptedCause && fiber.interruptible) {
      return () => failCause(fiber._interruptedCause);
    }
  }
});
const setInterruptibleTrue = /*#__PURE__*/setInterruptible(true);
const setInterruptibleFalse = /*#__PURE__*/setInterruptible(false);
/** @internal */
export const interruptible = self => withFiber(fiber => {
  if (fiber.interruptible) return self;
  fiber.interruptible = true;
  fiber._stack.push(setInterruptibleFalse);
  if (fiber._interruptedCause) return failCause(fiber._interruptedCause);
  return self;
});
/** @internal */
export const uninterruptibleMask = f => withFiber(fiber => {
  if (!fiber.interruptible) return f(identity);
  fiber.interruptible = false;
  fiber._stack.push(setInterruptibleTrue);
  return f(interruptible);
});
/** @internal */
export const interruptibleMask = f => withFiber(fiber => {
  if (fiber.interruptible) return f(identity);
  fiber.interruptible = true;
  fiber._stack.push(setInterruptibleFalse);
  return f(uninterruptible);
});
/** @internal */
export const abortSignal = /*#__PURE__*/map(/*#__PURE__*/acquireRelease(/*#__PURE__*/sync(() => new AbortController()), controller => sync(() => controller.abort())), _ => _.signal);
// ========================================================================
// collecting & elements
// ========================================================================
/** @internal */
export const all = (arg, options) => {
  if (isIterable(arg)) {
    return options?.mode === "result" ? forEach(arg, result, options) : forEach(arg, identity, options);
  } else if (options?.discard) {
    return options.mode === "result" ? forEach(Object.values(arg), result, options) : forEach(Object.values(arg), identity, options);
  }
  return suspend(() => {
    const out = {};
    return as(forEach(Object.entries(arg), ([key, effect]) => map(options?.mode === "result" ? result(effect) : effect, value => {
      out[key] = value;
    }), {
      discard: true,
      concurrency: options?.concurrency
    }), out);
  });
};
/** @internal */
export const partition = /*#__PURE__*/dual(args => isIterable(args[0]) && !isEffect(args[0]), (elements, f, options) => map(forEach(elements, (a, i) => result(f(a, i)), options), results => Arr.partition(results, identity)));
/** @internal */
export const validate = /*#__PURE__*/dual(args => isIterable(args[0]) && !isEffect(args[0]), (elements, f, options) => flatMap(partition(elements, f, {
  concurrency: options?.concurrency
}), ([excluded, satisfying]) => {
  if (Arr.isArrayNonEmpty(excluded)) {
    return fail(excluded);
  }
  return options?.discard ? void_ : succeed(satisfying);
}));
/** @internal */
export const findFirst = /*#__PURE__*/dual(args => isIterable(args[0]) && !isEffect(args[0]), (elements, predicate) => suspend(() => {
  const iterator = elements[Symbol.iterator]();
  const next = iterator.next();
  if (!next.done) {
    return findFirstLoop(iterator, 0, predicate, next.value);
  }
  return succeed(Option.none());
}));
const findFirstLoop = (iterator, index, predicate, value) => flatMap(predicate(value, index), keep => {
  if (keep) {
    return succeed(Option.some(value));
  }
  const next = iterator.next();
  if (!next.done) {
    return findFirstLoop(iterator, index + 1, predicate, next.value);
  }
  return succeed(Option.none());
});
/** @internal */
export const findFirstFilter = /*#__PURE__*/dual(args => isIterable(args[0]) && !isEffect(args[0]), (elements, filter) => suspend(() => {
  const iterator = elements[Symbol.iterator]();
  const next = iterator.next();
  if (!next.done) {
    return findFirstFilterLoop(iterator, 0, filter, next.value);
  }
  return succeed(Option.none());
}));
const findFirstFilterLoop = (iterator, index, filter, value) => flatMap(filter(value, index), result => {
  if (Result.isSuccess(result)) {
    return succeed(Option.some(result.success));
  }
  const next = iterator.next();
  if (!next.done) {
    return findFirstFilterLoop(iterator, index + 1, filter, next.value);
  }
  return succeed(Option.none());
});
/** @internal */
export const whileLoop = /*#__PURE__*/makePrimitive({
  op: "While",
  [contA](value, fiber) {
    this[args].step(value);
    if (this[args].while()) {
      fiber._stack.push(this);
      return this[args].body();
    }
    return exitVoid;
  },
  [evaluate](fiber) {
    if (this[args].while()) {
      fiber._stack.push(this);
      return this[args].body();
    }
    return exitVoid;
  }
});
/** @internal */
export const forEach = /*#__PURE__*/dual(args => typeof args[1] === "function", (iterable, f, options) => withFiber(parent => {
  const concurrencyOption = options?.concurrency === "inherit" ? parent.getRef(CurrentConcurrency) : options?.concurrency ?? 1;
  const concurrency = concurrencyOption === "unbounded" ? Number.POSITIVE_INFINITY : Math.max(1, concurrencyOption);
  if (concurrency === 1) {
    return forEachSequential(iterable, f, options);
  }
  const items = Arr.fromIterable(iterable);
  let length = items.length;
  if (length === 0) {
    return options?.discard ? void_ : succeed([]);
  }
  const out = options?.discard ? undefined : new Array(length);
  const eff = forEachConcurrent({
    f,
    out
  }, items, {
    concurrency
  });
  return eff ? as(eff, out) : succeed(out);
}));
const forEachSequential = (iterable, f, options) => suspend(() => {
  const out = options?.discard ? undefined : [];
  const iterator = iterable[Symbol.iterator]();
  let state = iterator.next();
  let index = 0;
  return as(whileLoop({
    while: () => !state.done,
    body: () => f(state.value, index++),
    step: b => {
      if (out) out.push(b);
      state = iterator.next();
    }
  }), out);
});
const iterateEagerImpl = options => {
  const onItem = options.onItem;
  const step = options.step;
  return (state, items, opts) => {
    let index = opts?.start ?? 0;
    const end = opts?.end ?? items.length;
    const concurrency = opts?.concurrency ?? 1;
    let done = false;
    let parentFiber;
    let fibers;
    let resume;
    let interrupted = false;
    let terminal;
    let effect;
    const go = () => {
      let paused = false;
      for (; !terminal && index < end; index++) {
        const item = items[index];
        const eff = effect ?? onItem(state, item, index);
        // fast case (already an exit)
        if (effectIsExit(eff)) {
          terminal = step(state, item, eff, index);
          if (terminal) break;
          // Use flatMap for concurrency of 1
        } else if (concurrency === 1) {
          return flatMap(exit(eff), exit => {
            terminal = step(state, item, exit, index);
            index++;
            return terminal ?? go() ?? void_;
          });
          // We have an effect, so enter "async" mode
        } else if (!parentFiber) {
          return callback(cb => {
            parentFiber = getCurrentFiber();
            effect = eff;
            resume = cb;
            const result = go();
            if (result) return cb(result);
            return suspend(() => {
              terminal = exitVoid;
              interrupted = true;
              return fibers ? fiberInterruptAll(fibers) : void_;
            });
          });
          // Fork the effect with concurrency > 1
        } else {
          // Clear the temporary effect from capturing the parentFiber
          effect = undefined;
          const fiber = forkUnsafe(parentFiber, eff, true, true, "inherit");
          if (fiber._exit) {
            terminal = step(state, item, fiber._exit, index);
            if (terminal) break;
            continue;
          }
          // Add the fiber to the Set
          if (fibers) fibers.add(fiber);else fibers = new Set([fiber]);
          const currentIndex = index;
          fiber.addObserver(exit => {
            fibers.delete(fiber);
            if (terminal) {
              if (!interrupted && exit._tag === "Failure") {
                for (const reason of exit.cause.reasons) {
                  if (reason._tag === "Interrupt") continue;else if (terminal._tag === "Failure") {
                    ;
                    terminal.cause.reasons.push(reason);
                  } else {
                    terminal = exitFailCause(causeFromReasons([reason]));
                  }
                }
              }
            } else {
              const result = step(state, item, exit, currentIndex);
              if (result) {
                terminal = result._tag === "Failure" ? exitFailCause(causeFromReasons(result.cause.reasons.slice())) : result;
                go();
              }
            }
            if (paused) {
              const eff = go();
              if (eff) resume(eff);
            } else if (done && fibers.size === 0) {
              resume(terminal ?? void_);
            }
          });
          // Check if we have reached the concurrency limit
          if (fibers.size < concurrency) continue;
          paused = true;
          index++;
          return;
        }
      }
      done = true;
      if (terminal) {
        if (fibers && fibers.size > 0) {
          const annotations = fiberStackAnnotations(parentFiber);
          fibers.forEach(f => f.interruptUnsafe(parentFiber.id, annotations));
          return;
        }
        if (resume || terminal._tag === "Failure") {
          return terminal;
        }
      } else if (resume) {
        if (!fibers) {
          return exitVoid;
        } else if (fibers.size === 0) {
          resume(void_);
        }
      }
    };
    return go();
  };
};
/** @internal */
export const iterateEager = () => iterateEagerImpl;
const forEachConcurrent = /*#__PURE__*/iterateEagerImpl({
  onItem(state, item, index) {
    return state.f(item, index);
  },
  step(state, _, exit, index) {
    if (exit._tag === "Failure") return exit;else if (state.out) {
      state.out[index] = exit.value;
    }
  }
});
/* @internal */
export const filterOrElse = /*#__PURE__*/dual(3, (self, predicate, orElse) => flatMap(self, a => predicate(a) ? succeed(a) : orElse(a)));
/** @internal */
export const filterMapOrElse = /*#__PURE__*/dual(3, (self, filter, orElse) => flatMap(self, a => {
  const result = filter(a);
  return Result.isFailure(result) ? orElse(result.failure) : succeed(result.success);
}));
/* @internal */
export const filterMapOrFail = /*#__PURE__*/dual(args => isEffect(args[0]), (self, filter, orFailWith) => filterMapOrElse(self, filter, orFailWith ? x => fail(orFailWith(x)) : () => fail(new NoSuchElementError())));
/** @internal */
export const filter = /*#__PURE__*/dual(args => isIterable(args[0]) && !isEffect(args[0]), (elements, predicate, options) => suspend(() => {
  const out = [];
  return as(forEach(elements, (a, i) => {
    const result = predicate(a, i);
    if (typeof result === "boolean") {
      if (result) out.push(a);
      return void_;
    }
    return map(result, keep => {
      if (keep) {
        out.push(a);
      }
    });
  }, {
    discard: true,
    concurrency: options?.concurrency
  }), out);
}));
/** @internal */
export const filterMap = /*#__PURE__*/dual(args => isIterable(args[0]) && !isEffect(args[0]), (elements, filter) => suspend(() => {
  const out = [];
  for (const a of elements) {
    const result = filter(a);
    if (Result.isSuccess(result)) {
      out.push(result.success);
    }
  }
  return succeed(out);
}));
/** @internal */
export const filterMapEffect = /*#__PURE__*/dual(args => isIterable(args[0]) && !isEffect(args[0]), (elements, filter, options) => suspend(() => {
  const out = [];
  return as(forEach(elements, a => map(filter(a), result => {
    if (Result.isSuccess(result)) {
      out.push(result.success);
    }
  }), {
    discard: true,
    concurrency: options?.concurrency
  }), out);
}));
// ----------------------------------------------------------------------------
// do notation
// ----------------------------------------------------------------------------
/** @internal */
export const Do = /*#__PURE__*/succeed({});
/** @internal */
export const bindTo = /*#__PURE__*/doNotation.bindTo(map);
/** @internal */
export const bind = /*#__PURE__*/doNotation.bind(map, flatMap);
/** @internal */
const let_ = /*#__PURE__*/doNotation.let_(map);
/** @internal */
export { let_ as let };
// ----------------------------------------------------------------------------
// fibers & forking
// ----------------------------------------------------------------------------
/** @internal */
export const forkChild = /*#__PURE__*/dual(args => isEffect(args[0]), (self, options) => withFiber(fiber => {
  interruptChildrenPatch();
  return succeed(forkUnsafe(fiber, self, options?.startImmediately, false, options?.uninterruptible ?? false));
}));
/** @internal */
export const forkUnsafe = (parent, effect, immediate = false, daemon = false, uninterruptible = false) => {
  const interruptible = uninterruptible === "inherit" ? parent.interruptible : !uninterruptible;
  const child = new FiberImpl(parent.context, interruptible);
  if (immediate) {
    child.evaluate(effect);
  } else {
    parent.currentDispatcher.scheduleTask(() => child.evaluate(effect), 0);
  }
  if (!daemon && !child._exit) {
    parent.children().add(child);
    child.addObserver(() => parent._children.delete(child));
  }
  return child;
};
/** @internal */
export const forkDetach = /*#__PURE__*/dual(args => isEffect(args[0]), (self, options) => withFiber(fiber => succeed(forkUnsafe(fiber, self, options?.startImmediately, true, options?.uninterruptible))));
/** @internal */
export const awaitAllChildren = self => withFiber(fiber => {
  const initialChildren = fiber._children && Arr.fromIterable(fiber._children);
  return onExit(self, _ => {
    let children = fiber._children;
    if (children === undefined || children.size === 0) {
      return void_;
    } else if (initialChildren) {
      children = Iterable.filter(children, child => !initialChildren.includes(child));
    }
    return asVoid(fiberAwaitAll(children));
  });
});
/** @internal */
export const forkIn = /*#__PURE__*/dual(args => isEffect(args[0]), (self, scope, options) => withFiber(parent => {
  const fiber = forkUnsafe(parent, self, options?.startImmediately, true, options?.uninterruptible);
  if (!fiber._exit) {
    if (scope.state._tag !== "Closed") {
      const key = {};
      const finalizer = () => withFiberId(interruptor => interruptor === fiber.id ? void_ : fiberInterrupt(fiber));
      scopeAddFinalizerUnsafe(scope, key, finalizer);
      fiber.addObserver(() => scopeRemoveFinalizerUnsafe(scope, key));
    } else {
      fiber.interruptUnsafe(parent.id, fiberStackAnnotations(parent));
    }
  }
  return succeed(fiber);
}));
/** @internal */
export const forkScoped = /*#__PURE__*/dual(args => isEffect(args[0]), (self, options) => flatMap(scope, scope => forkIn(self, scope, options)));
// ----------------------------------------------------------------------------
// execution
// ----------------------------------------------------------------------------
/** @internal */
export const runForkWith = context => (effect, options) => {
  const fiber = new FiberImpl(options?.scheduler ? Context.add(context, Scheduler.Scheduler, options.scheduler) : context, options?.uninterruptible !== true);
  fiber.evaluate(effect);
  if (fiber._exit) return fiber;
  if (options?.signal) {
    if (options.signal.aborted) {
      fiber.interruptUnsafe();
    } else {
      const abort = () => fiber.interruptUnsafe();
      options.signal.addEventListener("abort", abort, {
        once: true
      });
      fiber.addObserver(() => options.signal.removeEventListener("abort", abort));
    }
  }
  if (options?.onFiberStart) {
    options.onFiberStart(fiber);
  }
  return fiber;
};
/** @internal */
export const fiberRunIn = /*#__PURE__*/dual(2, (self, scope) => {
  if (self._exit) {
    return self;
  } else if (scope.state._tag === "Closed") {
    self.interruptUnsafe(self.id);
    return self;
  }
  const key = {};
  scopeAddFinalizerUnsafe(scope, key, () => fiberInterrupt(self));
  self.addObserver(() => scopeRemoveFinalizerUnsafe(scope, key));
  return self;
});
/** @internal */
export const runFork = /*#__PURE__*/runForkWith(/*#__PURE__*/Context.empty());
/** @internal */
export const runCallbackWith = context => {
  const runFork = runForkWith(context);
  return (effect, options) => {
    const fiber = runFork(effect, options);
    if (options?.onExit) {
      fiber.addObserver(options.onExit);
    }
    return interruptor => {
      return fiber.interruptUnsafe(interruptor);
    };
  };
};
/** @internal */
export const runCallback = /*#__PURE__*/runCallbackWith(/*#__PURE__*/Context.empty());
/** @internal */
export const runPromiseExitWith = context => {
  const runFork = runForkWith(context);
  return (effect, options) => {
    const fiber = runFork(effect, options);
    return new Promise(resolve => {
      fiber.addObserver(exit => resolve(exit));
    });
  };
};
/** @internal */
export const runPromiseExit = /*#__PURE__*/runPromiseExitWith(/*#__PURE__*/Context.empty());
/** @internal */
export const runPromiseWith = context => {
  const runPromiseExit = runPromiseExitWith(context);
  return (effect, options) => runPromiseExit(effect, options).then(exit => {
    if (exit._tag === "Failure") {
      throw causeSquash(exit.cause);
    }
    return exit.value;
  });
};
/** @internal */
export const runPromise = /*#__PURE__*/runPromiseWith(/*#__PURE__*/Context.empty());
/** @internal */
export const runSyncExitWith = context => {
  const runFork = runForkWith(context);
  return effect => {
    if (effectIsExit(effect)) return effect;
    const scheduler = new Scheduler.MixedScheduler("sync");
    const fiber = runFork(effect, {
      scheduler
    });
    fiber.currentDispatcher?.flush();
    return fiber._exit ?? exitDie(new AsyncFiberError(fiber));
  };
};
/** @internal */
export const runSyncExit = /*#__PURE__*/runSyncExitWith(/*#__PURE__*/Context.empty());
/** @internal */
export const runSyncWith = context => {
  const runSyncExit = runSyncExitWith(context);
  return effect => {
    const exit = runSyncExit(effect);
    if (exit._tag === "Failure") throw causeSquash(exit.cause);
    return exit.value;
  };
};
/** @internal */
export const runSync = /*#__PURE__*/runSyncWith(/*#__PURE__*/Context.empty());
const succeedTrue = /*#__PURE__*/succeed(true);
const succeedFalse = /*#__PURE__*/succeed(false);
class Latch {
  waiters = [];
  scheduled = false;
  isOpen;
  constructor(isOpen) {
    this.isOpen = isOpen;
  }
  scheduleUnsafe(fiber) {
    if (this.scheduled || this.waiters.length === 0) {
      return succeedTrue;
    }
    this.scheduled = true;
    fiber.currentDispatcher.scheduleTask(this.flushWaiters, 0);
    return succeedTrue;
  }
  flushWaiters = () => {
    this.scheduled = false;
    const waiters = this.waiters;
    this.waiters = [];
    for (let i = 0; i < waiters.length; i++) {
      waiters[i](exitVoid);
    }
  };
  open = /*#__PURE__*/withFiber(fiber => {
    if (this.isOpen) return succeedFalse;
    this.isOpen = true;
    return this.scheduleUnsafe(fiber);
  });
  release = /*#__PURE__*/withFiber(fiber => this.isOpen ? succeedFalse : this.scheduleUnsafe(fiber));
  openUnsafe() {
    if (this.isOpen) return false;
    this.isOpen = true;
    this.flushWaiters();
    return true;
  }
  await = /*#__PURE__*/callback(resume => {
    if (this.isOpen) {
      return resume(void_);
    }
    this.waiters.push(resume);
    return sync(() => {
      const index = this.waiters.indexOf(resume);
      if (index !== -1) {
        this.waiters.splice(index, 1);
      }
    });
  });
  closeUnsafe() {
    if (!this.isOpen) return false;
    this.isOpen = false;
    return true;
  }
  close = /*#__PURE__*/sync(() => this.closeUnsafe());
  whenOpen = self => flatMap(this.await, () => self);
}
/** @internal */
export const makeLatchUnsafe = open => new Latch(open ?? false);
/** @internal */
export const makeLatch = open => sync(() => makeLatchUnsafe(open));
// ----------------------------------------------------------------------------
// Tracer
// ----------------------------------------------------------------------------
/** @internal */
export const tracer = /*#__PURE__*/withFiber(fiber => succeed(fiber.getRef(Tracer.Tracer)));
/** @internal */
export const withTracer = /*#__PURE__*/dual(2, (effect, tracer) => provideService(effect, Tracer.Tracer, tracer));
/** @internal */
export const withTracerEnabled = /*#__PURE__*/provideService(TracerEnabled);
/** @internal */
export const withTracerTiming = /*#__PURE__*/provideService(TracerTimingEnabled);
const bigint0 = /*#__PURE__*/BigInt(0);
const NoopSpanProto = {
  _tag: "Span",
  spanId: "noop",
  traceId: "noop",
  sampled: false,
  status: {
    _tag: "Ended",
    startTime: bigint0,
    endTime: bigint0,
    exit: exitVoid
  },
  attributes: /*#__PURE__*/new Map(),
  links: [],
  kind: "internal",
  attribute() {},
  event() {},
  end() {},
  addLinks() {}
};
/** @internal */
export const noopSpan = options => Object.assign(Object.create(NoopSpanProto), options);
const filterDisablePropagation = span => {
  if (!span) return Option.none();
  return Context.get(span.annotations, Tracer.DisablePropagation) ? span._tag === "Span" ? filterDisablePropagation(Option.getOrUndefined(span.parent)) : Option.none() : Option.some(span);
};
/** @internal */
export const makeSpanUnsafe = (fiber, name, options) => {
  const disablePropagation = !fiber.getRef(TracerEnabled) || options?.annotations && Context.get(options.annotations, Tracer.DisablePropagation);
  const parent = options?.parent !== undefined ? Option.some(options.parent) : options?.root ? Option.none() : filterDisablePropagation(fiber.currentSpan);
  let span;
  if (disablePropagation) {
    span = noopSpan({
      name,
      parent,
      annotations: Context.add(options?.annotations ?? Context.empty(), Tracer.DisablePropagation, true)
    });
  } else {
    const tracer = fiber.getRef(Tracer.Tracer);
    const clock = fiber.getRef(ClockRef);
    const timingEnabled = fiber.getRef(TracerTimingEnabled);
    const annotationsFromEnv = fiber.getRef(TracerSpanAnnotations);
    const linksFromEnv = fiber.getRef(TracerSpanLinks);
    const level = options?.level ?? fiber.getRef(Tracer.CurrentTraceLevel);
    const links = options?.links !== undefined ? [...linksFromEnv, ...options.links] : linksFromEnv.slice();
    span = tracer.span({
      name,
      parent,
      annotations: options?.annotations ?? Context.empty(),
      links,
      startTime: timingEnabled ? clock.currentTimeNanosUnsafe() : BigInt(0),
      kind: options?.kind ?? "internal",
      root: options?.root ?? Option.isNone(parent),
      sampled: options?.sampled ?? (Option.isSome(parent) && parent.value.sampled === false ? false : !isLogLevelGreaterThan(fiber.getRef(Tracer.MinimumTraceLevel), level))
    });
    for (const [key, value] of Object.entries(annotationsFromEnv)) {
      span.attribute(key, value);
    }
    if (options?.attributes !== undefined) {
      for (const [key, value] of Object.entries(options.attributes)) {
        span.attribute(key, value);
      }
    }
  }
  return span;
};
/** @internal */
export const makeSpan = (name, options) => withFiber(fiber => succeed(makeSpanUnsafe(fiber, name, options)));
/** @internal */
export const makeSpanScoped = (name, options) => uninterruptible(withFiber(fiber => {
  const scope = Context.getUnsafe(fiber.context, scopeTag);
  const span = makeSpanUnsafe(fiber, name, options ?? {});
  const clock = fiber.getRef(ClockRef);
  const timingEnabled = fiber.getRef(TracerTimingEnabled);
  return as(scopeAddFinalizerExit(scope, exit => endSpan(span, exit, clock, timingEnabled)), span);
}));
/** @internal */
export const withSpanScoped = function () {
  const dataFirst = typeof arguments[0] !== "string";
  const name = dataFirst ? arguments[1] : arguments[0];
  const options = addSpanStackTrace(dataFirst ? arguments[2] : arguments[1]);
  if (dataFirst) {
    const self = arguments[0];
    return flatMap(makeSpanScoped(name, options), span => withParentSpan(self, span, options));
  }
  return self => flatMap(makeSpanScoped(name, options), span => withParentSpan(self, span, options));
};
const provideSpanStackFrame = (name, stack) => {
  stack = typeof stack === "function" ? stack : constUndefined;
  return updateService(CurrentStackFrame, parent => ({
    name,
    stack,
    parent
  }));
};
/** @internal */
export const spanAnnotations = /*#__PURE__*/TracerSpanAnnotations.asEffect();
/** @internal */
export const spanLinks = /*#__PURE__*/TracerSpanLinks.asEffect();
/** @internal */
export const linkSpans = /*#__PURE__*/dual(args => isEffect(args[0]), (self, span, attributes = {}) => {
  const spans = Array.isArray(span) ? span : [span];
  const links = spans.map(span => ({
    span,
    attributes
  }));
  return updateService(self, TracerSpanLinks, current => [...current, ...links]);
});
/** @internal */
export const endSpan = (span, exit, clock, timingEnabled) => sync(() => {
  if (span.status._tag === "Ended") return;
  span.end(timingEnabled ? clock.currentTimeNanosUnsafe() : bigint0, exit);
});
/** @internal */
export const useSpan = (name, ...args) => {
  const options = args.length === 1 ? undefined : args[0];
  const evaluate = args[args.length - 1];
  return withFiber(fiber => {
    const span = makeSpanUnsafe(fiber, name, options);
    const clock = fiber.getRef(ClockRef);
    return onExit(internalCall(() => evaluate(span)), exit => sync(() => {
      if (span.status._tag === "Ended") return;
      span.end(clock.currentTimeNanosUnsafe(), exit);
    }));
  });
};
const provideParentSpan = /*#__PURE__*/provideService(Tracer.ParentSpan);
/** @internal */
export const withParentSpan = function () {
  const dataFirst = isEffect(arguments[0]);
  const span = dataFirst ? arguments[1] : arguments[0];
  let options = dataFirst ? arguments[2] : arguments[1];
  let provideStackFrame = identity;
  if (span._tag === "Span") {
    options = addSpanStackTrace(options);
    provideStackFrame = provideSpanStackFrame(span.name, options?.captureStackTrace);
  }
  if (dataFirst) {
    return provideParentSpan(provideStackFrame(arguments[0]), span);
  }
  return self => provideParentSpan(provideStackFrame(self), span);
};
/** @internal */
export const withSpan = function () {
  const dataFirst = typeof arguments[0] !== "string";
  const name = dataFirst ? arguments[1] : arguments[0];
  const traceOptions = addSpanStackTrace(arguments[2]);
  if (dataFirst) {
    const self = arguments[0];
    return useSpan(name, arguments[2], span => withParentSpan(self, span, traceOptions));
  }
  const fnArg = typeof arguments[1] === "function" ? arguments[1] : undefined;
  const options = fnArg ? undefined : arguments[1];
  return (self, ...args) => useSpan(name, fnArg ? fnArg(...args) : options, span => withParentSpan(self, span, traceOptions));
};
/** @internal */
export const annotateSpans = /*#__PURE__*/dual(args => isEffect(args[0]), (effect, ...args) => updateService(effect, TracerSpanAnnotations, annotations => {
  const newAnnotations = {
    ...annotations
  };
  if (args.length === 1) {
    Object.assign(newAnnotations, args[0]);
  } else {
    newAnnotations[args[0]] = args[1];
  }
  return newAnnotations;
}));
/** @internal */
export const annotateCurrentSpan = (...args) => withFiber(fiber => {
  const span = fiber.currentSpanLocal;
  if (span) {
    if (args.length === 1) {
      for (const [key, value] of Object.entries(args[0])) {
        span.attribute(key, value);
      }
    } else {
      span.attribute(args[0], args[1]);
    }
  }
  return void_;
});
/** @internal */
export const currentSpan = /*#__PURE__*/withFiber(fiber => {
  const span = fiber.currentSpanLocal;
  return span ? succeed(span) : fail(new NoSuchElementError());
});
/** @internal */
export const currentParentSpan = /*#__PURE__*/serviceOptional(Tracer.ParentSpan);
// ----------------------------------------------------------------------------
// Clock
// ----------------------------------------------------------------------------
/** @internal */
export const ClockRef = /*#__PURE__*/Context.Reference("effect/Clock", {
  defaultValue: () => new ClockImpl()
});
const MAX_TIMER_MILLIS = 2 ** 31 - 1;
class ClockImpl {
  currentTimeMillisUnsafe() {
    return Date.now();
  }
  currentTimeMillis = /*#__PURE__*/sync(() => this.currentTimeMillisUnsafe());
  currentTimeNanosUnsafe() {
    return processOrPerformanceNow();
  }
  currentTimeNanos = /*#__PURE__*/sync(() => this.currentTimeNanosUnsafe());
  sleep(duration) {
    const millis = Duration.toMillis(duration);
    if (millis <= 0) return yieldNow;
    return callback(resume => {
      if (millis > MAX_TIMER_MILLIS) return;
      const handle = setTimeout(() => resume(void_), millis);
      return sync(() => clearTimeout(handle));
    });
  }
}
const performanceNowNanos = /*#__PURE__*/function () {
  const bigint1e6 = /*#__PURE__*/BigInt(1_000_000);
  if (typeof performance === "undefined" || typeof performance.now === "undefined") {
    return () => BigInt(Date.now()) * bigint1e6;
  } else if (typeof performance.timeOrigin === "number" && performance.timeOrigin === 0) {
    return () => BigInt(Math.round(performance.now() * 1_000_000));
  }
  const origin = /*#__PURE__*/BigInt(/*#__PURE__*/Date.now()) * bigint1e6 - /*#__PURE__*/BigInt(/*#__PURE__*/Math.round(/*#__PURE__*/performance.now() * 1_000_000));
  return () => origin + BigInt(Math.round(performance.now() * 1_000_000));
}();
const processOrPerformanceNow = /*#__PURE__*/function () {
  const processHrtime = typeof process === "object" && "hrtime" in process && typeof process.hrtime.bigint === "function" ? process.hrtime : undefined;
  if (!processHrtime) {
    return performanceNowNanos;
  }
  const origin = /*#__PURE__*/performanceNowNanos() - /*#__PURE__*/processHrtime.bigint();
  return () => origin + processHrtime.bigint();
}();
/** @internal */
export const clockWith = f => withFiber(fiber => f(fiber.getRef(ClockRef)));
/** @internal */
export const sleep = duration => clockWith(clock => clock.sleep(Duration.fromInputUnsafe(duration)));
/** @internal */
export const currentTimeMillis = /*#__PURE__*/clockWith(clock => clock.currentTimeMillis);
/** @internal */
export const currentTimeNanos = /*#__PURE__*/clockWith(clock => clock.currentTimeNanos);
// ----------------------------------------------------------------------------
// Errors
// ----------------------------------------------------------------------------
/** @internal */
export const TimeoutErrorTypeId = "~effect/Cause/TimeoutError";
/** @internal */
export const isTimeoutError = u => hasProperty(u, TimeoutErrorTypeId);
/** @internal */
export class TimeoutError extends /*#__PURE__*/TaggedError("TimeoutError") {
  [TimeoutErrorTypeId] = TimeoutErrorTypeId;
  constructor(message) {
    super({
      message
    });
  }
}
/** @internal */
export const IllegalArgumentErrorTypeId = "~effect/Cause/IllegalArgumentError";
/** @internal */
export const isIllegalArgumentError = u => hasProperty(u, IllegalArgumentErrorTypeId);
/** @internal */
export class IllegalArgumentError extends /*#__PURE__*/TaggedError("IllegalArgumentError") {
  [IllegalArgumentErrorTypeId] = IllegalArgumentErrorTypeId;
  constructor(message) {
    super({
      message
    });
  }
}
/** @internal */
export const ExceededCapacityErrorTypeId = "~effect/Cause/ExceededCapacityError";
/** @internal */
export const isExceededCapacityError = u => hasProperty(u, ExceededCapacityErrorTypeId);
/** @internal */
export class ExceededCapacityError extends /*#__PURE__*/TaggedError("ExceededCapacityError") {
  [ExceededCapacityErrorTypeId] = ExceededCapacityErrorTypeId;
  constructor(message) {
    super({
      message
    });
  }
}
/** @internal */
export const AsyncFiberErrorTypeId = "~effect/Cause/AsyncFiberError";
/** @internal */
export const isAsyncFiberError = u => hasProperty(u, AsyncFiberErrorTypeId);
/** @internal */
export class AsyncFiberError extends /*#__PURE__*/TaggedError("AsyncFiberError") {
  [AsyncFiberErrorTypeId] = AsyncFiberErrorTypeId;
  constructor(fiber) {
    super({
      message: "An asynchronous Effect was executed with Effect.runSync",
      fiber
    });
  }
}
/** @internal */
export const UnknownErrorTypeId = "~effect/Cause/UnknownError";
/** @internal */
export const isUnknownError = u => hasProperty(u, UnknownErrorTypeId);
/** @internal */
export class UnknownError extends /*#__PURE__*/TaggedError("UnknownError") {
  [UnknownErrorTypeId] = UnknownErrorTypeId;
  constructor(cause, message) {
    super({
      message,
      cause
    });
  }
}
// ----------------------------------------------------------------------------
// Console
// ----------------------------------------------------------------------------
/** @internal */
export const ConsoleRef = /*#__PURE__*/Context.Reference("effect/Console/CurrentConsole", {
  defaultValue: () => globalThis.console
});
// ----------------------------------------------------------------------------
// LogLevel
// ----------------------------------------------------------------------------
/** @internal */
export const logLevelToOrder = level => {
  switch (level) {
    case "All":
      return Number.MIN_SAFE_INTEGER;
    case "Fatal":
      return 50_000;
    case "Error":
      return 40_000;
    case "Warn":
      return 30_000;
    case "Info":
      return 20_000;
    case "Debug":
      return 10_000;
    case "Trace":
      return 0;
    case "None":
      return Number.MAX_SAFE_INTEGER;
  }
};
/** @internal */
export const LogLevelOrder = /*#__PURE__*/Order.mapInput(Order.Number, logLevelToOrder);
/** @internal */
export const isLogLevelGreaterThan = /*#__PURE__*/Order.isGreaterThan(LogLevelOrder);
// ----------------------------------------------------------------------------
// Logger
// ----------------------------------------------------------------------------
/** @internal */
export const CurrentLoggers = /*#__PURE__*/Context.Reference("effect/Loggers/CurrentLoggers", {
  defaultValue: () => new Set([defaultLogger, tracerLogger])
});
/** @internal */
export const LogToStderr = /*#__PURE__*/Context.Reference("effect/Logger/LogToStderr", {
  defaultValue: constFalse
});
/** @internal */
export const annotateLogsScoped = function () {
  const entries = typeof arguments[0] === "string" ? [[arguments[0], arguments[1]]] : Object.entries(arguments[0]);
  return uninterruptible(withFiber(fiber => {
    const prev = fiber.getRef(CurrentLogAnnotations);
    const next = {
      ...prev
    };
    for (let i = 0; i < entries.length; i++) {
      const [key, value] = entries[i];
      next[key] = value;
    }
    fiber.setContext(Context.add(fiber.context, CurrentLogAnnotations, next));
    return scopeAddFinalizerExit(Context.getUnsafe(fiber.context, scopeTag), _ => {
      const current = fiber.getRef(CurrentLogAnnotations);
      const next = {
        ...current
      };
      for (let i = 0; i < entries.length; i++) {
        const [key, value] = entries[i];
        if (current[key] !== value) continue;
        if (key in prev) {
          next[key] = prev[key];
        } else {
          delete next[key];
        }
      }
      fiber.setContext(Context.add(fiber.context, CurrentLogAnnotations, next));
      return void_;
    });
  }));
};
/** @internal */
export const LoggerTypeId = "~effect/Logger";
const LoggerProto = {
  [LoggerTypeId]: {
    _Message: identity,
    _Output: identity
  },
  pipe() {
    return pipeArguments(this, arguments);
  }
};
/** @internal */
export const loggerMake = log => {
  const self = Object.create(LoggerProto);
  self.log = log;
  return self;
};
/**
 * Sanitize a given string by replacing spaces, equal signs, and double quotes
 * with underscores.
 *
 * @internal
 */
export const formatLabel = key => key.replace(/[\s="]/g, "_");
/**
 * Formats a log span into a `<label>=<value>ms` string.
 *
 * @internal
 */
export const formatLogSpan = (self, now) => {
  const label = formatLabel(self[0]);
  return `${label}=${now - self[1]}ms`;
};
/** @internal */
export const structuredMessage = u => {
  switch (typeof u) {
    case "bigint":
    case "function":
    case "symbol":
      {
        return String(u);
      }
    default:
      {
        return toJson(u);
      }
  }
};
/** @internal */
export const logWithLevel = level => (...message) => {
  let cause = undefined;
  for (let i = 0, len = message.length; i < len; i++) {
    const msg = message[i];
    if (isCause(msg)) {
      if (cause) {
        ;
        message.splice(i, 1);
      } else {
        message = message.slice(0, i).concat(message.slice(i + 1));
      }
      cause = cause ? causeFromReasons(cause.reasons.concat(msg.reasons)) : msg;
      i--;
    }
  }
  if (cause === undefined) {
    cause = causeEmpty;
  }
  return withFiber(fiber => {
    const logLevel = level ?? fiber.currentLogLevel;
    if (isLogLevelGreaterThan(fiber.minimumLogLevel, logLevel)) {
      return void_;
    }
    const clock = fiber.getRef(ClockRef);
    const loggers = fiber.getRef(CurrentLoggers);
    if (loggers.size > 0) {
      const date = new Date(clock.currentTimeMillisUnsafe());
      for (const logger of loggers) {
        logger.log({
          cause,
          fiber,
          date,
          logLevel,
          message
        });
      }
    }
    return void_;
  });
};
const withColor = (text, ...colors) => {
  let out = "";
  for (let i = 0; i < colors.length; i++) {
    out += `\x1b[${colors[i]}m`;
  }
  return out + text + "\x1b[0m";
};
const withColorNoop = (text, ..._colors) => text;
const colors = {
  bold: "1",
  red: "31",
  green: "32",
  yellow: "33",
  blue: "34",
  cyan: "36",
  white: "37",
  gray: "90",
  black: "30",
  bgBrightRed: "101"
};
const logLevelColors = {
  None: [],
  All: [],
  Trace: [colors.gray],
  Debug: [colors.blue],
  Info: [colors.green],
  Warn: [colors.yellow],
  Error: [colors.red],
  Fatal: [colors.bgBrightRed, colors.black]
};
const logLevelStyle = {
  None: "",
  All: "",
  Trace: "color:gray",
  Debug: "color:blue",
  Info: "color:green",
  Warn: "color:orange",
  Error: "color:red",
  Fatal: "background-color:red;color:white"
};
const defaultDateFormat = date => `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${date.getSeconds().toString().padStart(2, "0")}.${date.getMilliseconds().toString().padStart(3, "0")}`;
const hasProcessStdout = typeof process === "object" && process !== null && typeof process.stdout === "object" && process.stdout !== null;
const processStdoutIsTTY = hasProcessStdout && process.stdout.isTTY === true;
const hasProcessStdoutOrDeno = hasProcessStdout || "Deno" in globalThis;
/** @internal */
export const consolePretty = options => {
  const mode_ = options?.mode ?? "auto";
  const mode = mode_ === "auto" ? hasProcessStdoutOrDeno ? "tty" : "browser" : mode_;
  const isBrowser = mode === "browser";
  const showColors = typeof options?.colors === "boolean" ? options.colors : processStdoutIsTTY || isBrowser;
  const formatDate = options?.formatDate ?? defaultDateFormat;
  return isBrowser ? prettyLoggerBrowser({
    colors: showColors,
    formatDate
  }) : prettyLoggerTty({
    colors: showColors,
    formatDate
  });
};
const prettyLoggerTty = options => {
  const processIsBun = typeof process === "object" && "isBun" in process && process.isBun === true;
  const color = options.colors ? withColor : withColorNoop;
  return loggerMake(({
    cause,
    date,
    fiber,
    logLevel,
    message: message_
  }) => {
    const console = fiber.getRef(ConsoleRef);
    // oxlint-disable-next-line no-console
    const log = fiber.getRef(LogToStderr) ? console.error : console.log;
    const message = Array.isArray(message_) ? message_.slice() : [message_];
    let firstLine = color(`[${options.formatDate(date)}]`, colors.white) + ` ${color(logLevel.toUpperCase(), ...logLevelColors[logLevel])}` + ` (#${fiber.id})`;
    const now = date.getTime();
    const spans = fiber.getRef(CurrentLogSpans);
    for (const span of spans) {
      firstLine += " " + formatLogSpan(span, now);
    }
    firstLine += ":";
    let messageIndex = 0;
    if (message.length > 0) {
      const firstMaybeString = structuredMessage(message[0]);
      if (typeof firstMaybeString === "string") {
        firstLine += " " + color(firstMaybeString, colors.bold, colors.cyan);
        messageIndex++;
      }
    }
    log(firstLine);
    // oxlint-disable-next-line no-console
    if (!processIsBun) console.group();
    if (cause.reasons.length > 0) {
      log(causePretty(cause));
    }
    if (messageIndex < message.length) {
      for (; messageIndex < message.length; messageIndex++) {
        log(redact(message[messageIndex]));
      }
    }
    const annotations = fiber.getRef(CurrentLogAnnotations);
    for (const [key, value] of Object.entries(annotations)) {
      log(color(`${key}:`, colors.bold, colors.white), redact(value));
    }
    // oxlint-disable-next-line no-console
    if (!processIsBun) console.groupEnd();
  });
};
const prettyLoggerBrowser = options => {
  const color = options.colors ? "%c" : "";
  return loggerMake(({
    cause,
    date,
    fiber,
    logLevel,
    message: message_
  }) => {
    const console = fiber.getRef(ConsoleRef);
    const message = Array.isArray(message_) ? message_.slice() : [message_];
    let firstLine = `${color}[${options.formatDate(date)}]`;
    const firstParams = [];
    if (options.colors) {
      firstParams.push("color:gray");
    }
    firstLine += ` ${color}${logLevel.toUpperCase()}${color} (#${fiber.id})`;
    if (options.colors) {
      firstParams.push(logLevelStyle[logLevel], "");
    }
    const now = date.getTime();
    const spans = fiber.getRef(CurrentLogSpans);
    for (const span of spans) {
      firstLine += " " + formatLogSpan(span, now);
    }
    firstLine += ":";
    let messageIndex = 0;
    if (message.length > 0) {
      const firstMaybeString = structuredMessage(message[0]);
      if (typeof firstMaybeString === "string") {
        firstLine += ` ${color}${firstMaybeString}`;
        if (options.colors) {
          firstParams.push("color:deepskyblue");
        }
        messageIndex++;
      }
    }
    // oxlint-disable-next-line no-console
    console.groupCollapsed(firstLine, ...firstParams);
    if (cause.reasons.length > 0) {
      // oxlint-disable-next-line no-console
      console.error(causePretty(cause));
    }
    if (messageIndex < message.length) {
      for (; messageIndex < message.length; messageIndex++) {
        // oxlint-disable-next-line no-console
        console.log(redact(message[messageIndex]));
      }
    }
    const annotations = fiber.getRef(CurrentLogAnnotations);
    for (const [key, value] of Object.entries(annotations)) {
      const redacted = redact(value);
      if (options.colors) {
        // oxlint-disable-next-line no-console
        console.log(`%c${key}:`, "color:gray", redacted);
      } else {
        // oxlint-disable-next-line no-console
        console.log(`${key}:`, redacted);
      }
    }
    // oxlint-disable-next-line no-console
    console.groupEnd();
  });
};
/** @internal */
export const defaultLogger = /*#__PURE__*/loggerMake(({
  cause,
  date,
  fiber,
  logLevel,
  message
}) => {
  const message_ = Array.isArray(message) ? message.slice() : [message];
  if (cause.reasons.length > 0) {
    message_.push(causePretty(cause));
  }
  const now = date.getTime();
  const spans = fiber.getRef(CurrentLogSpans);
  let spanString = "";
  for (const span of spans) {
    spanString += ` ${formatLogSpan(span, now)}`;
  }
  const annotations = fiber.getRef(CurrentLogAnnotations);
  if (Object.keys(annotations).length > 0) {
    message_.push(annotations);
  }
  const console = fiber.getRef(ConsoleRef);
  // oxlint-disable-next-line no-console
  const log = fiber.getRef(LogToStderr) ? console.error : console.log;
  log(`[${defaultDateFormat(date)}] ${logLevel.toUpperCase()} (#${fiber.id})${spanString}:`, ...message_);
});
/** @internal */
export const tracerLogger = /*#__PURE__*/loggerMake(({
  cause,
  fiber,
  logLevel,
  message
}) => {
  const clock = fiber.getRef(ClockRef);
  const annotations = fiber.getRef(CurrentLogAnnotations);
  const span = fiber.currentSpan;
  if (span === undefined || span._tag === "ExternalSpan") return;
  const attributes = {};
  for (const [key, value] of Object.entries(annotations)) {
    attributes[key] = value;
  }
  attributes["effect.fiberId"] = fiber.id;
  attributes["effect.logLevel"] = logLevel.toUpperCase();
  if (cause.reasons.length > 0) {
    attributes["effect.cause"] = causePretty(cause);
  }
  span.event(toStringUnknown(Array.isArray(message) && message.length === 1 ? message[0] : message), clock.currentTimeNanosUnsafe(), attributes);
});
/** @internal */
export function interruptChildrenPatch() {
  fiberMiddleware.interruptChildren ??= fiberInterruptChildren;
}
/** @internal */
const undefined_ = /*#__PURE__*/succeed(undefined);
/** @internal */
export { undefined_ as undefined };
// ----------------------------------------------------------------------------
// ErrorReporter
// ----------------------------------------------------------------------------
/** @internal */
export const withErrorReporting = /*#__PURE__*/dual(args => isEffect(args[0]), (self, options) => onError(self, cause => withFiber(fiber => {
  reportCauseUnsafe(fiber, cause, options?.defectsOnly);
  return void_;
})));
/** @internal */
export const reportCauseUnsafe = (fiber, cause, defectsOnly) => {
  const reporters = fiber.getRef(CurrentErrorReporters);
  if (reporters.size === 0) return;
  if (defectsOnly && !hasDies(cause)) return;
  const opts = {
    cause,
    fiber,
    timestamp: fiber.getRef(ClockRef).currentTimeNanosUnsafe()
  };
  reporters.forEach(reporter => reporter.report(opts));
};
//# sourceMappingURL=effect.js.map