Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
0a8d1e2
feat(demo-app): add demo.sonicjs.com app with auto-reseed
lane711 Jul 1, 2026
4c75d45
test(demo-app): real-DB reseed integration test + fix ensureTypes source
lane711 Jul 1, 2026
cc2bb53
Merge remote-tracking branch 'origin/main' into lane711/demo-app-seed…
lane711 Jul 2, 2026
a35e3ce
feat(demo-app): wire real D1/KV IDs into wrangler.toml
lane711 Jul 2, 2026
dc31577
fix(demo-app): set BETTER_AUTH_URL to custom domain
lane711 Jul 2, 2026
6fdb889
feat(demo-app): static login cache, media plugin, blog hero images, R…
lane711 Jul 6, 2026
04c1647
feat(deploy): upload blog hero images to R2 on every deploy
lane711 Jul 6, 2026
8c978a4
fix(deploy): add --remote flag to wrangler r2 object put
lane711 Jul 6, 2026
45fcfc4
feat(media): set core-media defaultActive so it auto-installs on boot…
lane711 Jul 6, 2026
e39a33f
chore: sync package-lock.json with demo-app workspace
lane711 Jul 6, 2026
84c77d8
fix(ci): regenerate lock file with npm 10 so npm ci passes
lane711 Jul 6, 2026
d9282f6
fix(ci): add cross-platform rollup binaries to lock file
lane711 Jul 6, 2026
5817a99
fix(tests): correct pre-existing test failures from versioning=false …
lane711 Jul 6, 2026
742988d
fix(tests): quarantine email-plugin tests + versioning=true for blog_…
lane711 Jul 6, 2026
bda31b9
chore: merge origin/main into demo-app-seed-plan
lane711 Jul 7, 2026
298198c
fix(tests): fix admin-layout-catalyst and admin-users-profile regress…
lane711 Jul 7, 2026
a299377
chore: merge origin/main, resolve admin-layout-catalyst test conflict
lane711 Jul 7, 2026
1066e6b
chore: merge origin/main, resolve admin-users-profile test conflict
lane711 Jul 7, 2026
6302156
fix(ci): guard HEAD~1 fallback in E2E tag-detection step
lane711 Jul 7, 2026
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
112 changes: 112 additions & 0 deletions .github/workflows/deploy-demo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Deploy Demo

# demo.sonicjs.com always runs the latest main. Every push to main redeploys the
# demo worker and resets its data (full wipe + reseed) so the public demo always
# reflects the newest build with a known dataset.
on:
push:
branches:
- main
paths:
- 'demo-app/**'
- 'packages/core/src/**'
- 'packages/core/migrations/**'
- 'www/public/images/blog/**'
- '.github/workflows/deploy-demo.yml'
workflow_dispatch:

jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 25

env:
DEMO_BASE_URL: https://demo.sonicjs.com

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build core package
run: npm run build:core

- name: Type check demo app
run: npm run type-check --workspace=demo-app

- name: Test demo app (reseed integration)
run: npm test --workspace=demo-app

- name: Apply D1 migrations
run: cd demo-app && npx wrangler d1 migrations apply DB --remote
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

- name: Deploy demo to Cloudflare Workers
run: cd demo-app && npx wrangler deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

- name: Upload blog hero images to R2
# Uploads all www/public/images/blog/<slug>/hero.png files to R2 under
# blog/<slug>/hero.png. Idempotent — re-uploads on every deploy so the
# bucket stays in sync if images are added or replaced. Runs before reseed
# so mediaSvc.createFromUpload finds the objects already in R2.
run: |
cd demo-app
for slug_dir in ../www/public/images/blog/*/; do
slug=$(basename "$slug_dir")
src="../www/public/images/blog/$slug/hero.png"
[ -f "$src" ] || continue
echo "Uploading blog/$slug/hero.png ..."
npx wrangler r2 object put sonicjs-demo-media/blog/$slug/hero.png \
--file="$src" \
--content-type=image/png \
--remote
done
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

- name: Wait for deployment to be live
run: |
echo "Polling $DEMO_BASE_URL/auth/login ..."
for i in $(seq 1 30); do
code=$(curl -s -o /dev/null -w "%{http_code}" "$DEMO_BASE_URL/auth/login" || true)
if [ "$code" = "200" ]; then
echo "Demo is live (HTTP $code)."
exit 0
fi
echo "Attempt $i: HTTP $code — retrying in 5s"
sleep 5
done
echo "Demo did not become healthy in time."
exit 1

- name: Seed admin user (idempotent)
run: |
curl -fsS -X POST "$DEMO_BASE_URL/auth/seed-admin" -o /dev/null \
&& echo "Admin seeded." \
|| echo "Admin seed returned non-zero (may already exist) — continuing."

- name: Reseed demo data (full wipe + rebuild)
run: |
status=$(curl -s -o /tmp/reseed.json -w "%{http_code}" \
-X POST "$DEMO_BASE_URL/__demo/reseed" \
-H "Authorization: Bearer ${DEMO_SEED_TOKEN}")
echo "Reseed HTTP $status"
cat /tmp/reseed.json || true
echo
test "$status" = "200"
env:
DEMO_SEED_TOKEN: ${{ secrets.DEMO_SEED_TOKEN }}
2 changes: 1 addition & 1 deletion .github/workflows/pr-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ jobs:
run: |
# Get changed files vs base branch (PR diff) or last commit (push)
if [ "${{ github.event_name }}" = "pull_request_target" ]; then
CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...${{ github.event.pull_request.head.sha }} 2>/dev/null || git diff --name-only HEAD~1)
CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...${{ github.event.pull_request.head.sha }} 2>/dev/null || git diff --name-only HEAD~1 2>/dev/null || echo "")
else
CHANGED=$(git diff --name-only HEAD~1 2>/dev/null || echo "")
fi
Expand Down
16 changes: 16 additions & 0 deletions demo-app/.dev.vars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copy to .dev.vars and fill in real values. .dev.vars is gitignored.
# Wrangler loads this file for `wrangler dev` (local dev only).
#
# Required: BETTER_AUTH_SECRET must be >= 16 chars. Auth init refuses to
# start without it and login returns 500.
#
# Generate a strong random secret:
# openssl rand -hex 32
BETTER_AUTH_SECRET="replace-me-with-32-bytes-of-hex"

# Bearer token guarding POST /__demo/reseed. The deploy workflow sends it as
# `Authorization: Bearer <token>`. Any non-empty value works for local dev.
DEMO_SEED_TOKEN="replace-me-with-a-random-token"

# Optional: set if Better Auth can't detect the base URL.
# BETTER_AUTH_URL="http://localhost:8787"
40 changes: 40 additions & 0 deletions demo-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Dependencies
node_modules/
.pnpm-store/

# Build outputs
dist/
.wrangler/
.mf/

# Environment files
.env
.env.local
.env.*.local
.dev.vars

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db

# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# Test coverage
coverage/
.nyc_output/

# Temporary files
tmp/
temp/
99 changes: 99 additions & 0 deletions demo-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# SonicJS Demo App — demo.sonicjs.com

The public demo. It **always runs the latest `main`** and **resets its data on
every deploy and every 2 hours**, so visitors can freely edit content, upload
media, and explore the admin without permanently changing anything.

## What it includes

- **4 example collections** (code-defined, no DB tables): `blog_post`, `page`,
`testimonial`, `faq`.
- **Sample content + images** — seeded blog posts, pages, testimonials, FAQs,
and SVG media assets uploaded to R2.
- **Demo-login prefill** — the login page is pre-filled with
`admin@sonicjs.com` / `sonicjs!` (the `demo-login` plugin, gated to this app).
- **Reset machinery** — the `demo-seed` plugin exposes `POST /__demo/reseed`
and a `0 */2 * * *` cron; both run the same `runReseed` (full wipe + rebuild).

## How the reset works

`runReseed(env)` (`src/plugins/demo-seed/reseed.ts`):

1. Counts, then deletes **every** document for tenant `default` plus its derived
facet / reference / permission rows.
2. Purges the `demo-seed/` prefix in R2.
3. Upserts the seed document types (defensive FK guard).
4. Uploads the bundled SVG images to R2 and registers `media_asset` documents.
5. Recreates the 4 collections' sample content (published-on-create).
6. Re-activates the demo-login prefill.

`document_types` and Better-Auth users are **not** documents, so they survive a
reset — the admin user is seeded once at deploy time via `/auth/seed-admin`.

Both triggers are **hard-gated to `ENVIRONMENT === 'demo'`**; the HTTP route also
requires `Authorization: Bearer $DEMO_SEED_TOKEN`. This app can never wipe a
non-demo install.

## One-time Cloudflare setup (operator)

Provision the dedicated resources and paste their ids into `wrangler.toml`
(placeholders marked `REPLACE_WITH_...`):

```bash
cd demo-app

# D1
npx wrangler d1 create sonicjs-demo
# → paste database_id into [[d1_databases]]

# R2
npx wrangler r2 bucket create sonicjs-demo-media

# KV
npx wrangler kv namespace create sonicjs-demo-cache
# → paste id into [[kv_namespaces]]

# Secrets
openssl rand -hex 32 | npx wrangler secret put BETTER_AUTH_SECRET
npx wrangler secret put DEMO_SEED_TOKEN # random token; also add as a GH Actions secret
```

DNS: point `demo.sonicjs.com` at this worker (the `sonicjs.com` zone is on the
same Cloudflare account, so the `custom_domain` route in `wrangler.toml` binds
directly).

GitHub Actions secrets required by `.github/workflows/deploy-demo.yml`:
`CLOUDFLARE_API_TOKEN`, `CLOUDFLARE_ACCOUNT_ID`, `DEMO_SEED_TOKEN`.

## Local development

```bash
# from repo root — build core first (the demo imports @sonicjs-cms/core)
npm run build:core

cd demo-app
cp .dev.vars.example .dev.vars # set BETTER_AUTH_SECRET + DEMO_SEED_TOKEN
npm run db:migrate:local # apply 0001 + 0002 to local D1
npm run seed:demo # full wipe + reseed local data (same runReseed)
npm run dev # wrangler dev
```

## Deploy

Automatic on every push to `main` (see `.github/workflows/deploy-demo.yml`):
build core → type-check → migrate → deploy → seed admin → reseed.

Manual:

```bash
npm run deploy:demo # from repo root (builds core, deploys demo-app)
# then, against the live site:
curl -X POST https://demo.sonicjs.com/__demo/reseed \
-H "Authorization: Bearer $DEMO_SEED_TOKEN"
```

## E2E

`tests/e2e/82-demo-seed.spec.ts` — runs only when `DEMO_BASE_URL` is set
(skipped in the normal suite). Validates credential prefill, seeded public
content, and reseed-endpoint auth.
Loading
Loading