Conversation
Mounts Keystatic at /keystatic via keystatic-sveltekit. Storage is local in dev, GitHub (PR per save, branchPrefix cms/) in prod. Schema mirrors the existing zod metadataSchema; categories list is duplicated because the config file is loaded raw by Node at Vite startup. Setup, env vars, and the GitHub App config are in docs/BLOG_CMS.md.
Each post's cover + body images move to static/assets/blog-images/<slug>/, author avatars move to .../authors/<id>/. Single-string authors become arrays so the Keystatic schema can use a single fields.array(fields.relationship). Reader already handles both shapes via z.union, so existing posts keep rendering unchanged.
CMS routes 404 on alt-chain deployments — same convention the blog uses for redirecting to drips.network/blog.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR integrates the Keystatic CMS into the SvelteKit app (served at /keystatic) so marketing can manage blog content via a git-based workflow: local file edits in dev and GitHub-backed PR creation in production. It also migrates existing blog posts and static assets into Keystatic’s per-slug directory layout, with minimal reader/schema changes to keep existing rendering working.
Changes:
- Add Keystatic integration (Vite plugin + SvelteKit
handle) and a repo-rootkeystatic.config.ts. - Update blog metadata parsing to tolerate YAML-parsed
Datevalues and normalize authors to arrays. - Migrate blog posts and images into Keystatic-friendly directory structure; add CMS setup docs.
Reviewed changes
Copilot reviewed 38 out of 104 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| vite.config.ts | Registers the Keystatic Vite plugin and adjusts dev server host behavior for Keystatic UI redirects. |
| static/assets/blog-images/scroll-argentinia-hackathon/collab-drip-list-hiw.png | Adds migrated blog image asset under per-post directory. |
| static/assets/blog-images/ens-funds-its-critical-open-source-dependencies/ens-2.png | Adds migrated blog image asset under per-post directory. |
| static/assets/blog-images/dependency-funding-with-drips/how-drip-lists-work.png | Adds migrated blog image asset under per-post directory. |
| static/assets/blog-images/authors/jason/avatarUrl.png | Adds migrated author avatar asset under per-author directory. |
| src/routes/api/blog/posts/schema.ts | Normalizes date values so YAML Date objects are accepted as strings. |
| src/hooks.server.ts | Adds Keystatic request handling and guards CMS routes on alt-chain deployments. |
| src/blog-posts/wave-4-changelog.md | Migrates frontmatter formatting and image paths to per-slug layout. |
| src/blog-posts/wave-3-changelog.md | Updates cover image path and normalizes author to array. |
| src/blog-posts/wave-2-changelog.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/the-monthly-wave.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/scroll-argentinia-hackathon.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/rpgf-launch-with-filecoin.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/radworks-gives-1m-to-foss-dependencies-with-drips.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/q4-2025-roundup.md | Updates cover image path and normalizes author to array. |
| src/blog-posts/q4-2024-feature-roundup.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/q2-2025-roundup.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/q1-2026-roundup.md | Updates cover image path and normalizes author to array. |
| src/blog-posts/q1-2025-roundup.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/open-source-collective.md | Updates cover image path and normalizes author to array. |
| src/blog-posts/octant-teams-up-with-drips-to-fund-its-dependencies.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/introducing-collaborative-drip-lists.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/full-rpgf-on-drips.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/exploring-sustainable-funding-for-digital-public-goods-with-unicef.md | Updates cover image path and normalizes author to array. |
| src/blog-posts/ens-funds-its-critical-open-source-dependencies.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/drips-web3privacynow.md | Updates cover image path and normalizes author to array. |
| src/blog-posts/drips-wave-whats-launching-in-january.md | Updates cover image path and normalizes author to array. |
| src/blog-posts/devcon-devconnect-support-their-dependencies-with-drips.md | Updates cover image path and normalizes author to array. |
| src/blog-posts/dependency-funding-with-drips.md | Updates cover/body image paths and normalizes author to array. |
| src/blog-posts/creating-meaningful-issues.md | Updates cover image path and normalizes author to array. |
| src/blog-posts/berlin-blockchain-week-guide.md | Updates cover image path and normalizes author to array. |
| src/blog-posts/authors/ugo-x.json | Updates author avatar path to per-author directory layout. |
| src/blog-posts/authors/kat.json | Updates author avatar path to per-author directory layout. |
| src/blog-posts/authors/jason.json | Updates author avatar path to per-author directory layout. |
| src/blog-posts/authors/ele.json | Updates author avatar path to per-author directory layout. |
| src/blog-posts/authors/becca.json | Updates author avatar path to per-author directory layout. |
| src/blog-posts/amplifying-the-impact-of-funding.md | Updates cover image path and normalizes author to array. |
| scripts/migrate-blog-images.mjs | Adds one-off script to migrate images into Keystatic’s expected layout and rewrite refs. |
| README.md | Documents the new /keystatic CMS entrypoint and links to setup guide. |
| package.json | Adds Keystatic/React deps and sets NODE_OPTIONS=--experimental-strip-types for dev/build. |
| keystatic.config.ts | Defines Keystatic collections/schema and dev vs prod storage selection. |
| docs/BLOG_CMS.md | Adds CMS setup/workflow documentation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds Keystatic at
/keystaticso marketing can publish blog posts on their own. Local storage in dev (saves direct to working tree), GitHub storage in prod (each save → branchcms/...→ PR againstmain).Schema in
keystatic.config.tsmirrors the existing zodmetadataSchema. Existing posts and images are migrated into the per-slug directory layout Keystatic uses; reader changes are limited to (a) toleratingDateobjects fordate(YAML auto-parses unquotedYYYY-MM-DD) and (b) no-op for authors since the zod schema already acceptsstring | string[].Detailed setup is in
docs/BLOG_CMS.md.GitHub App setup (one-time, for prod)
The CMS UI walks you through this if you just visit
https://<deployed>/keystaticwhile logged in to GitHub as adrips-network/appadmin:/keystaticon the deployed app, click Set up Keystatic with GitHub.Drips Blog CMS), accept the suggested permissions, install the app ondrips-network/apponly.drips-network/app(collaborator role is enough; no other GH perms needed). They sign in to/keystaticwith their GitHub account.If you'd rather create the app manually, the required perms are: Contents R/W, Metadata R, Pull requests R/W. Callback URL is
https://<host>/api/keystatic/github/oauth/callback, setup URL ishttps://<host>/keystatic/setup.Known follow-ups (in docs)
<BlogVideoPlayer />etc.) aren't editable as CMS blocks. The editor shows them as raw text. Proper block support needs migrating the renderer frommdsvextomarkdoc-svelte— separate PR.Notes for review
package.jsondevandbuild:appscripts now haveNODE_OPTIONS=--experimental-strip-types. Required because the keystatic-sveltekit Vite plugin loadskeystatic.config.tsvia raw Nodeimport(), not via Vite's transform.BLOG_CATEGORY_OPTIONSis intentionally duplicated betweenkeystatic.config.tsandsrc/routes/api/blog/posts/schema.ts— keep them in sync.isDevcheck inkeystatic.config.tsuseswindow.location.hostnamebecause the CMS UI bundle is built by rolldown (not Vite), and rolldown doesn't injectimport.meta.env.DEV. Comment in the file explains.scripts/migrate-blog-images.mjsis a one-off; safe to delete after merge if you don't want it kicking around.Test plan
npm install,npm run dev, openhttp://127.0.0.1:5173/keystatic— admin loads without GitHub prompt/blogand a few post detail pages still render correctly with the migrated frontmatter + image paths.mdfile updates in the working tree