Skip to content

Replace the legacy stack-trace dependency without breaking CommonJS consumers #539

Description

@TheRealAgentK

Context

Raygun4Node currently depends on stack-trace 0.0.10 to synchronously convert JavaScript Error stacks into Raygun stack-frame payloads in lib/raygun.messageBuilder.ts. Dependabot PR #533 proposed updating it to 1.0.0.

That automated major update was intentionally rejected:

  • stack-trace 1.0.0 is ESM-only ("type": "module").
  • It requires Node.js >=20.0.0.
  • Raygun4Node is built and published as CommonJS and declares Node.js >=14.17.0.
  • Raygun4Node's normal test suite passed on the proposed update, but the dedicated packed/CommonJS-style compatibility path failed on Node 20, 22, and 24 because the compiled SDK attempted to require() the ESM-only package.
  • The AWS Lambda provider consumes Raygun4Node through CommonJS and would inherit the incompatibility.
  • The existing 0.0.10 version has no npm audit vulnerability, so retaining it is currently safer than accepting a known runtime regression.

PR #533 was closed with @dependabot ignore this major version. That is a temporary compatibility decision, not a recommendation to depend on 0.0.10 indefinitely. This issue tracks removing the long-term dependency risk deliberately.

Problem statement

The SDK needs a maintained stack-frame parsing strategy that:

  1. Works synchronously in the existing message-building path.
  2. Preserves the current Raygun payload shape and stack-frame fidelity.
  3. Does not break CommonJS consumers or the AWS Lambda provider.
  4. Supports the project's approved Node.js runtime floor.
  5. Avoids permanently pinning an old package solely because its successor changed module format and engine requirements.

This should be treated as runtime SDK work, not as a routine dependency update.

Investigation required

1. Establish the compatibility policy

Before selecting an implementation, confirm:

  • Whether Node.js >=14.17.0 remains the supported runtime floor.
  • Whether CommonJS remains the primary published format.
  • Whether dual CommonJS/ESM publishing is planned separately.
  • Whether a higher Node floor or packaging change would require a Raygun4Node major release.

Do not raise the Node floor or migrate the package to ESM implicitly to accommodate one dependency.

2. Evaluate implementation options

Evaluate at least these approaches with prototypes and trade-offs:

A. Replace stack-trace with another maintained parser

Assess candidate packages for:

  • CommonJS compatibility or reliable dual-package exports.
  • Node engine support matching Raygun4Node policy.
  • Synchronous parsing.
  • TypeScript declarations.
  • Maintenance activity, licensing, dependency footprint, and security history.
  • Correct handling of V8/Node stack formats and edge cases already represented by Raygun tests.

Avoid introducing a large dependency tree for this narrow runtime responsibility.

B. Implement a small internal parser or CallSite adapter

Assess whether the limited SDK use case can be owned directly using supported V8/Node mechanisms such as structured CallSite data, with a string-parser fallback where necessary.

The design must account for:

  • Interaction with Error.prepareStackTrace and restoration of global state.
  • Concurrent/nested error reporting.
  • Errors with a precomputed or custom stack value.
  • Stack traces produced outside V8 or supplied as strings.
  • Anonymous, native, eval, constructor, async, and internal frames.
  • Windows paths, URLs, paths containing parentheses/braces, and missing line/column data.
  • Source-map and transpilation expectations.

Do not copy or fork upstream implementation code without reviewing license and maintenance obligations.

C. Maintain a narrowly scoped CommonJS-compatible fork

Consider only if no maintained replacement or safe internal implementation exists. Document:

  • Ownership and release process.
  • Upstream attribution/license requirements.
  • Security monitoring.
  • Why a fork is preferable to a small internal implementation.
  • Exit strategy.

D. Adopt stack-trace 1.x as part of a future package-format migration

This is viable only if separately approved Node/runtime and ESM packaging work makes the dependency compatible. It must be coordinated with the TypeScript 7/runtime modernization tracked in #538 and with the AWS Lambda provider. Do not make the broader migration a hidden prerequisite of this ticket unless that strategy is explicitly chosen.

3. Define and test the behavioral contract

Inventory the exact stack-frame fields currently emitted by getStackTrace() and consumed by Raygun:

  • lineNumber
  • columnNumber
  • className
  • fileName
  • methodName

Build table-driven fixtures for representative stack inputs and expected payload frames. Include at least:

  • Standard Error and subclassed errors.
  • Nested errors and VError chains.
  • Anonymous and named functions/methods.
  • Constructors and class methods.
  • Async function frames.
  • Native and Node internal frames.
  • Eval frames.
  • Missing file, method, line, or column information.
  • Windows drive-letter and UNC paths.
  • Paths containing spaces, parentheses, and braces.
  • File URLs and package paths.
  • User-supplied/custom error.stack strings.
  • Very large or malformed stack strings.

Existing message-builder tests should remain, but the replacement needs focused parser-contract tests so a parser can be changed without relying only on end-to-end payload assertions.

Proposed implementation sequence

  1. Confirm runtime/module compatibility policy and release classification.
  2. Document the current parsing contract with fixtures before changing implementation.
  3. Prototype the smallest two viable options and compare correctness, package size, maintenance burden, and performance.
  4. Select an approach in the issue/PR rationale.
  5. Replace stack-trace and remove @types/stack-trace if no longer needed.
  6. Run the full supported Node matrix and packed CommonJS consumer tests.
  7. Validate the AWS Lambda provider against a packed Raygun4Node candidate.
  8. Document any observable stack-frame changes in the changelog and release notes.

Acceptance criteria

  • Supported Node.js floor and CommonJS/ESM strategy are explicitly confirmed.
  • The selected approach has a documented dependency, maintenance, licensing, and security rationale.
  • Focused stack-parser contract fixtures cover the edge cases listed above.
  • Existing message-builder, nested error, VError, Express, batch, offline, and exception-reporting tests pass.
  • Stack-frame payload fields remain compatible, or intentional differences are documented and approved.
  • Parsing remains synchronous and does not introduce global Error.prepareStackTrace leakage or concurrency hazards.
  • npm pack includes only the expected runtime files and does not introduce an unexpectedly large dependency tree.
  • A clean CommonJS consumer can require("raygun"), instantiate the client, and build/send an error on every supported Node version.
  • The AWS Lambda provider builds and passes async, callback, error-forwarding, and breadcrumb tests against the packed candidate.
  • Production npm audit remains clean.
  • Release semver and migration notes are agreed before merge.
  • Dependabot ignore configuration for stack-trace 1.x is removed only if the selected solution makes that appropriate.

Release guidance

  • A drop-in parser replacement with identical payloads, unchanged Node support, and unchanged CommonJS packaging can be released as a patch.
  • Observable stack-frame changes may require a minor release and explicit release notes.
  • Raising the Node floor, removing CommonJS support, or changing package entry points should be treated as a major release.

Related work

Non-goals

  • Changing the SDK module format solely to satisfy stack-trace 1.x.
  • Raising the Node support floor without an independent product decision.
  • Refactoring unrelated error-message construction or transport behavior.
  • Silencing the CommonJS compatibility test.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Needs Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions