Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 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
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
56 changes: 56 additions & 0 deletions .changeset/olive-pans-smoke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
'@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.9.0 || ^4.0.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. Docusaurus v4 is pre-accepted so upgrading to it will not trip a
peer-dependency error.
- 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. `@docusaurus/core`
remains the only peer, matching what every first-party Docusaurus plugin declares.
- Minimum Node is now 20, matching Docusaurus 3.9+.

**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`.
- `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,
},
},
],
};
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'
80 changes: 54 additions & 26 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,44 +33,72 @@ jobs:
- name: Type check
run: yarn run type-check

test-plugins:
name: Test Plugins
# 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

# The website pins its own React range, so swapping only the root would
# leave a nested copy behind and the build would not actually exercise
# the matrix version.
- name: Pin React ${{ matrix.react }}
run: |
yarn add -W --dev \
react@^${{ matrix.react }} \
react-dom@^${{ matrix.react }} \
@types/react@^${{ matrix.react }} \
@types/react-dom@^${{ matrix.react }}
yarn workspace website add \
react@^${{ matrix.react }} \
react-dom@^${{ matrix.react }}
# Yarn 1.22 `workspace <name> add` drops hoisted root devDependencies
# from node_modules (@testing-library/*, rimraf) while leaving them in
# package.json. This restores them; the pinned React is unaffected.
yarn install

# Guards against the leg silently testing the wrong version: if the
# website kept a nested copy, root and site would resolve different
# files and the build below would not be exercising matrix.react at all.
- name: Verify the whole workspace resolves one React ${{ matrix.react }}
run: |
node -e "
const path = require('path');
const resolve = (from) =>
require.resolve('react/package.json', { paths: [from] });
const root = resolve(process.cwd());
const site = resolve(path.join(process.cwd(), 'website'));
const version = require(root).version;
console.log('root ->', root);
console.log('site ->', site);
console.log('version->', version);
if (root !== site) {
throw new Error('website resolves a different React copy');
}
if (!version.startsWith('${{ matrix.react }}.')) {
throw new Error('expected React ${{ matrix.react }}.x, got ' + version);
}
"

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

- name: Test packages
run: yarn run test

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

- name: Setup Node.js and Dependencies
uses: ./.github/actions/setup
- name: Test packages
run: yarn 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
56 changes: 56 additions & 0 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
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

# Dev-only DoS advisories in versions lerna/nx pin exactly. All three
# are dev-time only: `yarn audit --groups dependencies` is clean.
#
# js-yaml@4.1.1 (x2) pinned by lerna, patched in 4.3.1
# brace-expansion@5.0.8 pinned by nx, patched in 5.0.9
#
# Not fixable by `resolutions`: Yarn 1.22 ignores the scoped
# `lerna/js-yaml` form, and an unscoped entry rewrites every range for
# the name -- forcing read-yaml-file (used by @changesets/cli) onto
# js-yaml 4.x, where the `safeLoad` it calls no longer exists.
# Removing lerna is the real fix; see issue for tracking.
allow-ghsas: GHSA-5p4m-2wfm-xmqj, GHSA-52cp-r559-cp3m, GHSA-rgw5-rvv9-x895
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ export default config;

### Prerequisites

- Node.js ≥ 18.0.0
- Yarn 1.22.0
- Node.js ≥ 20.0.0
- Yarn 1.22.x (Yarn Classic)

### Setup

Expand Down Expand Up @@ -130,17 +130,17 @@ docusaurus-plugins/
│ ├── docusaurus-plugin-llms-txt/
│ └── docusaurus-theme-llms-txt/
├── website/ # Demo/documentation site
├── .changeset/ # Changeset configuration
├── lerna.json # Lerna configuration
├── .changeset/ # Versioning and release (changesets)
├── lerna.json # Lerna config -- task running only
└── package.json # Root package with workspaces
```

### Technology Stack

- **Package Management**: Yarn Workspaces + Lerna
- **Package Management**: Yarn Workspaces (linking) + Lerna (task running)
- **Build System**: TypeScript with project references
- **Version Management**: Changesets
- **Code Quality**: ESLint + Prettier + Husky
- **Code Quality**: ESLint + Prettier
- **Testing**: Jest
- **Documentation**: Docusaurus

Expand Down
Loading
Loading