ReeWeb Publisher Signal
The publisher signal is a Reepolee middleware that automatically pings a ReeWeb Publisher instance after every successful content mutation. When an editor saves a record in the Reepolee admin panel — creates, updates, or deletes — the middleware fires a fire-and-forget POST to the Publisher's signal endpoint, which triggers a static-site rebuild. No cron job, no manual deploy, no polling.
The result is a hands-off content pipeline: Reepolee holds the data → editors make changes → Reepolee signals the Publisher → the Publisher re-renders the static site → you review and deploy.
How It Works
Two pieces in lib/publisher_signal/index.ts:
send_publisher_signal()— sends a singlePOSTto the Publisher's signal endpoint.publisher_signal_mw()— a middleware wrapper that callssend_publisher_signal()after every successful mutation.
send_publisher_signal()
async function send_publisher_signal(
publisher_url?: string,
fetcher?: PublisherFetch,
): Promise<void>;
Reads REEWEB_PUBLISHER_URL from the environment, sends a POST with a 1-second timeout, and catches all errors silently (logs a warning). If the env var is unset, it returns immediately — no signal is sent.
| Behaviour | Detail |
|---|---|
| Env var | REEWEB_PUBLISHER_URL |
| Method | POST |
| Timeout | 1 second |
| On failure | Logs [publisher] Render signal failed: <message> |
| On success | Silent — the Publisher acknowledged the signal |
| When URL is unset | Silent skip — no signal, no warning |
The signal is fire-and-forget. If the Publisher is down, restarting, or unreachable, the user's mutation completes normally and Reepolee logs a warning. The user's request is never delayed by the signal.
publisher_signal_mw()
function publisher_signal_mw(
send_signal?: () => Promise<void>,
): Middleware;
Wraps any route handler. After the handler returns a response, the middleware checks two conditions:
- Was the request a mutation? Only
POST,PUT,PATCH, andDELETErequests qualify.GETrequests never trigger a signal. - Did the mutation succeed? Only responses with status
201(Created),204(No Content), or3xx(Redirect) qualify. A200with validation errors, a400, or a500do not trigger a signal.
Only when both conditions are met does the middleware call send_signal(). Failed validations, rejected logins, and server errors never trigger a rebuild.
Configuration
Set a single environment variable in Reepolee's .env:
REEWEB_PUBLISHER_URL=http://localhost:3011/api/render-signal
| Variable | Example | Purpose |
|---|---|---|
REEWEB_PUBLISHER_URL | http://localhost:3011/api/render-signal | The Publisher's signal endpoint |
When empty or unset, the signal is disabled entirely — no warnings, no errors, the middleware still runs but skips the signal call. This means you can ship the middleware in every route and control signalling purely through the env var.
Wiring Into Routes
Add publisher_signal_mw() to the middleware chain of any route whose mutations should trigger a rebuild. The most common pattern is to wrap entire CRUD modules:
// routes/routes.ts
import { publisher_signal_mw } from "$lib/publisher_signal";
import { my_table_crud } from "./my_table/index";
export default [
...mount_prefix("/my-table",
// ...my_table_crud routes,
publisher_signal_mw(), // fires after every create/update/delete
),
];
The middleware composes with existing guards — put it after auth so unauthenticated requests don't trigger a signal:
...mount_prefix("/admin",
require_module_mw("admin"), // auth first
publisher_signal_mw(), // signal only after authenticated mutations
);
For hand-written routes, wrap individual handlers:
import { publisher_signal_mw } from "$lib/publisher_signal";
const signal = publisher_signal_mw();
export async function post(req: Request): Promise<Response> {
return signal(req, async () => {
// ... your mutation logic
return Response.redirect("/success", 303);
});
}
Because the middleware only fires after 201, 204, or 3xx responses, a hand-written handler that returns 200 with JSON will NOT trigger a signal — return a redirect or a 201/204 to opt into signalling.
End-to-End Flow
Reepolee Admin ReeWeb Publisher Cloudflare
────────────── ──────────────── ──────────
1. Editor saves record
2. POST /my-table returns 201 ──→ POST /api/render-signal (1s timeout)
3. Debounce (collapses bursts)
4. git pull (fetch fresh data)
5. bun ssg (render static site)
6. Diff candidate vs deployed
7. Preview available at :3012
8. [Manual] Click Deploy ──────→ wrangler deploy → live
Steps 3-7 happen automatically once Reepolee sends the signal. Step 8 (deploy) is manual by default — the Publisher shows a Deploy button and a diff of what changed. You can wire deploy into an automated flow if you prefer fully hands-off publishing.
Relationship to Server Notify
Reepolee has a separate internal notification system in lib/server_notify.ts for in-process reloads:
| System | File | Purpose | Target |
|---|---|---|---|
| Publisher signal | lib/publisher_signal/ | Trigger a ReeWeb static-site rebuild | External Publisher (HTTP) |
| Server notify | lib/server_notify.ts | Reload Reepolee's own in-memory translations or trigger a server restart | Self (local process) |
Server notify is used by the generator (reeman) to reload translations or restart after CRUD scaffolding. Publisher signal is used by route middleware to trigger an external ReeWeb rebuild. They serve different purposes and different targets — you may have both active simultaneously.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| No rebuilds after saves | REEWEB_PUBLISHER_URL not set | Set it in .env to the Publisher's signal endpoint |
| "Render signal failed" in logs | Publisher not running or wrong URL | Verify bun publisher is running and the URL matches PUBLISHER_PORT |
| Signal sent but no rebuild | Publisher branch mismatch | Ensure the Publisher is watching the correct PUBLISHER_BRANCH |
| GET requests triggering signals | Middleware order problem | Ensure publisher_signal_mw() only wraps mutation routes, not list routes |
| Signal hangs the request | Network issue or slow Publisher | The 1-second timeout prevents this — if you see slow mutations, check network latency to the Publisher |
See Also
- ReeWeb Publisher — the Publisher dashboard, its API, and how it processes render signals
- ReeWeb & Reepolee — the broader data-source model: fetch-loaders, dynamic asset sync, and how a ReeWeb site pairs with a Reepolee backend