Skip to content
Draft
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
27 changes: 22 additions & 5 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ jobs:
node-version: ${{ matrix.node-version }}
- name: Run tests with Node.js ${{ matrix.node-version }}
run: npm run test-node
test-karma:
test-browser:
runs-on: ubuntu-latest
timeout-minutes: 10
# three browser engines plus a cold browser install
timeout-minutes: 20
strategy:
matrix:
node-version: [24.x]
Expand All @@ -58,11 +59,19 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- name: Run karma tests
run: npm run test-karma
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package.json') }}
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium firefox webkit
- name: Run browser tests
run: npm run test-browser
coverage:
runs-on: ubuntu-latest
timeout-minutes: 10
# the browser project runs here too, across three engines
timeout-minutes: 20
strategy:
matrix:
node-version: [24.x]
Expand All @@ -75,6 +84,14 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- run: npm install
# coverage runs the browser project too, so the browsers are required
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package.json') }}
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium firefox webkit
- name: Generate coverage report
run: npm run coverage-ci
- name: Upload coverage to Codecov
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
*.sw[nop]
*~
.cache
.vitest-attachments
.nyc_output
.project
.settings
.vscode
TAGS
coverage
dist
__screenshots__
node_modules
reports
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,33 @@
- Test on Node.js >=22.
- Update `engines.node` to `>=22`.
- Update README requirements section.
- **BREAKING**: Add an `exports` field.
- Only `.`, `./agentCompatibility.js`, and `./package.json` are importable;
other deep imports into the package are no longer reachable.
- Switch testing from `mocha`/`chai`/`karma`/`c8` to `vitest`.
- `karma` is unmaintained; `vitest` covers Node.js tests, browser tests, and
coverage with a single tool and config.
- Browser tests now run via `playwright` instead of `karma`, in Chromium,
Firefox, and WebKit rather than Chromium alone.
- `npm test` now runs both the Node.js and browser suites; use
`npm run test-node` or `npm run test-browser` for one of them.
- `npm run test-karma` is replaced by `npm run test-browser`.
- `npm run coverage-report` is removed; use
`npm run coverage -- --coverage.reporter=html`.
- Coverage now includes the browser suite, and reported totals shift
slightly because `istanbul` and `c8` count executable lines differently.
The `istanbul` provider is used rather than `v8` because v8 coverage is
gathered over CDP, which only Chromium supports.

### Fixed
- Detect a possible CORS error in Firefox and WebKit, not just Chromium. The
`Failed to fetch "<url>". Possible CORS error.` message was produced by
matching Chromium's network-error text, so other engines fell through to a
generic error. Firefox and WebKit wording is now recognized as well.
- Resolve `agentCompatibility` through an `exports` `browser` condition rather
than only the top-level `browser` field. Bundlers that do not apply the
`browser` field to package-internal relative imports (such as Vite) no longer
pull `undici` into browser builds.

### Removed
- **BREAKING**: Remove CJS support.
Expand Down
109 changes: 0 additions & 109 deletions karma.conf.cjs

This file was deleted.

27 changes: 22 additions & 5 deletions lib/httpClient.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*!
* Copyright (c) 2020-2026 Digital Bazaar, Inc.
*/
import {convertAgent} from './agentCompatibility.js';
import {convertAgent} from '@digitalbazaar/http-client/agentCompatibility.js';
import ky from 'ky';

export {ky};
Expand All @@ -15,6 +15,23 @@ const PROXY_METHODS = new Set([
'get', 'post', 'put', 'patch', 'head', 'delete', 'query', 'options', 'trace'
]);

/*
Browsers reject a blocked or failed `fetch` with a `TypeError` whose message
is engine-specific. A cross-origin block is deliberately indistinguishable
from any other network failure -- the response is opaque -- which is why the
message below says "Possible". Node.js rejects with `fetch failed`, which is
intentionally absent here: there is no CORS in Node.js, so the hint would be
misleading. Each entry is exercised by the browser test matrix.
*/
const BROWSER_NETWORK_ERRORS = new Set([
// Chromium
'Failed to fetch',
// Firefox
'NetworkError when attempting to fetch resource.',
// WebKit
'Load failed'
]);

/**
* Returns a custom httpClient instance. Used to specify default headers and
* other default overrides.
Expand Down Expand Up @@ -125,10 +142,10 @@ async function _handleError({error, url}) {

// handle network errors and system errors that do not have a response
if(!error.response) {
if(error.message === 'Failed to fetch' ||
error.cause?.message === 'Failed to fetch') {
// ky@2 wraps the browser's underlying `TypeError: Failed to fetch`
// in its own `NetworkError`, with the original error as `cause`
if(BROWSER_NETWORK_ERRORS.has(error.message) ||
BROWSER_NETWORK_ERRORS.has(error.cause?.message)) {
// ky@2 wraps the browser's underlying `TypeError` in its own
// `NetworkError`, with the original error as `cause`
error.message = `Failed to fetch "${url}". Possible CORS error.`;
}
// ky's TimeoutError class
Expand Down
49 changes: 20 additions & 29 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,28 @@
"license": "BSD-3-Clause",
"type": "module",
"main": "./lib/index.js",
"exports": {
".": "./lib/index.js",
"./agentCompatibility.js": {
"react-native": "./lib/agentCompatibility-browser.js",
"browser": "./lib/agentCompatibility-browser.js",
"default": "./lib/agentCompatibility.js"
},
"./package.json": "./package.json"
},
"browser": {
"./lib/agentCompatibility.js": "./lib/agentCompatibility-browser.js",
"./tests/utils.js": "./tests/utils-browser.js"
"./lib/agentCompatibility.js": "./lib/agentCompatibility-browser.js"
},
"react-native": {
"./lib/agentCompatibility.js": "./lib/agentCompatibility-browser.js"
},
"scripts": {
"test": "npm run test-node",
"test-node": "cross-env NODE_ENV=test mocha --preserve-symlinks -t 30000 -A -R ${REPORTER:-spec} --require tests/test-mocha.js tests/*.spec.js",
"test-karma": "karma start karma.conf.cjs",
"test-watch": "cross-env NODE_ENV=test mocha --watch --parallel --preserve-symlinks -t 30000 -A -R ${REPORTER:-spec} --require tests/test-mocha.js tests/*.spec.js",
"coverage": "cross-env NODE_ENV=test c8 npm run test-node",
"coverage-ci": "cross-env NODE_ENV=test c8 --reporter=lcovonly --reporter=text-summary --reporter=text npm run test-node",
"coverage-report": "c8 report",
"test": "vitest run",
"test-node": "vitest run --project node",
"test-browser": "vitest run --project browser",
"test-watch": "vitest",
"coverage": "vitest run --coverage",
"coverage-ci": "vitest run --coverage --coverage.reporter=lcovonly --coverage.reporter=text-summary --coverage.reporter=text",
"lint": "eslint"
},
"files": [
Expand All @@ -31,22 +38,13 @@
},
"devDependencies": {
"@digitalbazaar/eslint-config": "^9.0.0",
"c8": "^12.0.0",
"chai": "^4.5.0",
"@vitest/browser-playwright": "^4.1.10",
"@vitest/coverage-istanbul": "^4.1.10",
"cors": "^2.8.6",
"cross-env": "^10.1.0",
"detect-node": "^2.1.0",
"eslint": "^10.8.1",
"express": "^5.2.1",
"karma": "^6.4.4",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^3.2.0",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-sourcemap-loader": "^0.4.0",
"karma-webpack": "^5.0.1",
"mocha": "^11.8.0",
"webpack": "^5.109.2"
"playwright": "^1.62.1",
"vitest": "^4.1.10"
},
"repository": {
"type": "git",
Expand All @@ -68,12 +66,5 @@
"homepage": "https://github.com/digitalbazaar/http-client",
"engines": {
"node": ">=22"
},
"c8": {
"reporter": [
"lcov",
"text-summary",
"text"
]
}
}
Loading
Loading