npm run check
Manifest validation, 31 unit tests, and doc index validation must all pass on Node 20, 22, and 24 — CI covers the matrix.
Then run the manual test plan in full. Nothing
in the chrome.* layer is covered by tests, so this is the only gate on the
service worker, popup, content script, and viewer.
The version lives in two places and they must match:
# manifest.json -> "version"
# package.json -> "version"
Chrome requires 1–4 dot-separated integers. Semantic versioning applies: patch for fixes, minor for new behaviour, major for anything that changes permissions or removes a feature.
npm run lint:manifest enforces the format but cannot know the two files agree
— check by eye.
Grep for anything version- or count-specific that has drifted:
grep -rn "31 unit tests\|31 tests" README.md docs/ CLAUDE.md AGENTS.md GEMINI.md .github/
If the test count changed, these all need updating. The same applies to the
permission table in SECURITY.md if manifest.json changed.
npm run build
Produces dist/youtube-transcript-to-pdf-<version>.zip containing only
manifest.json, icons/, src/, and LICENSE — no tests, no scripts, no
.git.
Confirm the contents:
unzip -l dist/youtube-transcript-to-pdf-*.zip
git commit -am "chore: release v<version>"
git tag -a v<version> -m "v<version>"
git push origin main --follow-tags
gh release create v<version> dist/youtube-transcript-to-pdf-<version>.zip \
--title "v<version>" \
--notes "..."
Release notes should say what changed for a user — not the commit list.
The listing is prepared but not yet submitted. Everything the dashboard asks for lives in CHROMEWEBSTORE.md: listing copy, the per-permission justifications, the data-use disclosure, and the asset inventory.
The blockers that file tracked are cleared: the publisher name and contact email are set, the icon is now a document mark rather than a play triangle, and the extension was renamed to “Transcript to PDF for YouTube” so it no longer leads with a trademark.
Screenshot 1 is now a capture of the running extension. Browser automation
cannot reach chrome-extension:// URLs, so that capture has to be taken by
hand: open the popup with a transcript loaded, screenshot it, crop to the popup
alone, and save it as store-assets/raw-popup-live.png. The composer picks it
up automatically and falls back to the harness render when it is absent.
For the full submission procedure, see chrome-web-store-submission.md.
Confirm the privacy policy is still live before every submission — a dead URL is an automatic rejection:
curl -sI https://mithudso.github.io/youtube-transcript-to-pdf/PRIVACY.html | head -1
The permission justifications are what reviews most often fail on. “Needed for
the extension to work” is rejected; each one needs a specific, plain-English
reason, which is why they are written out in full in CHROMEWEBSTORE.md.
After a successful submission, add a row to that file’s Version History and set its status.
Unpacked installs roll back with git checkout <previous-tag> and a reload on
the extension card. A published Web Store release cannot be un-published — only
superseded by a higher version, so a bad release is fixed by shipping a fix.