Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 80 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ permissions:
pull-requests: read

env:
SOCKET_SECURITY_MODE: monitor # Options: monitor (non-blocking) or block (fails on vulnerabilities)
SOCKET_SECURITY_MODE: monitor # Options: monitor (non-blocking) or block (fails on vulnerabilities)

jobs:
# Detect which file groups changed so downstream jobs can skip when irrelevant.
Expand All @@ -36,6 +36,7 @@ jobs:
with:
filters: |
source:
- '.github/workflows/ci.yml'
- 'modules/**'
- 'package.json'
- 'yarn.lock'
Expand All @@ -62,30 +63,37 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [22.x, 24.x]
node-version: [22.x, 24.x, 26.x]
experimental: [false]
include:
# Node's Current release line — not yet an LTS. Failures here are
# surfaced via PR comment but do not block merge (see all-checks).
- node-version: 26.x
- node-version: 27-nightly
experimental: true

steps:
- uses: socketdev/action@937f824ec476dfd164d4a4d9995751427b0be143 # v1.3.0
- id: socket-firewall
continue-on-error: ${{ matrix.experimental }}
uses: socketdev/action@937f824ec476dfd164d4a4d9995751427b0be143 # v1.3.0
with:
mode: firewall-free

- uses: actions/checkout@v6
- id: checkout
continue-on-error: ${{ matrix.experimental }}
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0

- name: Setup node:${{ matrix.node-version }}
id: setup-node
continue-on-error: ${{ matrix.experimental }}
timeout-minutes: 15
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}

- name: Build Info
id: build-info
continue-on-error: ${{ matrix.experimental }}
run: |
echo "node $(node --version)"
echo "npm $(npm --version)"
Expand All @@ -95,26 +103,48 @@ jobs:
echo "head ref $GITHUB_HEAD_REF"

- name: Fetch Base Ref
id: fetch-base-ref
continue-on-error: ${{ matrix.experimental }}
run: |
git fetch origin ${GITHUB_BASE_REF:-master}

- name: restore lerna dependencies
id: lerna-cache
uses: actions/cache@v5
continue-on-error: ${{ matrix.experimental }}
uses: actions/cache/restore@v5
with:
path: |
node_modules
modules/*/node_modules
key: ${{ runner.os }}-node${{matrix.node-version}}-${{ hashFiles('yarn.lock') }}-${{ hashFiles('tsconfig.packages.json') }}-${{ hashFiles('**/package.json') }}

- name: Install Packages
id: install-packages
if: steps.lerna-cache.outputs.cache-hit != 'true' || contains( github.event.pull_request.labels.*.name, 'SKIP_CACHE')
continue-on-error: ${{ matrix.experimental }}
timeout-minutes: 60
run: sfw yarn install --with-frozen-lockfile --ignore-scripts
Comment thread
zahin-mohammad marked this conversation as resolved.

- name: save lerna dependencies
id: save-lerna-cache
if: steps.lerna-cache.outputs.cache-hit != 'true' && steps.install-packages.outcome == 'success'
continue-on-error: ${{ matrix.experimental }}
uses: actions/cache/save@v5
with:
path: |
node_modules
modules/*/node_modules
key: ${{ steps.lerna-cache.outputs.cache-primary-key }}

- name: Check In-Repo Package Versions
id: check-versions
continue-on-error: ${{ matrix.experimental }}
run: yarn run check-versions

- name: build packages
id: build-packages
continue-on-error: ${{ matrix.experimental }}
timeout-minutes: 60
env:
# Workaround for https://github.com/nodejs/node/issues/51555
DISABLE_V8_COMPILE_CACHE: '1'
Expand All @@ -123,26 +153,44 @@ jobs:
- name: Unit Test
id: unit-test
continue-on-error: ${{ matrix.experimental }}
timeout-minutes: 60
Comment thread
zahin-mohammad marked this conversation as resolved.
run: yarn run unit-test-changed
env:
BITGOJS_TEST_PASSWORD: ${{ secrets.BITGOJS_TEST_PASSWORD }}

- name: Comment on Node Current failure
if: matrix.experimental && steps.unit-test.outcome == 'failure' && github.event_name == 'pull_request'
- name: Comment on experimental Node.js failure
if: >-
always() &&
matrix.experimental &&
github.event_name == 'pull_request' &&
(
steps.socket-firewall.outcome == 'failure' ||
steps.checkout.outcome == 'failure' ||
steps.setup-node.outcome == 'failure' ||
steps.build-info.outcome == 'failure' ||
steps.fetch-base-ref.outcome == 'failure' ||
steps.lerna-cache.outcome == 'failure' ||
steps.install-packages.outcome == 'failure' ||
steps.save-lerna-cache.outcome == 'failure' ||
steps.check-versions.outcome == 'failure' ||
steps.build-packages.outcome == 'failure' ||
steps.unit-test.outcome == 'failure'
)
continue-on-error: true
uses: actions/github-script@v7
Comment thread
zahin-mohammad marked this conversation as resolved.
with:
script: |
const marker = '<!-- node-current-ci-failure -->';
const body = `${marker}\n⚠️ Unit tests are failing on Node ${{ matrix.node-version }} (Current release line, non-blocking). ` +
`This is not an LTS version yet, so it does not block merge, but it signals an incompatibility to fix before Node ${{ matrix.node-version }} becomes LTS.\n\n` +
const body = `${marker}\n⚠️ Compatibility checks are failing on Node.js ${{ matrix.node-version }} (experimental, non-blocking). ` +
`This does not block merge, but it signals an incompatibility to fix before this release becomes supported.\n\n` +
`[View run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`;

const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
});
const existing = comments.find((c) => c.body.includes(marker));
const existing = comments.find((comment) => comment.body.includes(marker));

if (existing) {
await github.rest.issues.updateComment({
Expand All @@ -160,8 +208,23 @@ jobs:
});
}

- name: Resolve Node Current failure comment
if: matrix.experimental && steps.unit-test.outcome == 'success' && github.event_name == 'pull_request'
- name: Resolve experimental Node.js failure comment
if: >-
always() &&
matrix.experimental &&
github.event_name == 'pull_request' &&
steps.socket-firewall.outcome != 'failure' &&
steps.checkout.outcome != 'failure' &&
steps.setup-node.outcome != 'failure' &&
steps.build-info.outcome != 'failure' &&
steps.fetch-base-ref.outcome != 'failure' &&
steps.lerna-cache.outcome != 'failure' &&
steps.install-packages.outcome != 'failure' &&
steps.save-lerna-cache.outcome != 'failure' &&
steps.check-versions.outcome != 'failure' &&
steps.build-packages.outcome != 'failure' &&
steps.unit-test.outcome == 'success'
continue-on-error: true
uses: actions/github-script@v7
with:
script: |
Expand All @@ -171,13 +234,13 @@ jobs:
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
});
const existing = comments.find((c) => c.body.includes(marker));
const existing = comments.find((comment) => comment.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body: `${marker}\n✅ Unit tests now pass on Node ${{ matrix.node-version }} (Current release line).`,
body: `${marker}\n✅ Unit tests now pass on Node.js ${{ matrix.node-version }} (experimental).`,
});
}

Expand Down
14 changes: 13 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Build and Development Commands

### Installation

```bash
yarn install
```

### Development

```bash
# Watch mode for development (compiles all TypeScript packages and watches for changes)
yarn dev
Expand All @@ -19,6 +21,7 @@ yarn
```

### Linting

```bash
# Lint all packages
yarn lint
Expand All @@ -34,6 +37,7 @@ yarn check-commits
```

### Testing

```bash
# Run all unit tests
yarn unit-test
Expand All @@ -55,6 +59,7 @@ yarn coverage
```

### Browser Compatibility

```bash
# Run browser tests
yarn browser-tests
Expand All @@ -73,32 +78,38 @@ For modules that need browser support (especially those using `@bitgo/wasm-utxo`
## Code Style

### Commits

BitGoJS uses conventional commits. All commits MUST pass the spec described in `commitlint.config.js`.

Every commit needs a footer issue reference (`references-empty: never`). Web Experience side work without a Linear ticket may use `WEB-000` in the footer (junk-drawer reference, same pattern as `BTC-000` / `CSHLD-000`). Branches named `WEB-000-*` get `TICKET: WEB-000` appended automatically by `scripts/prepare-commit-msg.js`.

### TypeScript Guidelines

- **Avoid `any` type**: Use specific types, interfaces, or union types instead of `any`. If absolutely necessary, prefer `unknown` and use type guards for safety.

## Code Architecture

BitGoJS is a monorepo composed of multiple modules, each implementing specific functionality:

### Core Modules

- `bitgo`: Main module providing authentication, wallet management, cryptographic primitives, and coin interfaces
- `@bitgo/sdk-core`: Core SDK functionality, base classes, and interfaces
- `@bitgo/sdk-api`: API client utilities
- `@bitgo/statics`: Static configuration values used across the platform

### Coin Implementation Modules

- `@bitgo/sdk-coin-*`: Individual cryptocurrency implementations (e.g., btc, eth, sol, etc.)
- `@bitgo/abstract-eth`, `@bitgo/abstract-utxo`, etc.: Abstract base classes for similar coin families

### Transaction Building and Signing

- `@bitgo/account-lib`: Build and sign transactions for account-based coins
- `@bitgo/utxo-lib`: Build and sign transactions for UTXO-based coins

### Other Utility Modules

- `@bitgo/blockapis`: Access public block explorer APIs for various coins
- `@bitgo/express`: Local BitGo transaction signing server and proxy
- `@bitgo/unspents`: Utilities for UTXO chains
Expand All @@ -122,6 +133,7 @@ The BitGoJS SDK follows a modular architecture:
## Adding New Coins

To implement a new coin:

```bash
yarn sdk-coin:new
```
Expand All @@ -130,4 +142,4 @@ This will generate the necessary boilerplate for a new coin implementation.

## Node.js Version Support

BitGoJS supports Node.js versions >=22, with NPM >=3.10.10.
BitGoJS supports Node.js versions 22 and later, including Node.js 26, with NPM >=3.10.10.
4 changes: 2 additions & 2 deletions DEVELOPERS.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Requirements

- yarn version 1 (classic)
- node version >=22 and <25
- Node.js version 22 or later

# Installing

Expand Down Expand Up @@ -180,7 +180,7 @@ Engines should be set to the following:
```json
{
"engines": {
"node": ">=22 <25",
"node": ">=22",
"npm": ">=3.10.10"
}
}
Expand Down
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,27 @@ Other tags may be released to npm (e.g. `hotfix`, `dev`, etc...), but are not co

Examples can be found in each of the modules specific to the module use cases. Starter examples can be found [here](https://github.com/BitGo/BitGoJS/tree/master/examples).

# NodeJS Version Support Policy
# Node.js Version Support Policy

BitGoJS currently provides support for the following Node versions per package.json engines policy:

```
"engines": {
"node": ">=22 <25",
"node": ">=22",
"npm": ">=3.10.10"
}
```

We specifically limit our support to these versions of Node, not because this package won't work on other versions, but because these versions tend to be the most widely used in practice. It's possible the packages in this repository will work correctly on newer or older versions of Node, but we typically don't run automated tests against non-specified versions of Node (including odd versions), with the possible exception of the latest odd numbered version for advanced awareness of upcoming breaks in version support.
We specifically limit our support to these versions of Node, not because this package won't work on other versions, but because these versions tend to be the most widely used in practice. The packages may work correctly on newer or older versions, but only the supported versions below are required to pass continuous integration. We also run one newer Node.js release as a non-blocking early-warning check so incompatibilities are visible before that release becomes supported.

As each Node LTS version reaches its end-of-life we will exclude that version from the node engines property of our package's package.json file. Removing a Node version is considered a breaking change and will entail the publishing of a new major version of this package. We will not accept any requests to support an end-of-life version of Node, and any pull requests or issues regarding support for an end-of-life version of Node will be closed. We will accept code that allows this package to run on newer, non-LTS, versions of Node. Furthermore, we will attempt to ensure our own changes work on the latest version of Node. To help in that commitment, our continuous integration setup runs the full test suite on the latest release of the following versions of node:

- `22` (Maintenance LTS) — required to pass
- `24` (Active LTS) — required to pass
- `26` (Current) — run non-blocking; a failure posts a warning comment on the PR instead of blocking merge
- `24` (Maintenance LTS) — required to pass
- `26` (Current) — required to pass
- `27` nightly (experimental) — non-blocking; a failure posts a warning comment on the pull request

When a new Node major becomes Active LTS, update the `node-version` matrix in `.github/workflows/ci.yml` (moving the outgoing Current version into the required set and adding the new Current release), and bump the `engines.node` range across all `modules/*/package.json` files accordingly.
When a new Node.js major becomes supported, add it to the required `node-version` matrix in `.github/workflows/ci.yml` and update the `engines.node` range across all `modules/*/package.json` files if the range does not already include it. Keep exactly one newer release as the non-blocking early-warning check: when Node.js 28 development builds become available, replace the Node.js 27 nightly entry rather than adding another experimental matrix entry. Node.js 26 is required before its Long Term Support (LTS) transition, so its CI check is intentionally blocking already.

JavaScript package managers should allow you to install this package with any version of Node, with, at most, a warning if your version of Node does not fall within the range specified by our node engines property. If you encounter issues installing this package on a supported version of Node, please report the issue to us.

Expand Down
2 changes: 1 addition & 1 deletion modules/bitgo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ If you have questions or comments about this API, email support@bitgo.com.

# Installation

Ensure you're running Node version 20 or higher (preferably the latest LTS release) and NPM version 10.
Ensure you're running Node.js version 22 or later, including Node.js 26, and NPM version 10.
For setting your Node version, we recommend using `nvm` - the [Node Version Manager](https://github.com/creationix/nvm/blob/master/README.markdown#installation).

`npm install --save bitgo`
Expand Down
4 changes: 3 additions & 1 deletion modules/express/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,15 @@ $ yarn build-docker-express
$ docker run -it bitgo-express:latest
```

The BitGo Express Docker image tracks the older of the two most recent Node.js Long-Term Support (LTS) releases. It currently builds and runs on Node.js 24.

## From source

For users who are unable to run BitGo Express as a Docker container, we recommend building and running from the source code.

### Prerequisites

Ensure you're running at least Node version 16. We recommend using `nvm`, the [Node Version Manager](https://github.com/creationix/nvm/blob/master/README.markdown#installation), for setting your Node version. BitGo Express has become a first class citizen of the monorepo so we recommend using `yarn` for local setup.
Use Node.js 22 or later. The required continuous integration checks cover Node.js 22, 24, and 26. We recommend using `nvm`, the [Node Version Manager](https://github.com/creationix/nvm/blob/master/README.markdown#installation), for setting your Node.js version. BitGo Express is part of the monorepo, so use `yarn` for local setup.

### Cloning the repository and installing dependencies

Expand Down
8 changes: 5 additions & 3 deletions modules/express/src/clientRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,9 +453,11 @@ async function decryptPrivKey(bg: BitGo, encryptedPrivKey: string, walletPw: str
export async function handleV2GenerateShareTSS(
req: ExpressApiRouteRequest<'express.v2.tssshare.generate', 'post'>
): Promise<any> {
const walletId = req.body.txRequest ? req.body.txRequest.walletId : req.body.tssParams.txRequest.walletId;
if (!walletId) {
throw new Error('Missing required field: walletId');
const txRequest = req.body.txRequest ?? req.body.tssParams?.txRequest;
const walletId =
txRequest && typeof txRequest === 'object' && !Array.isArray(txRequest) ? txRequest.walletId : undefined;
if (typeof walletId !== 'string' || !walletId) {
throw new ApiResponseError('Missing required field: walletId', 400);
}

const walletPw = getWalletPwFromEnv(walletId);
Expand Down
Loading
Loading