1/**
2 * Utility for safely manipulating `Error.stackTraceLimit` in environments
3 * where intrinsics may be frozen (e.g., SES / hardened JavaScript or
4 * deterministic sandboxes such as Temporal). When the property is non-writable,
5 * mutating it throws, so all manipulation here degrades to a best-effort,
6 * silent no-op.
7 *
8 * Mirrors the guard Node uses internally:
9 * https://github.com/nodejs/node/blob/e77694631f1642c302f664703197b5aabc65b482/lib/internal/errors.js#L246
10 *
11 * The error is constructed inline at each call site (rather than inside a
12 * closure here) so the captured stack trace keeps pointing at the real caller
13 * instead of this module.
14 *
15 * @internal
16 */
17import type { ErrorWithStackTraceLimit } from "./tracer.ts"
18
19/**
20 * Check if `Error.stackTraceLimit` is writable.
21 * Returns `false` if the property is frozen, non-writable, or `Error` is non-extensible.
22 *
23 * @internal
24 */
25export const isStackTraceLimitWritable = (): boolean => {
26 const desc = Object.getOwnPropertyDescriptor(Error, "stackTraceLimit")
27 if (desc === undefined) {
28 return Object.isExtensible(Error)
29 }
30
31 return Object.hasOwn(desc, "writable")
32 ? desc.writable === true
33 : desc.set !== undefined
34}
35
36// Cache the check result since it won't change during runtime
37const canWriteStackTraceLimit = isStackTraceLimitWritable()
38
39/**
40 * Get the current `Error.stackTraceLimit` value.
41 * Returns `undefined` if the property doesn't exist.
42 *
43 * @internal
44 */
45export const getStackTraceLimit = (): number | undefined => (Error as ErrorWithStackTraceLimit).stackTraceLimit
46
47/**
48 * Safely set `Error.stackTraceLimit` if possible, otherwise no-op.
49 *
50 * Accepts `undefined` so a value read via {@link getStackTraceLimit} can be
51 * restored faithfully.
52 *
53 * @internal
54 */
55export const setStackTraceLimit = (value: number | undefined): void => {
56 if (canWriteStackTraceLimit) {
57 ;(Error as ErrorWithStackTraceLimit).stackTraceLimit = value
58 }
59}