Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
12cad9c
fix(deps): remove harmful resolutions, refresh lockfile (71 -> 5 advi…
Devon-White Aug 16, 2026
2aa2cf3
refactor(deps): reclassify Docusaurus as build tooling; React 18+19 p…
Devon-White Aug 16, 2026
a9e8194
ci: replace unsatisfiable audit gate; make the test job actually run …
Devon-White Aug 16, 2026
d602d39
ci(react): matrix-test React 18 and 19; document the support contract
Devon-White Aug 16, 2026
494bb41
chore(theme): apply the same dependency and dead-code hygiene as the …
Devon-White Aug 16, 2026
1cc0aeb
fix(build): repair theme type-checking and stop publishing test files
Devon-White Aug 16, 2026
a6a234d
chore: tighten published types and dependency hygiene
Devon-White Aug 16, 2026
1a7a54e
docs(theme): fix malformed nested block comment in theme-llms-txt.d.ts
Devon-White Aug 16, 2026
2aea0e7
fix(deps): declare tslib and the Docusaurus libraries the plugin imports
Devon-White Aug 16, 2026
56649e1
test(theme): make the "renders nothing" assertions able to fail
Devon-White Aug 16, 2026
84e4651
fix(ci): pin @testing-library/jest-dom below its Node 22 engines bump
Devon-White Aug 16, 2026
e33aa71
fix(deps): force lerna's pinned tar@6.2.1 up to the patched 7.x line
Devon-White Aug 16, 2026
64f4303
fix(ci): repair the React 18 leg and clear the js-yaml advisory
Devon-White Aug 16, 2026
d3ff705
ci: accept the brace-expansion advisory nx pins, with justification
Devon-White Aug 16, 2026
cf14786
docs: trim verbose comments across the test harness and CI config
Devon-White Aug 17, 2026
4a5c9b7
chore: strip dead release config from lerna.json
Devon-White Aug 17, 2026
c8ee350
build: migrate from Yarn 1 to pnpm
Devon-White Aug 17, 2026
46d4ecf
ci: accept the unfixable image-size advisories; run CI on stacked PRs
Devon-White Aug 17, 2026
d1106d1
fix(deps): override serialize-javascript instead of accepting it
Devon-White Aug 17, 2026
3658659
build: move pnpm settings into pnpm-workspace.yaml, matching Docusaurus
Devon-White Aug 17, 2026
02d5ede
fix(ci): pin React through pnpm-workspace.yaml, not package.json
Devon-White Aug 17, 2026
5f8429b
fix(build): harden pnpm release and React compatibility
Devon-White Aug 23, 2026
125bafd
fix(deps): patch SockJS uuid advisory
Devon-White Aug 23, 2026
de0e018
fix pnpm migration review findings
Devon-White Aug 23, 2026
b721cce
fix remaining pnpm migration review findings
Devon-White Aug 23, 2026
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: 10 additions & 0 deletions .changeset/lucky-pears-wander.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@signalwire/docusaurus-theme-llms-txt': patch
---

Fix the theme failing to type-check under React 18. `useDropdownState` declared its ref as
`RefObject<HTMLDivElement | null>` — the React 19 `@types/react` shape — which React 18 rejects when
assigned to a `ref` prop, so a site on React 18 that type-checks a swizzled `CopyPageContent` hit
TS2322. Release builds now emit declarations against the lowest supported React types, while CI also
rebuilds and tests against React 19. The package advertises `react: ^18.0.0 || ^19.0.0`, so the
published declaration remains consumable under either major.
66 changes: 66 additions & 0 deletions .changeset/olive-pans-smoke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
'@signalwire/docusaurus-plugin-llms-txt': minor
'@signalwire/docusaurus-theme-llms-txt': minor
---

Support React 19 alongside 18, raise the Docusaurus floor, and stop shipping Docusaurus as a runtime
dependency.

**Breaking — check your peer dependencies before upgrading.**

- `@docusaurus/core` is now required to be `^3.10.0` (was `^3.0.0`). Docusaurus only gained React 19
support in 3.7 and dropped Node 18 in 3.9, so the old range advertised combinations that could not
actually work. Version 3.10 is the compatibility baseline exercised by this release.
- The theme now declares `react`/`react-dom` as `^18.0.0 || ^19.0.0`, matching
`@docusaurus/theme-classic`. The previous `^18.0.0` cap was wrong: the package already shipped
React 19 types and was used on React 19 sites, so npm and pnpm users hit a peer conflict.
- `@docusaurus/core` and `@docusaurus/theme-common` moved from `dependencies` to `peerDependencies`
on the theme. Installing this theme no longer pulls a second copy of Docusaurus into your
`node_modules`.
- The plugin now declares `@docusaurus/logger`, `@docusaurus/utils` and
`@docusaurus/utils-validation` as `dependencies` (previously resolved only by hoisting). These are
libraries rather than the build tool, and sites never install them by name, so declaring them as
peers would leave them unmet under Yarn Classic and unresolved under pnpm. Keeping
`@docusaurus/core` as the only peer prevents a third-party package from pulling a second copy of
core. First-party Docusaurus packages instead pin core as an exact lockstep dependency, which a
third-party package cannot do.
- Minimum Node is now 20, matching the Docusaurus 3.10 baseline.

**Fixed**

- The ChatGPT dropdown icon crashed on any fresh install. The theme depends on `react-icons@^5.5.0`,
and 5.7.0 removed `SiOpenai` (Simple Icons dropped the OpenAI logo), so the import resolved to
`undefined` and React threw "Element type is invalid". Now uses `RiOpenaiFill`.
- The plugin no longer imports the `commander` type `CommanderStatic`, a commander@5-only name that
would break when Docusaurus bumps commander. The CLI argument type is derived from Docusaurus's
own `Plugin` interface instead.
- Declared `remark-parse`, `hast-util-to-mdast` and `@types/mdast`, which the plugin imported
without declaring. These previously resolved only via hoisting and would fail under pnpm or any
strict node_modules layout.
- Declared `tslib` on the theme. The build sets `importHelpers`, so 15 files in the published `lib/`
require it at runtime; it had been supplied only through `@docusaurus/core`'s own dependency tree,
which moving core to a peer removed. Under pnpm or a nested npm layout the theme failed to render
with `Cannot find module 'tslib'`.
- GFM options are now applied consistently. Omitting the `markdown` key entirely silently dropped
every GFM default, so `{llmsTxt: {...}}` and `{markdown: {}, llmsTxt: {...}}` emitted different
Markdown: the first reached `remark-gfm` with none of `stringLength`, `tablePipeAlign`,
`tableCellPadding` or `singleTilde`, misaligning table pipes for CJK and emoji content.
`undefined` now resolves to the same defaults as an explicit `remarkGfm: true`.

**Packaging**

- Test files are no longer published. The theme ships `src/theme` as the TypeScript swizzle
template, so a co-located test would have been copied into users' sites by
`docusaurus swizzle --typescript`.
- TypeScript swizzles now resolve the theme's hooks, types, and icon dependencies through exported
package entry points. Those source helpers are included in the tarball, so an ejected
`CopyPageContent` compiles in a consuming site under pnpm's strict dependency layout.
- The `@theme/*` module declarations now ship with the theme that provides those components. If your
`tsconfig.json` explicitly lists `@signalwire/docusaurus-plugin-llms-txt` in
`compilerOptions.types`, replace it with `@signalwire/docusaurus-theme-llms-txt`.
- The plugin's root TypeScript entry point now uses its generated declarations. Published consumers
can resolve `Options` and the default plugin signature without reaching an unshipped `src/types`
directory, and the declarations stay aligned with the runtime exports.
- `lib/.tsbuildinfo` is no longer published. It is TypeScript's incremental build cache and was the
single largest file in both tarballs: unpacked size drops from 204KB to 111KB (theme) and 473KB to
366KB (plugin).
1 change: 0 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ website/
**/assets/
**/*.min.js
**/*bundle*.js
__tests__/
development/
.eslintrc.*
16 changes: 13 additions & 3 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ module.exports = {
jsx: true,
},
},
globals: {
JSX: true,
},
extends: [
'eslint:recommended',
'plugin:react-hooks/recommended',
Expand Down Expand Up @@ -439,12 +436,25 @@ module.exports = {
'scripts/**/*',
'website/**/*',
'__tests__/**/*',
'test/**/*',
],
rules: {
'header/header': OFF,
'@docusaurus/no-untranslated-text': OFF,
'import/no-extraneous-dependencies': OFF,
},
},
// Jest setup and module stand-ins under test/ are harness code, not specs:
// top-level hooks are the point, and the stand-ins deliberately mirror
// module shapes rather than being real React components.
{
files: ['test/**/*'],
rules: {
'jest/require-top-level-describe': OFF,
'react/no-unused-prop-types': OFF,
'import/no-default-export': OFF,
'import/no-named-export': OFF,
},
},
],
};
11 changes: 8 additions & 3 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: 'Setup Node.js and Dependencies'
description: 'Setup Node.js with yarn cache and install dependencies'
description: 'Setup pnpm and Node.js with a dependency cache, then install'

inputs:
node-version:
Expand All @@ -10,12 +10,17 @@ inputs:
runs:
using: 'composite'
steps:
# Must precede setup-node: the pnpm cache key needs a resolvable store path.
# Version comes from packageManager in package.json.
- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'yarn'
cache: 'pnpm'

- name: Install dependencies
run: yarn install --frozen-lockfile
run: pnpm install --frozen-lockfile
shell: bash
64 changes: 64 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# The root cause of the 71-advisory pile-up was a lockfile that went ~9 months
# without a refresh: nearly every advisory was a caret-ranged transitive whose
# patch was already inside the declared range. This config exists so that does
# not happen again.
#
# Cooldown values mirror facebook/docusaurus. Deliberately not immediate: a
# cooldown window is what gives the ecosystem time to spot a compromised
# release before we pull it in. Security updates bypass cooldown.
version: 2
updates:
- package-ecosystem: github-actions
directory: '/'
schedule:
interval: monthly
labels:
- 'dependencies'
groups:
github-actions:
patterns: ['*']

- package-ecosystem: npm
directory: '/'
schedule:
interval: weekly
open-pull-requests-limit: 5
labels:
- 'dependencies'
cooldown:
default-days: 5
semver-major-days: 30
semver-minor-days: 8
semver-patch-days: 8
groups:
# One PR per ecosystem rather than one per package. Docusaurus ships ~20
# packages in lockstep, so ungrouped updates would be unreviewable.
docusaurus:
patterns:
- '@docusaurus/*'
- 'docusaurus-plugin-*'
react:
patterns:
- 'react'
- 'react-dom'
- '@types/react'
- '@types/react-dom'
unified:
patterns:
- 'unified'
- 'remark-*'
- 'rehype-*'
- 'hast-util-*'
- 'mdast-util-*'
- 'unist-util-*'
- '@types/hast'
- '@types/mdast'
dev-tooling:
dependency-type: development
patterns: ['*']
exclude-patterns:
- '@docusaurus/*'
- 'react'
- 'react-dom'
- '@types/react'
- '@types/react-dom'
100 changes: 66 additions & 34 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ name: CI
on:
push:
branches: [main, develop]
# No branch filter: a PR stacked on another feature branch still needs CI.
pull_request:
branches: [main, develop]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand All @@ -22,55 +22,87 @@ jobs:
uses: ./.github/actions/setup

- name: Build packages
run: yarn run build:packages
run: pnpm run build:packages

- name: Check code formatting
run: yarn run format:check
run: pnpm run format:check

- name: Lint
run: yarn run lint
run: pnpm run lint

- name: Type check
run: yarn run type-check

test-plugins:
name: Test Plugins
run: pnpm run type-check

- name: Type check tests
run: pnpm exec tsc -p tsconfig.test.json

# A safe component must build from only the directory Docusaurus copies
# for that component. This catches relative imports into parent theme
# directories that a full CopyPageContent ejection would hide.
- name: Build individually ejected safe icons
run: |
pnpm --filter website exec docusaurus swizzle \
@signalwire/docusaurus-theme-llms-txt CopyPageContent/Icons/ChatGPTIcon \
--eject --typescript
pnpm --filter website exec docusaurus swizzle \
@signalwire/docusaurus-theme-llms-txt CopyPageContent/Icons/ChevronIcon \
--eject --typescript
pnpm --filter website exec docusaurus swizzle \
@signalwire/docusaurus-theme-llms-txt CopyPageContent/Icons/ClaudeIcon \
--eject --typescript
pnpm --filter website exec docusaurus swizzle \
@signalwire/docusaurus-theme-llms-txt CopyPageContent/Icons/MarkdownIcon \
--eject --typescript
pnpm run build:website:only
rm -rf website/src/theme/CopyPageContent

- name: Type check ejected theme source
run: |
pnpm --filter website exec docusaurus swizzle \
@signalwire/docusaurus-theme-llms-txt CopyPageContent \
--eject --typescript --danger
pnpm --filter website exec tsc --noEmit

# Both published packages declare `react: ^18.0.0 || ^19.0.0`. Docusaurus v4
# will require React 19, but v3 sites are still on 18, so both legs have to
# stay green -- otherwise that peer range is an unverified claim.
test:
name: Test (React ${{ matrix.react }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
react: ['18', '19']
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js and Dependencies
uses: ./.github/actions/setup

- name: Build packages
run: yarn run build:packages
# React 18 is the lockfile baseline installed by the setup action. pnpm
# overrides apply tree-wide, so only the React 19 leg needs a re-pin and
# reinstall; changing root dependencies alone would leave nested types
# on React 18.
- name: Pin React 19
if: matrix.react == '19'
run: |
node scripts/pinReact.js 19
pnpm install --no-frozen-lockfile

# Guards against the leg silently testing the wrong version. Checks the
# types too: a runtime-only pin would leave tsc on the other major.
- name: Verify React ${{ matrix.react }} everywhere
run: node scripts/checkReactVersions.js ${{ matrix.react }}

- name: Test packages
run: yarn run test
- name: Build packages
run: pnpm run build:packages

test-website:
name: Test Website Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Type check
run: pnpm run type-check

- name: Setup Node.js and Dependencies
uses: ./.github/actions/setup
- name: Test packages
run: pnpm run test:ci

- name: Build website
run: yarn run build:website

security-audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js and Dependencies
uses: ./.github/actions/setup

- name: Run security audit
run: yarn audit --groups dependencies
run: pnpm run build:website:only
51 changes: 51 additions & 0 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Dependency Review

# Replaces the old `yarn audit --groups dependencies` gate, which could never
# pass: Yarn Classic's `--level` flag filters only what is printed, not the exit
# code (it is a bitmask over the unfiltered result set), and there is no way to
# accept an advisory that has no available fix.
#
# This gates the DELTA instead of the inventory. A PR that touches a README can
# no longer fail on a pre-existing transitive advisory, but a PR that introduces
# a newly vulnerable dependency still fails. This mirrors what Docusaurus itself
# runs -- see .github/workflows/dependency-review.yml in facebook/docusaurus,
# which has no audit step at all.

on: [pull_request]

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read
pull-requests: write # required by comment-summary-in-pr

jobs:
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Dependency Review
uses: actions/dependency-review-action@v5
with:
fail-on-severity: high

# `fail-on-scopes` defaults to `runtime`, which is the whole point:
# build/dev tooling is out of the threat model for a static-site
# toolchain. See facebook/docusaurus#5501 and
# facebook/create-react-app#11174.

comment-summary-in-pr: on-failure
show-patched-versions: true

# Only advisories with no patch at any version belong here.
#
# Both below are image-size 2.0.2, reached through @docusaurus/core.
# Neither has a patched release (verified via the GitHub advisory
# API), and both are parser DoS in a build-time image reader that
# never runs in a deployed site. Drop them if a fix ever ships.
allow-ghsas: GHSA-w3rx-r6r6-pgpr, GHSA-5p2g-fcmc-qvqq
Loading
Loading