Skip to content

Consume starpod from npm instead of maintaining a fork - #30

Merged
RobbieTheWagner merged 6 commits into
mainfrom
consume-starpod-npm
Sep 2, 2026
Merged

Consume starpod from npm instead of maintaining a fork#30
RobbieTheWagner merged 6 commits into
mainfrom
consume-starpod-npm

Conversation

@RobbieTheWagner

@RobbieTheWagner RobbieTheWagner commented Sep 2, 2026

Copy link
Copy Markdown
Member

What

Converts this repo from an upstream fork into a consumer of the published starpod npm package (currently ^1.0.1). 138 files changed, +415/−8,507.

The integration now generates the entire core site — episode pages, player, search, transcripts, LLM endpoints, and the Vercel Accept: text/markdown negotiation step (the old scripts/vercel-md-negotiation.mjs build step is gone). What remains here is only whiskey.fm-specific:

  • starpod.config.ts + astro.config.mjs wiring: starpod(starpodConfig, { database: true, components: { InfoCard }, customCss })
  • Sponsor pages with Polar checkout (local AdPackageCard variant with productId), collections pages/lib/data, transcripts, images, db seed data, ATProto publishing scripts
  • InfoCard override (Collections/Store/Sponsor nav links) and src/styles/custom.css via the integration's override options
  • tsconfig/vitest/drizzle now point at node_modules/starpod/src; standalone scripts pass the config explicitly (getAllEpisodes(starpodConfig))
  • Removed the monorepo/release machinery brought in by the sync merge (packages/, workspace file, release-plan, package CI jobs); rewrote README and CLAUDE.md

One consumer-side fix worth noting: Vitest needs an explicit esbuild: { jsx: 'automatic', jsxImportSource: 'preact' } because starpod's .tsx sources resolve inside node_modules, where tsconfig-based JSX detection doesn't reach (the upstream workspace never hits this since its symlink escapes node_modules).

Parity status

All fork parity gaps are closed as of starpod@1.1.0: 1.0.1 restored the site-wide site.standard.publication tag (shipshapecode/starpod#64), and 1.1.0 generalizes breadcrumbs — collection detail pages render Home > Collections > <title> with aria-current and the full BreadcrumbList schema — while dropping the legacy mask-icon/msapplication-TileColor tags upstream, so no color config is needed.

Verification

  • pnpm build (astro check + full production build, markdown-negotiation routes emitted by the integration)
  • 170/170 unit tests, 51/51 Playwright e2e across chromium/firefox/webkit
  • Built output spot-checked: InfoCard override links, collections pages + custom CSS inlined, sponsor checkout links

🤖 Generated with Claude Code

RobbieTheWagner and others added 5 commits August 29, 2026 18:04
* Extract the site engine into a starpod Astro integration package (spike)

Monorepo spike: packages/starpod is now an installable Astro integration
that injects every route, adds the preact/sitemap/tailwind/rehype wiring,
exposes the user's config via virtual:starpod/config, and applies the
Vercel markdown content negotiation in astro:build:done. The root site
consumes it via workspace:*.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Fix type resolution, hook ordering, and renderer resolution in the integration spike

- tsconfig paths + vitest alias so starpod/src/* imports resolve for TS and
  tests (TS does not resolve the exports wildcard the way Vite does)
- Vercel markdown negotiation moves to a process exit handler: the adapter's
  astro:build:done runs after the integration's and rewrites config.json
- @astrojs/preact becomes a direct site dependency: Astro resolves the
  renderer client entrypoint from the project root, so the consumer must
  depend on it (matches how framework renderers are normally installed)
- Tighten the vercel-md-negotiation type declarations to match its tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Production-ready integration: hook-time negotiation, opt-in DB, overrides, bundled assets

- Vercel markdown negotiation now runs inside astro:build:done using the
  hook's own assets map (the adapter writes config.json before user hooks
  but copies static files after them, so the filesystem can't be scanned)
- @astrojs/preact and preact become peerDependencies; the package ships a
  tsconfig.json (nearest-tsconfig JSX settings for installed copies) and
  widens the preset's JSX exclude so starpod's own .tsx transforms when it
  lives in node_modules
- starpod(config, options): options.database gates the Drizzle/Turso
  guests+sponsors layer (default off; sections simply don't render),
  options.components overrides built-ins via virtual modules, and
  options.customCss loads site stylesheets after the built-in ones
- Engine assets (player icons, platform logos, dots, avatars) move into the
  package and are bundled by Vite instead of expected in consumer public/;
  host/guest/sponsor image lookups fall back gracefully when a site has not
  provided photos yet
- Normalize rss-to-json's dual CJS interop shape (externalized vs bundled)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Add create-starpod scaffolder

npm create starpod: prompts for name/RSS/database (or flags --name --rss
--database --yes) and generates a ready-to-build consumer project: renderer
deps declared directly, tsconfig with starpod/src/* paths for tests, content
config, .env.example, optional db/ folder with empty data files, seed script,
and drizzle config, plus the fast-xml-parser pin and sharp that real feeds
need. Smoke-tested against the local package with a component override and
customCss.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Fold the scaffolder into the starpod package as a CLI

Drops the separate create-starpod package: the starpod package now ships a
bin, so `npx starpod new my-podcast` scaffolds a project with the same
prompts and flags. One published package instead of two; the trade-off is
losing the `npm create starpod` alias, which requires a package named
create-starpod.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* De-Whiskey the engine: custom sponsor pages, config nav links, config-driven host order

The sponsor page is no longer part of the engine — sponsorship pitches are
bespoke marketing, so a consumer who wants one adds a normal Astro page to
their own src/pages/ built from the package's exported Layout and
components. whiskey.fm's page moves back into the site as the reference
implementation, and the scaffolded README documents the pattern.

- New optional `links` config renders extra nav entries after About and
  Contact (replaces the hardcoded whiskey.fund Store link)
- CreatorsAndGuests sorts configured hosts first in config order instead of
  a hardcoded name list (past hosts recorded in the database follow, then
  guests alphabetically — old whiskey.fm episodes may order Chuck after
  Adam now)
- AdPackageCard stays in the package as a generic building block

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Validate the Starpod config and fail helpfully without one

defineStarpodConfig now parses the config with valibot and throws a single
readable error listing every problem with its field path; the integration
validates too, so configs that skip the helper are still checked. Calling
starpod() with no config — what `astro add starpod` generates — throws
setup instructions instead of crashing mid-build.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Bless a stable export surface for custom pages

starpod/layout, starpod/components/AdPackageCard, and starpod/rss are the
supported imports for site-authored pages (the reference sponsor page and
scaffolded README now use them). starpod/src/* remains available for tests
but is internal API with no stability guarantees.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Document the integration model: package README and repo README rewrite

The package README is the npm landing page: quickstart for new and existing
projects, config reference, integration options, custom pages, transcripts,
database setup, and the API stability policy (src/* is internal; the blessed
subpath exports are the stable surface). The repo README keeps its ATProto
and LLM discovery docs but replaces the fork-model getting-started with the
integration story and documents the workspace layout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Add CI scaffold smoke test and npm release workflow

The scaffold job builds a freshly generated consumer project against the
local package on every push — covering the installed-from-npm code path
(node_modules JSX transform, CJS interop, bundled assets, dependency pins)
that the workspace build can't see, and asserting the agent endpoints and
negotiation routes exist in the output. The release workflow publishes
starpod to npm with provenance on a starpod@* tag or manual dispatch; it
needs an NPM_TOKEN repository secret.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Publish via npm OIDC trusted publishing instead of a token secret

npm handles the OIDC exchange natively (id-token: write stays; the
workflow upgrades npm since Node 22 bundles 10.x and trusted publishing
needs 11.5.1+), and provenance comes automatically with trusted-publisher
releases. Requires the one-time trusted publisher setup on npmjs.com.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Set up release-plan for automated releases

Generated by create-release-plan-setup: plan-release.yml opens and updates
a Prepare Release PR (changelog + .release-plan.json) from labeled PRs, and
publish.yml releases to npm via OIDC trusted publishing with provenance
when that PR merges — no token secret. Replaces the hand-rolled tag-based
release workflow. RELEASE.md documents the flow; every merged PR needs one
of the changelog labels.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
# Conflicts:
#	package.json
#	packages/starpod/src/lib/collections.ts
#	packages/starpod/src/lib/topic-keywords.ts
#	packages/starpod/src/pages/api/checkout.ts
#	pnpm-lock.yaml
#	tsconfig.json
…test

The workspace repo resolves starpod's .tsx files outside node_modules where
the tsconfig JSX settings apply; installed from npm they resolve inside
node_modules, so the transform must be configured explicitly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
starpod@1.0.1's Layout restores the site-wide
<link rel="site.standard.publication"> tag (gated on STANDARD_SITE_DID
and STANDARD_SITE_PUBLICATION_RKEY) that the forked Layout emitted
before converting to the npm package.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
www-starpod Building Building Preview Sep 2, 2026 6:27pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 112 files, which is 12 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: f3f32d75-ad11-43ec-8b7e-8ce8bbd37539

📥 Commits

Reviewing files that changed from the base of the PR and between 8329cd2 and 3e368a6.

⛔ Files ignored due to path filters (26)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • public/images/apple.svg is excluded by !**/*.svg
  • public/images/dots-dark.svg is excluded by !**/*.svg
  • public/images/dots-light.svg is excluded by !**/*.svg
  • public/images/forward-icon.svg is excluded by !**/*.svg
  • public/images/mute-icon.svg is excluded by !**/*.svg
  • public/images/overcast.svg is excluded by !**/*.svg
  • public/images/pocket-casts.svg is excluded by !**/*.svg
  • public/images/rewind-icon.svg is excluded by !**/*.svg
  • public/images/rocket-dark.svg is excluded by !**/*.svg
  • public/images/rocket-light.svg is excluded by !**/*.svg
  • public/images/search-icon.svg is excluded by !**/*.svg
  • public/images/spotify.svg is excluded by !**/*.svg
  • public/images/unmute-icon.svg is excluded by !**/*.svg
  • public/images/youtube.svg is excluded by !**/*.svg
  • src/img/people/avatar-dark.png is excluded by !**/*.png
  • src/img/people/avatar-light.png is excluded by !**/*.png
  • src/svgs/404-dark.svg is excluded by !**/*.svg
  • src/svgs/404-light.svg is excluded by !**/*.svg
  • src/svgs/apple.svg is excluded by !**/*.svg
  • src/svgs/overcast.svg is excluded by !**/*.svg
  • src/svgs/pocket-casts.svg is excluded by !**/*.svg
  • src/svgs/spotify.svg is excluded by !**/*.svg
  • src/svgs/ufo-dark.svg is excluded by !**/*.svg
  • src/svgs/ufo-light.svg is excluded by !**/*.svg
  • src/svgs/youtube.svg is excluded by !**/*.svg
📒 Files selected for processing (112)
  • CLAUDE.md
  • README.md
  • astro.config.mjs
  • db/index.ts
  • db/schema.ts
  • db/seed.ts
  • drizzle.config.ts
  • package.json
  • playwright.worktree.config.ts
  • scripts/analyze-transcripts.ts
  • scripts/publish-atproto-episodes.ts
  • scripts/vercel-md-negotiation.mjs
  • src/components/AdPackageCard.astro
  • src/components/Breadcrumbs.astro
  • src/components/ContactForm.tsx
  • src/components/Dots.astro
  • src/components/EpisodeList.astro
  • src/components/FormattedDate.tsx
  • src/components/FullPlayButton.tsx
  • src/components/Hosts.astro
  • src/components/LargePlatforms.astro
  • src/components/NotFoundContent.astro
  • src/components/Platforms.astro
  • src/components/Player.tsx
  • src/components/SearchButton.tsx
  • src/components/SearchDialog.tsx
  • src/components/ShowArtwork.astro
  • src/components/episode/CreatorsAndGuests.astro
  • src/components/episode/MarkdownTranscript.tsx
  • src/components/episode/Sponsors.astro
  • src/components/episode/Transcript.tsx
  • src/components/illustrations/404Illustration.astro
  • src/components/illustrations/UFOIllustration.astro
  • src/components/player/ForwardButton/index.tsx
  • src/components/player/ForwardButton/styles.css
  • src/components/player/MuteButton/index.tsx
  • src/components/player/MuteButton/styles.css
  • src/components/player/PlayButton.tsx
  • src/components/player/PlaybackRateButton.tsx
  • src/components/player/RewindButton/index.tsx
  • src/components/player/RewindButton/styles.css
  • src/components/player/Slider/index.tsx
  • src/components/player/Slider/styles.css
  • src/components/state.ts
  • src/content.config.ts
  • src/content/config.ts
  • src/layouts/Layout.astro
  • src/lib/api-errors.ts
  • src/lib/collections.ts
  • src/lib/llms.ts
  • src/lib/not-found.ts
  • src/lib/openapi.ts
  • src/lib/optimize-episode-image.ts
  • src/lib/rehype-transcript-timestamps.mjs
  • src/lib/rss.ts
  • src/lib/standardSite.ts
  • src/lib/transcript.ts
  • src/pages/.well-known/site.standard.publication.ts
  • src/pages/404.astro
  • src/pages/[...notFound].astro
  • src/pages/[episode].astro
  • src/pages/[episode].html.md.ts
  • src/pages/about.astro
  • src/pages/about.html.md.ts
  • src/pages/api/contact.ts
  • src/pages/api/episodes/[page].json.ts
  • src/pages/api/episodes/search.json.ts
  • src/pages/collections/[slug].astro
  • src/pages/collections/index.astro
  • src/pages/contact.astro
  • src/pages/contact.html.md.ts
  • src/pages/episodes-index.html.md.ts
  • src/pages/for-llms.astro
  • src/pages/for-llms.html.md.ts
  • src/pages/index.astro
  • src/pages/index.html.md.ts
  • src/pages/llms.txt.ts
  • src/pages/openapi.json.ts
  • src/pages/robots.txt.ts
  • src/pages/sponsor.astro
  • src/pages/sponsor/success.astro
  • src/styles/buttons.css
  • src/styles/custom.css
  • src/styles/global.css
  • src/styles/gradient-icon.css
  • src/styles/search-icon.css
  • src/styles/tailwind.css
  • src/utils/config.ts
  • src/utils/dasherize.ts
  • src/utils/truncate.ts
  • starpod.config.ts
  • tests/unit/ForwardButton.test.tsx
  • tests/unit/FullPlayButton.test.tsx
  • tests/unit/MuteButton.test.tsx
  • tests/unit/PlayButton.test.tsx
  • tests/unit/PlaybackRateButton.test.tsx
  • tests/unit/Player.test.tsx
  • tests/unit/RewindButton.test.tsx
  • tests/unit/SearchButton.test.tsx
  • tests/unit/SearchDialog.test.tsx
  • tests/unit/Slider.test.tsx
  • tests/unit/config.test.ts
  • tests/unit/contact-api.test.ts
  • tests/unit/llms.test.ts
  • tests/unit/not-found.test.ts
  • tests/unit/openapi.test.ts
  • tests/unit/rehype-transcript-timestamps.test.ts
  • tests/unit/robots.test.ts
  • tests/unit/transcript.test.ts
  • tests/unit/vercel-md-negotiation.test.ts
  • tsconfig.json
  • vitest.config.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Collection detail pages get their linked Collections middle crumb back
(with aria-current and the full BreadcrumbList schema), and the legacy
mask-icon/msapplication-TileColor tags are gone upstream, closing the last
parity gaps from the fork conversion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@RobbieTheWagner
RobbieTheWagner merged commit c9b95ed into main Sep 2, 2026
6 checks passed
@RobbieTheWagner
RobbieTheWagner deleted the consume-starpod-npm branch September 2, 2026 19:03
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.

1 participant