Skip to content

Surface the repo from the nav, docs and org profile (Tier 0)#790

Merged
choraria merged 4 commits into
mainfrom
tier0-github-stars
Jul 24, 2026
Merged

Surface the repo from the nav, docs and org profile (Tier 0)#790
choraria merged 4 commits into
mainfrom
tier0-github-stars

Conversation

@choraria

@choraria choraria commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

The repo measured four unique visitors in fourteen days. Nothing on any surface we own referred anyone to it — the www navigation carried no GitHub link at all, and the one link in the docs pointed at the org page, which is a repo list with no star button on it.

This is the Tier 0 half of internal/marketing/github-stars-strategy.md. It does not create demand; it stops us discarding the demand we already have.

What's here

www nav — a GitHub mark in the desktop bar and a labelled row at the end of the phone menu, both from a single REPO_LINK that is a member of ALL_NAV_DESTINATIONS, so the existing mobile-parity guard covers it and the two surfaces cannot drift. New nav.test.tsx pins presence, target and a11y.

No star count, deliberately. A bar announcing a small number converts a neutral visit into a negative one on every page view. There is a test that says so, so the decision survives the next person who reaches for a widget.

docs.json — a first-class {"type": "github"} navbar link, and footer.socials.github moved from the org to the repo. Docs is our only surface with measured search impressions.

docs-nav-guard gains collectRepoLinkIssues(), which walks the config rather than checking the two fields we know about today — a curated list would only ever report on the list. It exempts seo.organization.sameAs, keyed on what the guard means (clickable links) rather than on the field that tripped it: for an Organization node the org profile genuinely is the correct identity, and apps/www's JSON-LD asserts the same URL. A test pins that the exemption stays narrow.

release-cli--latest on release creation. Releases are drafts published by hand and the publish dialog carries its own checkbox, so the flag was a human decision every time. It went wrong once, silently: the sidebar advertised wbhk 0.4.0 as Latest for six days while npm served 0.6.0, which reads to a first-time visitor as an abandoned project. Already corrected on the published release; this stops it recurring.

README — a star ask, a pointer at the good first issue label, and a link to a new CODE_OF_CONDUCT.md (Contributor Covenant 2.1, enforcement at the existing hello@webhook.co).

Shipped outside this PR

Deliberately not shipped

.github/FUNDING.yml. This is a commercial open-core product, not a donation-funded project; a Sponsor button would misrepresent the model, and enabling Sponsors is a financial setup on the founder's account. Cal.com, Dub and Documenso carry no donation button either.

Verification

pnpm lint, pnpm typecheck, pnpm test (29 tasks), pnpm build all exit 0. The repo link is verified present in the built static HTML (apps/www/out/index.html), and docs-nav-guard passes on the real docs.json — with its new check proven to fail on the old value first.

🤖 Generated with Claude Code

https://claude.ai/code/session_016XkxpR5GKp98W5qq2cgsSt


Also here: @webhook-co/webhooks-spec is now publishable (Option B)

The 141-provider signature registry is the most differentiated open-source thing in this repo and the only part of it useful to someone who will never buy the product. It was private: true and unpublished, while the CLI and the SDK were both on npm.

This is not a repo split — that verdict stands (a bare data repo in this category tops out around a dozen stars). Only distribution changes; stars still land here.

The defect this uncovered

The build output did not load. tsc emits the source's extensionless relative specifiers verbatim (from "./scheme"), which TypeScript resolves and Node's ESM loader does not. npm i @webhook-co/webhooks-spec would have thrown ERR_MODULE_NOT_FOUND on the first import, with a green test suite behind it — invisible for as long as the package was private, because all five workspace consumers import src/ and bundle it.

Build is now tsup (dual ESM + CJS + bundled declarations), same as the SDK, for the same reason.

The pnpm/npm trap, and the guard in front of it

Entry points stay on src/ in the committed manifest so those five consumers keep resolving TypeScript; the rewrite to dist/ lives in publishConfig. That replacement is a pnpm feature — npm publish ignores it and would upload TypeScript to the registry. So the release workflow uses pnpm publish, and the packaged smoke test asserts the rewrite actually happened. Switch the publish path to plain npm and the smoke fails instead of shipping.

Verification

scripts/webhooks-spec-packaged-smoke.mjs packs, installs the tarball, imports it via both import and require, and makes it verify a real GitHub signature — plus the negative cases. 17/17 checks pass.

An earlier draft of that test asserted the wrong result shape (status === "verified"); the result is a discriminated union on ok, so undefined !== "verified" made both negative cases vacuous. Fixed, and the comment records why.

Also verified: 141 providers and 141 adapters at runtime from the built ESM (the README's claim, checked rather than asserted), and both README examples executed end to end — sign → verify → wrong-secret rejected.

Publishing

.github/workflows/release-webhooks-spec.yml is tag-triggered (webhooks-spec-vX.Y.Z), gated on a real tag push and NPM_TOKEN, and publishes with OIDC provenance. Nothing is published by merging this PR — the first publish is a deliberate tag push, and the README is the npm landing page, so it's worth an eyeball first.

The repo measured FOUR unique visitors in fourteen days. Nothing on any
surface we own referred anyone to it: the www navigation carried no GitHub
link at all, and the one link in the docs pointed at the ORG page — a repo
list with no star button on it. This is the Tier 0 half of
internal/marketing/github-stars-strategy.md: it does not create demand, it
stops us discarding the demand we already have.

- www nav: a GitHub mark in the desktop bar and a labelled row at the end of
  the phone menu, from a single `REPO_LINK` that is a member of
  ALL_NAV_DESTINATIONS — so the existing mobile-parity guard covers it and the
  two surfaces cannot drift. New nav.test.tsx pins presence, target and a11y.
  No star count: a bar announcing a small number converts a neutral visit into
  a negative one on every page view. That is a decision, and the test says so.

- docs.json: a first-class `{"type":"github"}` navbar link, and
  footer.socials.github moved from the org to the repo.

- docs-nav-guard gains collectRepoLinkIssues(), which WALKS the config rather
  than checking the two fields we know about today — a curated list would only
  ever report on the list. It exempts seo.organization.sameAs, keyed on what
  the guard means (clickable links) rather than on the field that tripped it:
  for an Organization node the org profile IS the correct identity. A test
  pins that the exemption stays narrow.

- release-cli: `--latest` on release creation. Releases are drafts published
  by hand and the publish dialog has its own checkbox, so the flag was a human
  decision every time. It went wrong once, silently: the sidebar advertised
  wbhk 0.4.0 as Latest for six days while npm served 0.6.0. Already corrected
  on the published release; this stops it recurring.

- README: a star ask, a pointer at the good-first-issue label, and a link to a
  new CODE_OF_CONDUCT.md (Contributor Covenant 2.1).

Deliberately NOT shipped: .github/FUNDING.yml. This is a commercial
open-core product, not a donation-funded project, and a Sponsor button would
misrepresent the model.

Gate: lint, typecheck, test (29 tasks), build all green. Repo link verified
present in the built static HTML.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016XkxpR5GKp98W5qq2cgsSt
@mintlify

mintlify Bot commented Jul 24, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
webhook-co 🟢 Ready View Preview Jul 24, 2026, 9:13 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Comment thread scripts/docs-nav-guard.test.mjs Fixed
choraria and others added 3 commits July 24, 2026 10:24
The signature registry is the most differentiated open-source thing this repo
has and the only part of it that is useful to someone who will never buy the
product. It was `private: true` and unpublished, while the CLI and the SDK
were both on npm. This is Option B of internal/marketing/github-stars-strategy.md:
a starrable artifact that needs no self-host path.

It is NOT a repo split — that verdict stands (a bare data repo in this
category tops out around a dozen stars). Distribution changes; stars still
land on webhook-co/webhook.

THE DEFECT THIS UNCOVERED: the build output did not load. `tsc` emits the
source's extensionless relative specifiers verbatim (`from "./scheme"`), which
TypeScript resolves and Node's ESM loader does not — `npm i` then
ERR_MODULE_NOT_FOUND on the first import. Invisible for as long as the package
was private, because all five workspace consumers import `src/` and bundle it.
Build is now tsup (dual ESM + CJS + bundled declarations), same as the SDK,
for the same reason.

Entry points stay on `src/` in the committed manifest so those five consumers
keep resolving TypeScript; the rewrite to `dist/` lives in `publishConfig`.
That replacement is a PNPM feature — `npm publish` ignores it and would upload
TypeScript to the registry — so the release workflow uses `pnpm publish`, and
the packaged smoke test asserts the rewrite actually happened.

- scripts/webhooks-spec-packaged-smoke.mjs: packs, installs the tarball,
  imports it via BOTH `import` and `require`, and makes it verify a real
  GitHub signature — plus the negative cases (wrong secret, tampered body).
  Written after an earlier draft asserted the wrong result shape and made
  those negatives vacuous: the result is a union on `ok`, not a status string.
- .github/workflows/release-webhooks-spec.yml: tag-triggered, gated on a real
  tag push + NPM_TOKEN, publishes with OIDC provenance.
- A package README pitched at someone who has never heard of us, and a
  standalone-library section in the root README.

Verified: 141 providers and 141 adapters at runtime from the built ESM; both
README examples executed and round-tripped (sign → verify → wrong-secret
rejected); 17/17 packaged-artifact checks pass. Full gate green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016XkxpR5GKp98W5qq2cgsSt
The release workflow is tag-triggered, so its packaged smoke would only ever
run at publish time — the point at which finding a broken tarball is most
expensive. This package has already shipped an unloadable dist/ once (tsc
emits extensionless relative specifiers; nothing ever loaded the build because
every workspace consumer imports src/), so the check belongs on every PR,
mirroring the SDK's.

It also pins that the PACKED manifest points at dist/ and not at TypeScript
source. That rewrite comes from publishConfig and is applied by pnpm only;
npm publish ignores it. If the release path is ever switched to plain npm,
this fails instead of TypeScript reaching the registry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016XkxpR5GKp98W5qq2cgsSt
… regex

CodeQL flagged the new end-to-end assertion in docs-nav-guard.test.mjs as
js/regex/missing-regexp-anchor (high): an unanchored /github\.com\/…/ used
against a URL matches anywhere, so arbitrary hosts can straddle it.

The assertion was never validating a URL — it checks that the serialized
navbar CONTAINS the repo link, so the deepEqual above it is not passing
vacuously. Written as a regex it claimed to be doing host matching. A
substring check says what it means and the rule no longer applies.

The guard's own URL matcher is unchanged and was already anchored
(/^https?:\/\/(?:www\.)?github\.com\/…/) — that is where anchoring is
load-bearing, and it is the reason a third-party GitHub URL is correctly
ignored rather than policed.

25/25 guard tests still pass; lint green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016XkxpR5GKp98W5qq2cgsSt
@choraria
choraria marked this pull request as ready for review July 24, 2026 10:00
@choraria
choraria merged commit 8a41084 into main Jul 24, 2026
38 checks passed
@choraria
choraria deleted the tier0-github-stars branch July 24, 2026 10:01
@mintlify

mintlify Bot commented Jul 24, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
webhook-co 🟡 Building Jul 24, 2026, 9:12 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants