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
10 changes: 7 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
version: 2
updates:
# `npm` is also the correct ecosystem for pnpm. This root run reads
# pnpm-workspace.yaml, so it covers the e2e/* members too, bumping a member
# package.json and the root pnpm-lock.yaml in one pull request. Do not add
# per-directory entries: a run inside a member treats the parent lockfile as a
# support file and drops it, leaving it stale and failing --frozen-lockfile
# (dependabot-core#11135).
- package-ecosystem: npm
directories:
- /
- '**/*'
directory: /
schedule:
interval: weekly
day: monday
Expand Down
27 changes: 9 additions & 18 deletions .github/workflows/dependabot-failure-watcher.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,16 @@ name: Dependabot Failure Watcher
#
# Outside the root, kinds 2 and 3 cannot be told apart by title, so the filter
# has to name directories instead. e2e/js and e2e/ts (in the Node repos this
# workflow is shared with) are consumer smoke tests carrying committed

@mm-jpoole mm-jpoole Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope of this PR, but this whole comment needs to be re-written by a human. Created follow-up SCO-9217

# lockfiles, so their transitive dev dependencies attract advisories that no
# pull request can fix, and nothing in them is shipped code.
# workflow is shared with) are consumer smoke tests, so their transitive dev
# dependencies attract advisories that no pull request can fix, and nothing in
# them is shipped code.
#
# Be clear about the cost, because it is not zero: both Node repos configure npm
# with directories: ["/", "**/*"], and that glob does match e2e/js and e2e/ts,
# so those directories DO get version updates. Dropping the pattern therefore
# discards their kind 2 failures as well as their kind 3 ones -- there is an
# open version-update pull request under e2e/ts in both repos as this is
# written. The npm ecosystem label does not rescue the distinction either:
# Dependabot writes "npm_and_yarn" for both kinds, so "npm_and_yarn in /e2e/ts
# for js-yaml" could be either a security job or the refresh of a
# version-update pull request.
#
# Accepted deliberately anyway. Kind 1 is what this watcher primarily exists to
# catch and is still reported for those directories, so what is given up is the
# narrower "one open pull request has gone stale" signal, for two directories of
# test scaffolding, in exchange for dropping 16 unactionable failures in each of
# the two Node repos over retained history.
# Since the pnpm conversion this clause cannot match kind 2: version updates are
# root-only, so their titles read "in /", never "in /e2e/js". It still discards
# kind 3, which names the directory holding the vulnerable manifest -- for a
# transitive e2e dev dependency, one of these paths. That is the intent, so it
# stays. Keep it in step with dependabot.yml: the ecosystem label cannot rescue
# the distinction, since Dependabot writes "npm_and_yarn" for both kinds.
#
# Reading the directories out of dependabot.yml instead looks more general but is
# worse: entries may use globs (directories: ["**/*"]), which never match a title
Expand Down
36 changes: 27 additions & 9 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,31 @@ jobs:
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
- name: Check that package-lock.json is valid JSON
run: jq empty package-lock.json
- name: Install npm packages
run: npm ci
- name: Run eslint
run: npm run lint
package-manager-cache: false
# Install only pnpm, not the repo's full toolchain — Node comes from
# actions/setup-node. See mise.toml [tools] comment for why.
- name: Setup mise
uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5
with:
install: false
add_shims_to_path: false
# mise-action saves a cache only inside its install branch, so with
# install: false nothing here ever writes one. The restore is gated
# separately and would still run, always missing, so turn it off.
cache: false
- name: Install pnpm
env:
MISE_AUTO_INSTALL: 'false'
run: |
mise install --locked github:pnpm/pnpm
pnpm_bin=$(mise which pnpm)
[ -x "$pnpm_bin" ] || { echo "mise which pnpm produced no usable path" >&2; exit 1; }
dirname "$pnpm_bin" >> "$GITHUB_PATH"
# Smoke check only; there is no matrix here to get wrong.
- run: node --version && pnpm --version
- name: Install packages
run: pnpm install --frozen-lockfile
- name: Run lint
run: pnpm run lint
- name: Run prettier
run: npm run prettier:ci
- name: Test compile
run: npx tsc --noEmit
run: pnpm run prettier:ci
71 changes: 61 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,30 @@ jobs:
with:
node-version: 22
package-manager-cache: false
- run: npm ci
- run: npm test
- run: npm run lint
- run: npm run build
- run: npm run build:docs
# Install only pnpm, not the repo's full toolchain — Node comes from
# actions/setup-node. See mise.toml [tools] comment for why.
- name: Setup mise
uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5
with:
install: false
add_shims_to_path: false
# zizmor's cache-poisoning audit flags a restorable cache in a job
# that publishes artifacts built at runtime, which is also why the
# setup-node steps here set package-manager-cache: false.
cache: false
- name: Install pnpm
env:
MISE_AUTO_INSTALL: 'false'
run: |
mise install --locked github:pnpm/pnpm
pnpm_bin=$(mise which pnpm)
[ -x "$pnpm_bin" ] || { echo "mise which pnpm produced no usable path" >&2; exit 1; }
dirname "$pnpm_bin" >> "$GITHUB_PATH"
- run: pnpm install --frozen-lockfile
- run: pnpm test
- run: pnpm run lint
- run: pnpm run build
- run: pnpm run build:docs

publish:
needs: build
Expand All @@ -42,14 +61,46 @@ jobs:
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
# npm Trusted Publishing needs npm >= 11.5.1 and Node >= 22.14.0.
# Node 24 bundles a new enough npm; Node 22 does not, which is why
# `npm install -g npm@latest` is gone (zizmor adhoc-packages). The
# bundled version moves each 24.x, so it is asserted before publish.
node-version: 24
package-manager-cache: false
# Writes the .npmrc that OIDC publishing needs.
registry-url: 'https://registry.npmjs.org'
- run: npm install -g npm@latest
- run: npm ci
- run: npm run build
# Install only pnpm, not the repo's full toolchain — Node comes from
# actions/setup-node. See mise.toml [tools] comment for why.
- name: Setup mise
uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5
with:
install: false
add_shims_to_path: false
# Same reason as the build job above.
cache: false
- name: Install pnpm
env:
MISE_AUTO_INSTALL: 'false'
run: |
mise install --locked github:pnpm/pnpm
pnpm_bin=$(mise which pnpm)
[ -x "$pnpm_bin" ] || { echo "mise which pnpm produced no usable path" >&2; exit 1; }
dirname "$pnpm_bin" >> "$GITHUB_PATH"
- run: pnpm install --frozen-lockfile
- run: pnpm run build
# Assert rather than trust the npm that setup-node's `node-version` pin
# bundled: a Node downgrade would otherwise only surface during a real
# release. Sits immediately before the publish so nothing can change PATH.
- name: Verify npm supports trusted publishing
run: |
npm_version=$(npm --version)
echo "npm $npm_version (need >= 11.5.1 for OIDC trusted publishing)"
printf '11.5.1\n%s\n' "$npm_version" | sort -V -C
# Publishing deliberately stays on the npm CLI; adopting pnpm's own OIDC
# support is a separate follow-up issue. npm publish is safe in a
# pnpm-installed tree: it packs only `files: ["dist"]`, reads no lockfile.
- run: npm publish --provenance
- run: npm run build:docs
- run: pnpm run build:docs
- name: Deploy docs to gh-pages
uses: peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 # v4.1.0
with:
Expand Down
58 changes: 44 additions & 14 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,50 @@ jobs:
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: ${{ matrix.version }}
- run: npm ci
- run: npm run test:coverage
- run: npm run build
- run: npm run build:docs
- run: npm link
- run: npm ci
working-directory: e2e/js
- run: npm link '@maxmind/minfraud-api-node'
working-directory: e2e/js
- run: npx vitest run
package-manager-cache: false
# Install only pnpm, not the repo's full toolchain — Node comes from
# actions/setup-node. See mise.toml [tools] comment for why.
- name: Setup mise
uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5
with:
install: false
add_shims_to_path: false
# mise-action saves a cache only inside its install branch, so with
# install: false nothing here ever writes one. The restore is gated
# separately and would still run, always missing, so turn it off.
cache: false
- name: Install pnpm
env:
MISE_AUTO_INSTALL: 'false'
run: |
mise install --locked github:pnpm/pnpm
pnpm_bin=$(mise which pnpm)
[ -x "$pnpm_bin" ] || { echo "mise which pnpm produced no usable path" >&2; exit 1; }
dirname "$pnpm_bin" >> "$GITHUB_PATH"
# Assert, don't just print: if mise shadowed the Node that setup-node
# selected, every matrix leg would test the same version and still pass.
- name: Verify the matrix Node is active
env:
EXPECTED_MAJOR: ${{ matrix.version }}
run: |
actual=$(node -p 'process.versions.node.split(".")[0]')
echo "node major: $actual (expected $EXPECTED_MAJOR), pnpm $(pnpm --version)"
test "$actual" = "$EXPECTED_MAJOR"
# One root install links the workspace, so e2e/js and e2e/ts resolve the
# library through a symlink to the repo root. `build` must run before
# them so dist/ exists.
- run: pnpm install --frozen-lockfile
- run: pnpm run test:coverage
- run: pnpm run build
- run: pnpm run build:docs
- run: pnpm exec vitest run
working-directory: e2e/js
- run: npm ci
working-directory: e2e/ts
- run: npm link '@maxmind/minfraud-api-node'
- run: pnpm exec vitest run
working-directory: e2e/ts
- run: npx vitest run
# Nothing else type-checks the TypeScript consumer: vitest transpiles
# without checking, and both root tsconfigs use include: ["src"]. That
# matters because a non-hoisting package manager breaks exactly this --
# type resolution in the published surface. Must run after `build`, or
# the workspace symlink to dist/src/index.d.ts gives TS2307.
- run: pnpm exec tsc --noEmit
working-directory: e2e/ts
12 changes: 8 additions & 4 deletions .precious.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
[commands.prettier-scripts]
type = "both"
cmd = [
"npx",
"pnpm",
"exec",
"prettier",
"--parser",
"typescript"
Expand All @@ -15,7 +16,8 @@ ok-exit-codes = 0
[commands.prettier-json]
type = "both"
cmd = [
"npx",
"pnpm",
"exec",
"prettier",
"--parser",
"json"
Expand All @@ -29,7 +31,8 @@ ok-exit-codes = 0
[commands.eslint-scripts]
type = "both"
cmd = [
"npx",
"pnpm",
"exec",
"eslint",
"--config",
"eslint.config.mjs",
Expand All @@ -43,7 +46,8 @@ ok-exit-codes = 0
[commands.tsc-scripts]
type = "lint"
cmd = [
"npx",
"pnpm",
"exec",
"tsc",
"--noEmit"
]
Expand Down
1 change: 0 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
**/package.json
**/package-lock.json
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
CHANGELOG
=========

9.1.1
------------------

* Added `maxmind` as a direct dependency. The `IpAddressWebRecord` type extends
`CityResponse` from that package, so it is part of this package's published
type surface. It was previously resolved only as a transitive dependency of
`@maxmind/geoip2-node`, which broke type checking for users of package
managers that do not flatten `node_modules`, such as pnpm.

9.1.0 (2026-07-21)
------------------

Expand Down
40 changes: 25 additions & 15 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,37 +145,36 @@ insights.risk = response.ip_address.risk;

```bash
# Install dependencies
npm install
pnpm install

# Run all tests
npm test
pnpm test

# Run tests in watch mode
npm run test:watch
pnpm run test:watch

# Run tests with coverage (100% thresholds enforced)
npm run test:coverage
pnpm run test:coverage

# Run specific test file
npx vitest run src/webServiceClient.spec.ts
pnpm exec vitest run src/webServiceClient.spec.ts
```

### Linting and Building

```bash
# Lint code (ESLint + TypeScript)
npm run lint
pnpm run lint

# Format code (Prettier)
npm run prettier:ts
npm run prettier:json
pnpm run prettier:ts
pnpm run prettier:json

# Build TypeScript
npm run build
pnpm run build

# Build and deploy documentation
npm run build:docs
npm run deploy:docs
# Build documentation
pnpm run build:docs
```

### Test Structure
Expand Down Expand Up @@ -373,8 +372,13 @@ insights.risk = response.ip_address.risk;
## Development Workflow

### Setup

pnpm is pinned in `mise.toml`. On a fresh checkout, install the toolchain
first:

```bash
npm install
mise install --quiet --locked
pnpm install
Comment thread
coderabbitai[bot] marked this conversation as resolved.
```

### Before Committing
Expand All @@ -386,16 +390,22 @@ precious tidy -g
precious lint -g

# Run tests
npm test
pnpm test

# Build
npm run build
pnpm run build
```

Note: Precious is already set up and handles code formatting and linting. Use `precious tidy -g` to automatically fix issues, and `precious lint -g` to check for remaining problems.

### Version Requirements
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- **Node.js 22+** required (targets active LTS: 22, 24)
- **pnpm 11+** required. It is pinned in `mise.toml`, so `mise install`
provides it. Use pnpm for all local dependency management; do not use npm or
corepack. The release workflow is the one exception: it publishes with
`npm publish --provenance`. pnpm 11 supports OIDC natively, so that is a
deliberate hold on a release path CI never runs, not a limitation.
- Uses Node.js built-in `fetch` (no external HTTP libraries)
- TypeScript 6.x

Expand Down
Loading