Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 2 additions & 14 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ just dev-watch # moq.watch on :5173
# Build & Deploy
just build # Production build of all three sites
just deploy # Deploy all three to Cloudflare (staging by default)
just deploy live # Deploy to production, and email subscribers about new posts
just deploy live # Deploy to production
just prod # Build and preview production locally

# Code Quality
Expand Down Expand Up @@ -109,19 +109,7 @@ The player sites read the repo-root `.env.<env>` files that the Astro site uses,
so `PUBLIC_RELAY_URL` is the single place the relay is configured. Staging is
`new.moq.dev`, `new.moq.pub`, and `new.moq.watch`.

The player sites deploy *before* moq.dev on purpose. Snapshot → moq.dev upload →
announce is effectively a transaction: a failure in the middle leaves posts live
but unannounced, and since the snapshot expires after an hour, a later retry
reads those posts as already-published and never mails them. Keep anything
fallible out from between those three steps.

**`just deploy live` mails the subscriber list.** `scripts/notify-subscribers.ts` snapshots the slugs in `https://moq.dev/rss.xml` before the upload, then sends a Resend broadcast for every post in the freshly built `dist/rss.xml` that wasn't in that snapshot. Subject and body come from the feed's `title` and `description`. A deploy that adds no posts sends nothing.

Credentials come from 1Password, so no secret has to sit on disk. `op.env` maps `RESEND_API_KEY` to `op://Corp/Resend/credential` and `op run` resolves it for the duration of the command. That file is committed on purpose: it holds references, not values. Install and sign in once with `brew install 1password-cli && op signin`.

Without the 1Password CLI the recipe falls back to `RESEND_API_KEY` and `RESEND_SEGMENT_ID` from the ambient environment, and if those are missing too the deploy still succeeds while the script exits non-zero to say the announcement did not go out. `just deploy staging` never announces and never touches 1Password.

Broadcasts cannot be recalled, so the script refuses to guess: an unreachable or empty live feed, a missing snapshot, or a missing build all skip sending rather than risk mailing the back catalogue. Any local `.mdx` under `src/pages/blog/` ships on the next `just deploy live` and gets announced, drafts included.
The player sites deploy before moq.dev.

## Development Tips

Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ just dev-watch # moq.watch, on :5173
## Deploy

`just deploy` builds and uploads all three sites to Cloudflare, staging by
default; `just deploy live` goes to production and mails subscribers about any
new blog posts.
default; `just deploy live` goes to production.

## License

Expand Down
33 changes: 1 addition & 32 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -44,42 +44,11 @@ build mode="live":
bun vite build sites/pub --mode {{mode}}
bun vite build sites/watch --mode {{mode}}

# Deploy all three sites to Cloudflare
# On `live`, any post that wasn't already on moq.dev gets mailed to subscribers.
# Deploy all three sites to Cloudflare.
deploy env="staging": (build env)
# The player sites go first. They're independent of the blog, and the
# snapshot/deploy/announce sequence below is a transaction: a failure between
# the moq.dev upload and the announcement leaves posts live but unannounced,
# and the snapshot expires after an hour, so a later retry sees the new posts
# as already-published and stays silent forever.
bun wrangler deploy --config sites/pub/wrangler.jsonc --env {{env}}
bun wrangler deploy --config sites/watch/wrangler.jsonc --env {{env}}

# Record what's live before we replace it, so we can tell what the deploy added.
bun scripts/notify-subscribers.ts snapshot --env {{env}}
bun wrangler deploy --env {{env}}
just _announce {{env}}

# Mail subscribers about anything this deploy published.
# Credentials come from 1Password (see op.env) so no secret has to live on disk.
[private]
_announce env:
#!/usr/bin/env bash
set -euo pipefail

# Staging never announces, so don't make it depend on 1Password.
if [ "{{env}}" != "live" ]; then
exec bun scripts/notify-subscribers.ts send --env {{env}}
fi

# Fall back to the ambient environment rather than failing outright: the deploy
# has already happened by now, and the script reports a missing key itself.
if ! command -v op >/dev/null 2>&1; then
echo "[notify] 1Password CLI not found, falling back to the ambient environment." >&2
exec bun scripts/notify-subscribers.ts send --env {{env}}
fi

exec op run --env-file=op.env -- bun scripts/notify-subscribers.ts send --env {{env}}

dev:
bun i
Expand Down
14 changes: 0 additions & 14 deletions op.env

This file was deleted.

283 changes: 0 additions & 283 deletions scripts/notify-subscribers.ts

This file was deleted.

Loading
Loading