Skip to content

Commit f56d854

Browse files
kadamwhiteclaude
andcommitted
Merge: remove parse-link-header, raise Node floor to 24
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 parents 7302cd1 + 11ad08b commit f56d854

9 files changed

Lines changed: 54 additions & 63 deletions

File tree

.github/workflows/ci.yml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,12 @@ on:
66
pull_request:
77

88
jobs:
9-
# tsdown/rolldown require Node >=22.18 to run; vitest requires >=20. The
10-
# published library itself only requires Node >=18 (see `engines` in
11-
# package.json) — that promise is checked separately by `dist-smoke` below,
12-
# against the pre-built output, without needing the build tooling to run.
139
test:
1410
name: Lint, typecheck, build & unit test (Node ${{ matrix.node-version }})
1511
runs-on: ubuntu-latest
1612
strategy:
1713
matrix:
18-
node-version: [ 22, 24, latest ]
14+
node-version: [ 24, latest ]
1915
steps:
2016
- uses: actions/checkout@v4
2117
- uses: actions/setup-node@v4
@@ -34,13 +30,16 @@ jobs:
3430
path: dist
3531
retention-days: 1
3632

33+
# Smokes the built artifact under a production-only install (no devDependencies),
34+
# which the test job above cannot catch: it verifies dist/ is self-contained and
35+
# requires nothing outside the declared runtime dependencies.
3736
dist-smoke:
3837
name: Published dist works on Node ${{ matrix.node-version }}
3938
runs-on: ubuntu-latest
4039
needs: test
4140
strategy:
4241
matrix:
43-
node-version: [ 18, 20 ]
42+
node-version: [ 24 ]
4443
steps:
4544
- uses: actions/checkout@v4
4645
- uses: actions/setup-node@v4
@@ -79,7 +78,7 @@ jobs:
7978
- uses: actions/checkout@v4
8079
- uses: actions/setup-node@v4
8180
with:
82-
node-version: 22
81+
node-version: 24
8382
cache: npm
8483
- run: npm ci
8584
- run: npm run env:start

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## v2.0.0 [**unreleased**] _Second Toughest in the Infants_
44
- **BREAKING**: "Node-style" error-first callbacks (_e.g._ `.get( ( err, data ) => {} )`) are no longer supported. All transport request methods return Promises.
5-
- **BREAKING**: The minimum supported Node.js version is now v18; Internet Explorer is no longer supported.
5+
- **BREAKING**: The minimum supported Node.js version is now v24; Internet Explorer is no longer supported.
66
- **BREAKING**: HTTP requests are made with the native `fetch` API. The superagent transport and the `wpapi/superagent` entrypoint introduced in the v2 alphas are removed; the default `wpapi` export makes HTTP requests out of the box again, with no additional dependencies. `wpapi/fetch` remains as an alias for the default export.
77
- **BREAKING**: Media uploads use native `FormData`/`Blob`. `.file()` accepts a file path (Node), a `Buffer` or `Blob` plus a file name, or a `File` object; streams are no longer supported. The multipart part's content type is no longer inferred from the file name (WordPress determines the type server-side from the name); pass a `Blob` or `File` with an explicit `type` to control it.
88
- **BREAKING**: Autodiscovery now either succeeds or fails; a WPAPI instance configured with default routes will no longer be returned.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ const WPAPI = require( 'wpapi' );
6262
import WPAPI from 'wpapi';
6363
```
6464

65-
HTTP requests are made with the `fetch` API built into Node 18+, browsers and other modern JavaScript runtimes, so no other dependencies are required. This library is designed to work in the browser as well, via a build system such as Vite or Webpack; just install the package and import it from your application code.
65+
HTTP requests are made with the `fetch` API built into Node.js (v24 or later is required), browsers and other modern JavaScript runtimes, so no other dependencies are required. This library is designed to work in the browser as well, via a build system such as Vite or Webpack; just install the package and import it from your application code.
6666

6767
### Download the UMD Bundle
6868

fetch/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ provides; the subpath remains as an alias for code written against the v2 alphas
77
## Installation & Usage
88

99
Install `wpapi` using the command `npm install --save wpapi`. No separate fetch
10-
implementation is needed — the library uses the `fetch` global built into Node 18+,
11-
browsers and other modern JavaScript runtimes.
10+
implementation is needed — the library uses the `fetch` global built into Node.js
11+
(v24+), browsers and other modern JavaScript runtimes.
1212

1313
```js
1414
import WPAPI from 'wpapi/fetch';

fetch/fetch-transport.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,10 @@ const createUploadForm = async (
205205
}
206206

207207
const form = new FormData();
208-
// An undefined name must be genuinely omitted, not passed as an explicit third
209-
// argument: FormData coerces a present-but-undefined filename to the string
210-
// "undefined" on Node 18-22, clobbering a File attachment's own name. (Node 24+
211-
// treats a trailing undefined as absent, which masked this in local dev.)
208+
// An undefined name is genuinely omitted rather than passed as an explicit third
209+
// argument: some FormData implementations (Node <=22 among them) coerce a
210+
// present-but-undefined filename to the string "undefined", clobbering a File
211+
// attachment's own name, and browser bundles run on engines we don't control.
212212
// Cast: by this point `file` is always a Blob at runtime (the `string` and
213213
// `Buffer` cases above always reassign it to one), but TS can't prove the
214214
// `globalThis.Buffer &&`-guarded branch always narrows away `Buffer`.

handoff.md

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,23 +65,34 @@ the exportless superagent stub (emits `export {}` — correct).
6565
Main's CI Node 22 leg had been red since the Phase 2 merge, unnoticed
6666
(local dev runs Node 24). Cause: `FormData#append( name, file, undefined )`
6767
with an explicit third argument coerces the filename to the string
68-
`"undefined"` on Node 18-22, clobbering a File attachment's own name;
68+
`"undefined"` on Node <=22, clobbering a File attachment's own name;
6969
Node 24+ treats a trailing undefined as absent. Fixed in fetch-transport's
70-
`createUploadForm` by omitting the argument when there is no name override.
71-
Lesson: run the transport suite under the oldest CI Node before merging
72-
transport changes (`nvm exec 22 npx vitest run fetch/tests/unit`).
70+
`createUploadForm` by omitting the argument when there is no name override
71+
(kept after the Node 24 floor bump: explicit omission also protects
72+
browser-bundle consumers on engines we don't control). Lesson: run the
73+
transport suite under the oldest supported Node before merging transport
74+
changes.
75+
76+
### Node floor raised to 24 (post-Phase 3)
77+
78+
`engines.node >=24`; CI test matrix is 24/latest, integration and
79+
dist-smoke run on 24 (dist-smoke retained for its production-only-install
80+
check of the built artifact, not for old-Node coverage). `@types/node@^24`.
81+
Newly unlocked, not yet used (candidates for Phase 4+): `File` global and
82+
`instanceof File` checks, `fs.openAsBlob()` to stream path uploads instead
83+
of buffering whole files, raising tsconfig `target` beyond es2020.
7384

7485
### Dependency notes
7586

76-
- Added `@types/node@^20` (vitest 4's peer floor; the published runtime
77-
floor is still Node 18 — types won't catch Node 19/20-only API use, so
78-
keep runtime code 18-safe; CI dist-smoke on 18 covers require-ability
79-
only), `@types/qs`, and an ambient `types/li.d.ts` (li has no published
80-
types).
81-
- `parse-link-header` is a declared runtime dependency that nothing
82-
imports (pagination uses `li`). Candidate for removal — human call.
83-
- The Dependabot alert (1 high) noted after the Phase 2 push is still
84-
unaddressed and unrelated to this phase.
87+
- `parse-link-header` removed — it was dead weight since Dec 2018 (commit
88+
4bf3a31 switched pagination back to `li` for bundle size but never
89+
dropped it from package.json), and it was the repo's 1-high Dependabot
90+
alert (runtime scope), now resolved.
91+
- `@types/qs` and an ambient `types/li.d.ts` added in Phase 3 (li has no
92+
published types).
93+
- `npm audit` still reports 4 high in dev-only paths, all under
94+
`jsdoc@3.6` (linkify-it, taffydb) — goes away when Phase 6 replaces
95+
jsdoc with TypeDoc.
8596

8697
## Dev workflow
8798

@@ -105,8 +116,9 @@ npm run test:integration
105116
rolldown trap above).
106117
- **One tsdown config per Node entry, each bundling its full closure** (a
107118
shared chunk breaks rolldown's CJS `module.exports` codegen).
108-
- **Build tooling needs Node 22+**; published dist supports 18+ (CI
109-
dist-smoke checks that separately).
119+
- **Node 24+ everywhere** since the floor bump: runtime, build tooling,
120+
and CI all share the same floor (this retired the old split where dist
121+
supported 18+ but the toolchain needed 22+).
110122
- **Integration tests share one wp-env DB**: keep `--no-file-parallelism`.
111123

112124
## Known gap (deferred to Phase 5)

lib/constructors/wp-request.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -626,9 +626,9 @@ class WPRequest {
626626
}
627627
// Uploads need a file name with an extension for WordPress to accept them, and
628628
// raw data objects carry none of their own; require one rather than fail obscurely.
629-
// A Blob is checked for a name property rather than a File instanceof because the
630-
// File global does not exist on Node 18. (Blob's type has no `.name`, hence the
631-
// cast: the check is a runtime duck-type test for a File masquerading as a Blob.)
629+
// A Blob is checked for a name property rather than a File instanceof so that any
630+
// Blob-like object carrying its own name is accepted, File instances included.
631+
// (Blob's type has no `.name`, hence the cast for the duck-type test.)
632632
if ( ! name && ( isBuffer || ( isBlob && typeof ( file as { name?: unknown } ).name !== 'string' ) ) ) {
633633
throw new Error( '.file(): File name is a required argument when uploading a Buffer or Blob' );
634634
}

package-lock.json

Lines changed: 8 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"wordpress"
2424
],
2525
"engines": {
26-
"node": ">=18"
26+
"node": ">=24"
2727
},
2828
"scripts": {
2929
"build": "rimraf dist && tsdown && node build/scripts/finalize-dist.js",
@@ -55,12 +55,11 @@
5555
},
5656
"dependencies": {
5757
"li": "^1.3.0",
58-
"parse-link-header": "^1.0.1",
5958
"qs": "^6.7.0"
6059
},
6160
"devDependencies": {
6261
"@eslint/js": "^9.39.5",
63-
"@types/node": "^20.19.43",
62+
"@types/node": "^24.13.3",
6463
"@types/qs": "^6.15.1",
6564
"@vitest/coverage-v8": "^4.1.10",
6665
"combyne": "^2.0.0",

0 commit comments

Comments
 (0)