Skip to content
This repository was archived by the owner on May 30, 2026. It is now read-only.
This repository was archived by the owner on May 30, 2026. It is now read-only.

Bundled CJS deps that __importDefault(require('node:*')) crash at runtime with broken instanceof #79

Closed

Description

Summary

When a bundled action depends (transitively) on a CommonJS package that uses the TypeScript-emitted __importDefault(require("node:<builtin>")) interop helper, the bundler can leave the resulting .default binding undefined in the emitted chunk. Any instanceof <ns>.default check downstream then throws at runtime:

TypeError: Right-hand side of 'instanceof' is not callable

Where it surfaced

Building workflow-release-action (which signs Sigstore attestations) hit this through three layers of CJS deps:

  • minipass@7.1.3 — dist/commonjs/index.js: s instanceof node_stream_1.default where node_stream_1 = __importDefault(require("node:stream")). This is the actual crash.
  • make-fetch-happen@15.0.5 — lib/remote.js: err.retried instanceof fetch.Response (same class of bug, fetch is a CJS function with .Response attached).
  • @sigstore/sign@4.1.1 — dist/error.js: err instanceof error_1.HTTPError (same pattern).

The crash is especially nasty because it happens inside error-handling paths — it masks the real upstream error (in our case a Fulcio HTTP response) behind a generic TypeError, so it took several iterations to trace.

Root cause

@savvy-web/github-action-builder builds the action as ESM (runs: { using: "node24" }). rspack rewrites CJS require("node:stream") into something like import * as ns from "node:stream" and the synthesized namespace object's .default is not what __importDefault expects for Node built-ins — it comes through undefined. Normal Node CJS execution (where these packages are downloaded ~500M/week and work fine) never hits this because require("node:stream") returns the Stream constructor directly.

Workaround we used

pnpm patch on all three packages, duck-typing the instanceof checks (e.g. typeof x === "function" && val instanceof x, or shape checks on statusCode/status). Works but is per-consumer and brittle — every action that bundles a sigstore/npm-cli-adjacent dep will rediscover this.

Suggested fix

Harden the builder's rspack config so __importDefault of Node built-ins resolves .default correctly. Options worth investigating:

  • A module.rules / NormalModuleReplacementPlugin shim that normalizes node:* external interop.
  • Marking node:* externals with a commonjs-style external type so require() semantics are preserved instead of ESM-namespace semantics.
  • Or document a recommended externals posture for actions that bundle CJS deps.

Reporter notes a similar issue was hit with another builder, so a general interop fix here would likely cover multiple cases.

Environment

  • @savvy-web/github-action-builder@0.6.3
  • Node 24 runner, action built as ESM single-bundle

Activity

  1. savvy-web-bot commented on May 15, 2026

    @savvy-web-bot
    Contributor

    Closed by release PR #72 merge.

    🤖 Automated by workflow-release-action

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions