Components Seeds Pipeline (Phase 2 closed)

Clean local path for first-gen seeds and shipping them into Netlify Blobs. Runtime Export / Preview / regenerate never write seeds via Gemini; they only read Blobs.

Related:

Mental model

Step Where Command
1. Generate seed TSX Local (public/components/code/) publish:content → build:artifacts / build:components
2. Upload seed to Blobs Local → Netlify CLI → Blobs publish:content → components:seeds:upload
3. Runtime Netlify Blobs Export / Preview / Reimagine / Fix

Default publish path: npm run publish:content runs generation and uploads new seeds (existing Blobs seeds are skipped). Use the standalone upload command only for targeted/ops recovery.

  • Default upload uses Netlify CLI (netlify login + netlify link) — same approach as meta enrich.
  • Seeds are immutable by default. Existing Blobs seeds are skipped (seed_exists). Overwrite a specific seed with --ids=<id> --force (keeps regenerate vN). --force-all replaces every matched seed and is dangerous.
  • Regenerates (vN) are click-only on /debug and do not replace seed / v0.
  • Debug Publish to Blobs (localhost row menu, signed in) can bootstrap a missing seed or append a local regenerate/rebuild as a new active Blobs vN. Same immutability: existing seeds are skipped.
  • out/components/code is stripped on publish. Do not rely on the live site serving TSX.

Prerequisites (once per machine)

netlify login
netlify link   # selects the PATTTTERNS site; writes .netlify/state.json

Or set NETLIFY_AUTH_TOKEN + NETLIFY_SITE_ID.

One-liner recipes

Full publish (new patterns included)

# search → content/shell → artifacts → upload new seeds to Blobs
npm run publish:content
# then commit public/search-index.json, .notion-cache/, components/code + status/metadata/manifest
# (not _*-report.json or seeds-manifest.json — those are gitignored)

New or rebuilt seed for one pattern

# 1) Gemini first-gen → public/components/code/<id>.tsx
npm run build:components -- --ids=<patternId> --force

# 2) Ship into Blobs via Netlify CLI (no Supabase token)
npm run components:seeds:upload -- --ids=<patternId>
# Replace an existing Blobs seed (keeps vN regenerates):
npm run components:seeds:upload -- --ids=<patternId> --force

Full local cache → Blobs bootstrap

npm run build:components -- --force   # or use existing code/ files
npm run components:seeds:upload

Manifest only (no upload)

npm run components:seeds:manifest
npm run components:seeds:manifest -- --ids=<id[,id…]>

Dry-run upload plan

npm run components:seeds:upload -- --dry-run
npm run components:seeds:upload -- --ids=<id> --dry-run
npm run components:seeds:upload -- --ids=<id> --force --dry-run

Optional: upload via Components API instead

export COMPONENTS_MIGRATE_TOKEN=<supabase-access-token>
export COMPONENTS_API_BASE=https://patttterns.com/.netlify/functions/components-api
npm run components:seeds:upload -- --via-api --ids=<patternId>

npm scripts

Script What it does
build:components Gemini first-gen into public/components/code/
build:components:dry Dry-run first-gen
components:seeds:manifest Write public/components/seeds-manifest.json (local, gitignored)
components:seeds:upload Manifest + write seeds to Blobs (Netlify CLI by default)
components:seeds:enrich Backfill title/slug/cover on existing Blobs meta (Netlify CLI)
strip:components-out Remove out/components/code + history after next build (also part of npm run build)

Environment

Var Required Purpose
Netlify CLI auth Upload (default) netlify login + netlify link, or NETLIFY_AUTH_TOKEN + NETLIFY_SITE_ID
COMPONENTS_MIGRATE_TOKEN Only with --via-api Supabase access token for op=put-seed
COMPONENTS_API_BASE Only with --via-api Function base URL
COMPONENTS_SEEDS_BASE_URL Optional / transitional Function may still fetch /components/code/{id}.tsx when Blobs seed is missing
GEMINI_API_KEY First-gen only build:components
COMPONENTS_STRIP_OUT Optional Set 0 to skip publish strip (escape hatch)

Upload behavior (Netlify CLI)

  • Reads public/components/code/*.tsx (optionally filtered by --ids=).
  • Attaches title / slug / coverImage from public/search-index.json when present.
  • Writes Blobs keys:
    • code/<id>/seed.tsx
    • meta/<id>.json (index with immutable seed version)
  • Already has seed → SKIP (seed_exists) unless --force / --force-all
  • Created → OK
  • Replaced → OVERWRITE (seed blob + seed meta row only; vN kept; active version unchanged)
  • Error → FAIL; process exits non-zero if any fail
  • --force requires --ids=<id[,id…]>. --force-all overwrites every matched seed (prints a warning).

Replacing a bad seed

npm run build:components -- --ids=<id> --force --promote=all
npm run components:seeds:upload -- --ids=<id> --force

That overwrites code/<id>/seed.tsx and the seed row in meta/<id>.json. Regenerates (vN) stay. Active version is not flipped back to seed — switch it in /debug if preview should show the new seed.

Manual Blobs deletes are no longer required. Avoid deleting meta/<id>.json unless you intend to drop the version index.

Phase 2 close checklist

  • Production loads TSX from Components API (not published out/ TSX)
  • Postbuild strips out/components/code + history
  • Local first-gen + Netlify CLI Blobs upload documented above
  • publish:content uploads new seeds to Blobs (no extra step for brand-new patterns)
  • Ops: run a full (or filtered) components:seeds:upload against the linked prod site once for any seeds created before this wire-up

After that bootstrap upload (if needed), Phase 2 ops is complete. Ongoing: npm run publish:content covers generate + Blobs for new seeds.