Add publishing, lint, and type-drift gates from create-ts-lib - #11
Conversation
The package had no linter, no typechecker, no coverage floor, and nothing standing between a local `npm publish` and the registry. This adds the gates, adapted to a build-less .mjs library rather than adopting create-ts-lib's TypeScript-source layout wholesale. Publishing. `release.yml` fires on a published GitHub release, not a tag push, checks the tag against package.json, runs the full gate, and publishes with npm trusted publishing (OIDC) and --provenance. There is no NPM_TOKEN; the first release needs trusted publishing configured on npmjs.com, and until then the publish step fails on authentication, which is the intended failure mode. `prepublishOnly` and `release:check` make that gate runnable locally. Type drift. index.d.ts is hand-written against .mjs sources and the exports map points consumers straight at src/index.mjs, so nothing verified the two agreed. tsconfig.json now runs strict checkJs over src, bin and index.d.ts, with `fonts()` annotated against its own published FontsOptions and Plugin types; test/types.test.mjs imports the package by name (through the exports map) and diffs runtime exports against declared ones; publint and attw check the packed shape. Getting to zero errors surfaced two real defects: codemodCss's JSDoc was missing its first @PARAM, so every option was typed against the wrong parameter, and a bare @import or @theme in a JSDoc description is parsed as a tag and silently truncates the enclosing @typedef. Coverage thresholds are a ratchet just under today's numbers, not the 80% the template uses -- index.mjs sits at 43% because the Vite hooks are covered by the fixture build rather than unit tests. They are enforced on Node 22 only, since V8's coverage output shifts between releases. Node floor moves to 22 and CI runs 22/24/26, split into a hermetic `checks` matrix and a single-version `integration` job for the work that needs network. Most of the diff is oxfmt reflow; `git diff -w` shows the substance. Two lint findings were real (a useless spread in the CLI, a useless fallback in extras/server.ts). Behaviour is unchanged: 48 tests pass, the fixture builds, and all six CI metric invariants still hold. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
📝 WalkthroughWalkthroughThe pull request adds strict JavaScript type checking, a shared Sequence Diagram(s)sequenceDiagram
participant GitHubRelease
participant ReleaseWorkflow
participant Npm
GitHubRelease->>ReleaseWorkflow: publish release event
ReleaseWorkflow->>ReleaseWorkflow: validate tag and run checks
ReleaseWorkflow->>Npm: publish with provenance and dist-tag
Possibly related PRs
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/release.yml:
- Line 48: Update the release workflow command assigning tag to avoid
interpolating github.event.release.tag_name directly into shell source; pass the
release tag through the step or job env and read it from an environment variable
inside the shell script, preserving the existing tag value used by the publish
flow.
- Around line 32-41: Pin the release workflow toolchain by changing node-version
from 22 to 22.14.0 and replacing npm@latest in the Upgrade npm step with
npm@11.5.1. Keep the existing npm installation and PATH setup unchanged.
- Line 33: Remove the explicit cache: pnpm setting from the publishing job in
the release workflow, leaving package-manager-cache: false intact so the release
path neither restores nor saves the pnpm store.
In `@docs/MAINTAINERS.md`:
- Line 31: Update the documentation comment for the `pnpm run check` command in
MAINTAINERS.md to describe it as the local lint → typecheck → coverage gate,
removing the claim that it represents all CI work and runs on every Node
version.
In `@tsconfig.json`:
- Line 12: Update the tsconfig.json compiler option skipLibCheck from true to
false, or remove it, so pnpm run typecheck validates index.d.ts and other
included declaration files.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 74d2928a-6029-49de-bf23-f1a9fb570519
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (29)
.github/dependabot.yml.github/workflows/ci.yml.github/workflows/release.yml.gitignore.oxfmtrc.json.oxlintrc.jsonbin/tss-fonts.mjsdocs/MAINTAINERS.mdextras/opsz-policy.mjsextras/server.tsharness/clswidth.mjsharness/sweep.mjsharness/targets.mjsharness/waterfall.mjsindex.d.tspackage.jsonsrc/codemod-css.mjssrc/detect.mjssrc/diff.mjssrc/generate.mjssrc/index.mjssrc/metrics.mjssrc/opsz.mjstest/detect.test.mjstest/metrics.test.mjstest/opsz.test.mjstest/types.test.mjstest/vite-codemod.test.mjstsconfig.json
| node-version: 22 | ||
| cache: pnpm | ||
| registry-url: https://registry.npmjs.org | ||
|
|
||
| # Node 22 ships npm 10, which predates trusted publishing. | ||
| - name: Upgrade npm | ||
| run: | | ||
| npm config set prefix ~/.local | ||
| echo "$HOME/.local/bin" >> "$GITHUB_PATH" | ||
| PATH="$HOME/.local/bin:$PATH" npm install -g npm@latest |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- workflow ---'
cat -n .github/workflows/release.yml | sed -n '1,90p'
printf '%s\n' '--- repository toolchain declarations ---'
rg -n --hidden -S 'node-version|npm@|packageManager|engines|trusted|provenance|npm publish|actions/setup-node' \
.github package.json pnpm-lock.yaml 2>/dev/null || true
printf '%s\n' '--- local npm/node availability ---'
node --version 2>/dev/null || true
npm --version 2>/dev/null || trueRepository: hbmartin/tailwind-vite-font-kit
Length of output: 12923
🌐 Web query:
npm trusted publishing requirements npm 11.5.1 Node 22.14.0 official documentation
💡 Result:
Trusted publishing in npm allows you to publish packages directly from CI/CD workflows using OpenID Connect (OIDC) authentication, removing the requirement for long-lived npm access tokens [1][2]. As of the specified versions (npm 11.5.1 and Node.js 22.14.0), the requirements and details for using trusted publishing are: Core Version Requirements - npm CLI: Version 11.5.1 or later [1][2]. - Node.js: Version 22.14.0 or higher [1][2]. General Prerequisites - Existing Package: The npm package must already exist on the registry before a trusted publisher can be configured for it [3][4]. - Permissions: You must have write access (maintainer or owner) to the package [3][4]. - Account Security: Two-factor authentication (2FA) must be enabled at the npm account level [3][5]. - CI/CD Provider: You must use a supported cloud-based CI/CD provider (such as GitHub Actions, GitLab CI/CD, or CircleCI) with cloud-hosted runners [1][6][4]. Self-hosted runners are not supported [1]. Configuration and Usage - OIDC Authentication: Trusted publishing works by exchanging a short-lived OIDC token for an npm publish token at runtime [4][2]. - Provenance: When using trusted publishing, provenance attestations are automatically generated for your packages without requiring the --provenance flag [6]. - Command Flags: When configuring trust relationships, you must specify at least one permission flag: --allow-publish or --allow-stage-publish [3][5]. - Important Note: If you encounter an ENEEDAUTH error, ensure that all fields in your configuration (such as workflow filenames and IDs) are exact and case-sensitive [1]. Additionally, for GitHub Actions, verify that the id-token: write permission is set in your workflow file [1].
Citations:
- 1: https://docs.npmjs.com/trusted-publishers/
- 2: https://github.com/npm/documentation/blob/main/content/packages-and-modules/securing-your-code/trusted-publishers.mdx
- 3: https://docs.npmjs.com/cli/v12/commands/npm-trust/
- 4: https://circleci.com/docs/guides/deploy/deploy-to-npm-registry/index.md
- 5: https://docs.npmjs.com/cli/v11/commands/npm-trust/
- 6: https://docs.npmjs.com/generating-provenance-statements/
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- package metadata ---'
cat -n package.json | sed -n '18,75p'
printf '%s\n' '--- npm 11.5.1 metadata ---'
curl -fsSL https://registry.npmjs.org/npm/11.5.1 |
jq '{version, engines, dist: {tarball, integrity}}'
printf '%s\n' '--- npm latest metadata ---'
curl -fsSL https://registry.npmjs.org/npm/latest |
jq '{version, engines}'
printf '%s\n' '--- setup-node version-resolution documentation references ---'
rg -n -S 'node-version: 22|22\.14\.0|semver|latest|check-latest' .github README.md package.json 2>/dev/null || trueRepository: hbmartin/tailwind-vite-font-kit
Length of output: 3800
Pin the npm trusted-publishing toolchain.
Set node-version to 22.14.0 and install npm@11.5.1 instead of npm@latest. Both current version selectors can change independently and can alter or break the release workflow.
🧰 Tools
🪛 zizmor (1.29.0)
[warning] 41-41: ad-hoc installation of packages (adhoc-packages): installs a package outside of a lockfile
(adhoc-packages)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/release.yml around lines 32 - 41, Pin the release workflow
toolchain by changing node-version from 22 to 22.14.0 and replacing npm@latest
in the Upgrade npm step with npm@11.5.1. Keep the existing npm installation and
PATH setup unchanged.
Source: Linters/SAST tools
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | ||
| with: | ||
| node-version: 22 | ||
| cache: pnpm |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- workflow files ---'
git ls-files '.github/workflows/release.yml'
printf '%s\n' '--- release workflow ---'
cat -n .github/workflows/release.ymlRepository: hbmartin/tailwind-vite-font-kit
Length of output: 3052
🌐 Web query:
npm trusted publishing package manager caching release builds setup-node cache pnpm guidance
💡 Result:
To set up npm trusted publishing with dependency caching in your CI/CD workflows, follow this guidance based on current best practices for August 2026. Trusted Publishing Overview Trusted publishing replaces long-lived NPM_TOKEN secrets with short-lived OpenID Connect (OIDC) tokens [1][2]. You must configure the trust relationship on npmjs.com under your package settings, specifying your CI provider, repository, and workflow constraints [3][2]. Your CI job requires id-token: write permissions [4][5][2]. When configured, the npm CLI automatically detects the environment and uses OIDC to authenticate, removing the need for an explicit authentication token [1][2]. Caching Guidance For release builds, it is common practice to disable automatic package manager caching to ensure the environment is clean and reproducible [4][5]. However, for general CI jobs or if you choose to cache dependencies for speed, note the following configurations: 1. Using setup-node with pnpm: The actions/setup-node action supports caching the pnpm store [6][7]. To implement this, set cache: 'pnpm' in your setup-node configuration [8][7]. Ensure your workflow defines cache-dependency-path: pnpm-lock.yaml to target the correct lockfile [7]. Example Configuration: - uses: actions/setup-node@v7 with: node-version: '24' cache: 'pnpm' cache-dependency-path: pnpm-lock.yaml - run: pnpm install --frozen-lockfile 2. Important Caching Considerations: - Caching for Release Builds: Official documentation often recommends setting package-manager-cache: false during the publish job to ensure build isolation [4][5]. - pnpm and setup-node: Always ensure pnpm is available (e.g., via corepack or pnpm/action-setup) before the setup-node step, as setup-node may fail if it cannot locate the pnpm executable [8][6][9]. - Cache Contents: Using cache: 'pnpm' caches the pnpm store, not the node_modules directory [6][7]. Running pnpm install --frozen-lockfile is still necessary to reconstruct the project layout and validate dependencies against the lockfile [7]. Provenance Trusted publishing automatically generates provenance attestations for your packages [4][10]. If you encounter issues, verify your npm CLI version (v11.15.0 or later is recommended) [1][10]. While automatic in many cases, you can explicitly ensure provenance by adding --provenance to your publish command or setting "provenance": true in your package.json under publishConfig [4][10].
Citations:
- 1: https://circleci.com/docs/guides/deploy/deploy-to-npm-registry/index.md
- 2: https://safeguard.sh/resources/blog/npm-trusted-publishing-walkthrough-2026
- 3: https://circleci.com/docs/guides/deploy/deploy-to-npm-registry/
- 4: https://docs.npmjs.com/generating-provenance-statements/
- 5: https://docs.npmjs.com/trusted-publishers/
- 6: Use actions/setup-node to cache pnpm store instead of doing it manually pnpm/action-setup#76
- 7: https://qaskills.sh/blog/ci-cache-pnpm-store-github-actions
- 8: https://github.com/actions/setup-node/blob/main/docs/advanced-usage.md
- 9: pnpm command does not exist actions/setup-node#1165
- 10: https://philna.sh/blog/2026/01/28/trusted-publishing-npm/
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from urllib.request import urlopen
from html import unescape
import re
url = "https://docs.npmjs.com/trusted-publishers/"
try:
text = urlopen(url, timeout=15).read().decode("utf-8", "replace")
except Exception as exc:
print(f"fetch failed: {exc}")
raise SystemExit(0)
text = re.sub(r"<script\b[^>]*>.*?</script>", " ", text, flags=re.I|re.S)
text = re.sub(r"<style\b[^>]*>.*?</style>", " ", text, flags=re.I|re.S)
text = re.sub(r"<[^>]+>", " ", text)
text = re.sub(r"\s+", " ", unescape(text))
for term in ("cache", "cach", "package-manager-cache", "release build", "npm 11"):
print(f"--- {term} ---")
for m in re.finditer(term, text, flags=re.I):
print(text[max(0, m.start()-250):m.end()+350])
PYRepository: hbmartin/tailwind-vite-font-kit
Length of output: 318
🏁 Script executed:
#!/bin/bash
set -eu
curl -k -L --max-time 20 -sS https://docs.npmjs.com/trusted-publishers/ |
python3 -c 'import sys,re,html; s=sys.stdin.read(); s=re.sub(r"<script\b[^>]*>.*?</script>"," ",s,flags=re.I|re.S); s=re.sub(r"<style\b[^>]*>.*?</style>"," ",s,flags=re.I|re.S); s=re.sub(r"<[^>]+>"," ",s); s=re.sub(r"\s+"," ",html.unescape(s)); terms=("cache","package-manager-cache","release build","publishing workflow"); [(print(f"--- {t} ---\n"+s[max(0,m.start()-300):m.end()+500])) for t in terms for m in list(re.finditer(t,s,re.I))[:10]]'Repository: hbmartin/tailwind-vite-font-kit
Length of output: 6005
🏁 Script executed:
#!/bin/bash
set -eu
curl -k -L --max-time 20 -sS https://raw.githubusercontent.com/actions/setup-node/main/action.yml |
sed -n '1,180p'
printf '%s\n' '--- setup-node cache documentation ---'
curl -k -L --max-time 20 -sS https://raw.githubusercontent.com/actions/setup-node/main/docs/advanced-usage.md |
rg -n -C 4 'package-manager-cache|cache:.*pnpm|cache' | head -120Repository: hbmartin/tailwind-vite-font-kit
Length of output: 8157
🏁 Script executed:
#!/bin/bash
set -eu
for url in \
https://raw.githubusercontent.com/actions/setup-node/main/src/main.ts \
https://raw.githubusercontent.com/actions/setup-node/main/src/cache-restore.ts \
https://raw.githubusercontent.com/actions/setup-node/main/src/cache-save.ts
do
printf '%s\n' "--- $url ---"
curl -k -L --max-time 20 -sS "$url" | rg -n -C 5 'packageManagerCache|cache|restoreCache|saveCache' | head -100
doneRepository: hbmartin/tailwind-vite-font-kit
Length of output: 8002
Remove cache: pnpm from the publishing job.
package-manager-cache: false does not disable an explicitly configured cache input. The job must not restore or save the pnpm store in this release path.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/release.yml at line 33, Remove the explicit cache: pnpm
setting from the publishing job in the release workflow, leaving
package-manager-cache: false intact so the release path neither restores nor
saves the pnpm store.
Source: Linters/SAST tools
|
|
||
| - name: Tag matches package.json version | ||
| run: | | ||
| tag="${{ github.event.release.tag_name }}" |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Do not interpolate the release tag into shell source.
GitHub expands this expression before the shell parses the script. A release tag containing shell metacharacters can alter the command in this OIDC-enabled publish job. Pass the value through env and read the environment variable.
Proposed fix
- name: Tag matches package.json version
+ env:
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
- tag="${{ github.event.release.tag_name }}"
+ tag="$RELEASE_TAG"
pkg="v$(node -p "require('./package.json').version")"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| tag="${{ github.event.release.tag_name }}" | |
| - name: Tag matches package.json version | |
| env: | |
| RELEASE_TAG: ${{ github.event.release.tag_name }} | |
| run: | | |
| tag="$RELEASE_TAG" | |
| pkg="v$(node -p "require('./package.json').version")" |
🧰 Tools
🪛 zizmor (1.29.0)
[error] 48-48: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/release.yml at line 48, Update the release workflow
command assigning tag to avoid interpolating github.event.release.tag_name
directly into shell source; pass the release tag through the step or job env and
read it from an environment variable inside the shell script, preserving the
existing tag value used by the publish flow.
Source: Linters/SAST tools
| ```bash | ||
| pnpm install | ||
| pnpm test # unit tests, no network, ~150 ms | ||
| pnpm run check # everything CI runs on every Node version, in CI's order |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the check description.
check runs lint, typecheck, and coverage only. It does not run all CI work, and coverage is documented as Node-22-only. Describe it as the local lint → typecheck → coverage gate.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/MAINTAINERS.md` at line 31, Update the documentation comment for the
`pnpm run check` command in MAINTAINERS.md to describe it as the local lint →
typecheck → coverage gate, removing the claim that it represents all CI work and
runs on every Node version.
| "allowJs": true, | ||
| "checkJs": true, | ||
| "noEmit": true, | ||
| "skipLibCheck": true, |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/sh
set -eu
# Confirm that the public declaration file is included while declaration checks are enabled.
sed -n '1,28p' tsconfig.json
rg -n '^(export|declare module)' index.d.tsRepository: hbmartin/tailwind-vite-font-kit
Length of output: 974
🏁 Script executed:
#!/bin/sh
set -eu
printf '%s\n' '--- tsconfig.json ---'
cat -n tsconfig.json
printf '%s\n' '--- index.d.ts ---'
cat -n index.d.ts
printf '%s\n' '--- package scripts and typecheck references ---'
node - <<'JS'
const fs = require('fs');
const p = JSON.parse(fs.readFileSync('package.json', 'utf8'));
console.log(JSON.stringify({scripts: p.scripts, types: p.types, files: p.files}, null, 2));
JS
rg -n 'typecheck|tsc|skipLibCheck|index\.d\.ts' --glob '!package-lock.json' --glob '!pnpm-lock.yaml' --glob '!yarn.lock' .Repository: hbmartin/tailwind-vite-font-kit
Length of output: 9099
🏁 Script executed:
#!/bin/sh
set -eu
printf '%s\n' '--- compiler availability ---'
command -v tsc || true
tsc --version 2>/dev/null || true
printf '%s\n' '--- type-surface test ---'
cat -n test/types.test.mjs
printf '%s\n' '--- maintainer typecheck documentation ---'
sed -n '55,73p' docs/MAINTAINERS.md
printf '%s\n' '--- temporary skipLibCheck probe ---'
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT
cat > "$tmpdir/index.d.ts" <<'EOF'
export interface PublicOptions {
value: MissingType
}
EOF
cat > "$tmpdir/use.ts" <<'EOF'
import type { PublicOptions } from "./index.js"
const options: PublicOptions = { value: 1 }
EOF
for setting in true false; do
cat > "$tmpdir/tsconfig.json" <<EOF
{
"compilerOptions": {
"strict": true,
"skipLibCheck": $setting,
"noEmit": true
},
"include": ["index.d.ts", "use.ts"]
}
EOF
echo "skipLibCheck=$setting"
if tsc -p "$tmpdir/tsconfig.json" --pretty false > "$tmpdir/out-$setting.txt" 2>&1; then
echo "status=0"
else
echo "status=$?"
fi
cat "$tmpdir/out-$setting.txt"
doneRepository: hbmartin/tailwind-vite-font-kit
Length of output: 4535
Enable checking for index.d.ts.
skipLibCheck suppresses semantic errors in the included public declaration file. Remove this setting or set it to false so pnpm run typecheck validates the published API declarations.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tsconfig.json` at line 12, Update the tsconfig.json compiler option
skipLibCheck from true to false, or remove it, so pnpm run typecheck validates
index.d.ts and other included declaration files.
Adopts the practices from hbmartin/create-ts-lib that fit a build-less
.mjslibrary. It deliberately does not adopt the TypeScript-source layout, a bundler, Vitest, fallow, or Semgrep — see "Not adopted" below.Most of the diff is oxfmt reflow. Review with
?w=1to hide it.Publishing gates
.github/workflows/release.ymlfires on a published GitHub release, not a tag push. It verifies the tag matchespackage.json, runsrelease:check, and publishes with npm trusted publishing (OIDC,id-token: write) and--provenance.There is no
NPM_TOKENanywhere. The first release through this path needs trusted publishing configured for the package on npmjs.com (publisher: this repo, workflowrelease.yml). Until then the publish step fails on authentication — intended, since there's no token fallback.prepublishOnlyandrelease:checkmake the same gate runnable locally.index.d.ts drift
This was the real gap:
index.d.tsis hand-written against the.mjssources andexportspoints consumers straight atsrc/index.mjs, so nothing verified the two agreed. Three layers now do:tsconfig.jsonruns strictcheckJsoversrc,bin, andindex.d.ts.fonts()is annotated@param {FontsOptions}/@returns {Plugin}, so an option the implementation reads that isn't declared is a typecheck failure.noImplicitAnyanduseUnknownInCatchVariablesare off; the rest of strict is on.test/types.test.mjsimports the package by its own name — which goes through the exports map — and diffs runtime exports against those declared inindex.d.ts. Verified it fails on an undeclared export.publint+attwcheck the packed shape and ESM resolution. Both clean.Getting from 63 type errors to 0 surfaced two real defects:
codemodCss's JSDoc was missing its first@param, so{object} obound to thecssparameter and every option was typed against the wrong thing.@importor@themein a JSDoc description is parsed as a tag by TypeScript and silently truncates the enclosing@typedef's property list.FontPreloadis now a named export instead of being duplicated inline in thevirtual:fontsdeclaration.Coverage
Thresholds via Node's own runner: 66% lines / 71% branches / 59% functions. That's a ratchet just under today's numbers (68.7 / 73.6 / 61.8), not the 80% create-ts-lib uses — 80 would fail immediately, since
index.mjsis at 43% anddetect.mjsat 48%. The Vite hooks are covered by the fixture build rather than unit tests. Enforced on Node 22 only; V8's coverage output shifts between releases.Node floor and CI
enginesmoves to>=22,@types/nodeis pinned to^22so the typecheck reflects the floor, and CI splits into:checks— hermetic, matrix over Node 22/24/26: lint, typecheck, tests. Coverage, publint, attw, andpnpm auditpinned to 22.integration— single version, needs network: registry staleness, fixture build, metrics, invariants.notes— unchanged, nowneeds: [checks, integration].Also
extras/server.ts.@types/nodemajors ignored so it can't drag the Node floor) and fortest/fixture.homepage/bugsinpackage.json;coverage,*.tgz,*.tsbuildinfogitignored.docs/MAINTAINERS.mdgains a Checks section (including the two JSDoc traps) and a corrected release procedure.Not adopted, deliberately
TypeScript source + a bundler (the package ships readable
.mjs; adist/step buys little at ~1500 LOC), Vitest (node --testruns the suite in 150ms), fallow (eight flat source files, no layering to enforce), Semgrep (its ruleset targetseval/child_process; the.exec(hits here are allRegExp.exec), and JSR.Verification
lint,typecheck,test,test:coverage,publint,types:lintall pass. 48 tests green, the fixture builds, and all six CI metric invariants still hold. I confirmed mechanically that every non-formatting diff is one of the changes described above.verify:packagefails locally because0.1.0is already on npm — that's the check working; it clears on the next version bump.🤖 Generated with Claude Code
Summary by cubic
Adds release, lint, type, and coverage gates tailored for a build-less
.mjslibrary. Enables trusted npm publishing and guardsindex.d.tsfrom drifting from the runtime code while tightening CI.New Features
package.json, publishes via npm Trusted Publishing with--provenance. Local gate viaprepublishOnlyandrelease:check.checkJsoversrc,bin, andindex.d.ts; newtest/types.test.mjscompares runtime exports toindex.d.ts;publintand@arethetypeswrong/cliverify the packed shape.checks(Node 22/24/26 for lint, typecheck, unit tests) andintegration(networked fixture/metrics). Coverage ratchet set to 66% lines / 71% branches / 59% functions on Node 22.oxlint+oxfmt, Dependabot for root and fixture, maintainer docs. Fixed two JSDoc issues that broke types and removed minor dead code in the CLI and server.Migration
>=22(@types/nodepinned to^22).release.yml). NoNPM_TOKENis used; publish will fail until trust is set.Written for commit a5175f2. Summary will update on new commits.
Summary by CodeRabbit
New Features
FontPreloadtype for clearer TypeScript usage.Improvements
Documentation