} title="GitHub webhooks" subtitle="Shadow ingestion health. Deliveries are observed but do not create jobs." action={} />
{error ? : null}
+
+ {sections.map((item) => )}
+
} />
- } />
- } />
- } />
+ } />
+ } />
+ } />
-
- {loading ? : Object.keys(status?.receipts ?? {}).length ? (
-
- {Object.entries(status?.receipts ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([state, count]) => )}
-
- ) : }
-
+ {section === "overview" ? <>
+
+ {sectionLoading ? : timeseries?.length ?
: }
+
+
+ {summaryLoading ? : Object.keys(summary?.receipts ?? {}).length ? {Object.entries(summary?.receipts ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([state, count]) => )}
: }
+
+ > : null}
+ {section === "hooks" ?
+ {sectionLoading ? : hooks?.length ? | Target | State | Events | Last ping | Last delivery |
{hooks.map((hook) => {hook.target} {hook.target_type} · #{hook.id} | {hook.status} | {hook.events.join(", ") || "All events"} | {hook.last_ping_at ?? "Never"} | {hook.last_event_at ?? "Never"} |
)}
: }
+ : null}
+ {section === "deliveries" ?
+ {sectionLoading ? : deliveries?.length ? <>| Received | Event | Repository | Result | Delivery |
{deliveries.map((delivery) => | {delivery.created_at} | {delivery.event_name}{delivery.action ? ` · ${delivery.action}` : ""} | {delivery.repository ?? "—"} | {delivery.status} | {delivery.delivery_id} |
)}
{deliveryCursor ? : null}{nextDeliveryCursor ? : null}
> : }
+ : null}
);
}
@@ -4123,6 +4291,9 @@ export {
selectedJobIdFromPath,
shouldRefreshJobForSessionEvent,
urlBase64ToUint8Array,
+ webhookDeliveriesPath,
+ webhookQuerySelection,
+ webhookTimeseriesPath,
WebhookPage,
};
diff --git a/docs/ingestion.md b/docs/ingestion.md
index aa3170e..56215df 100644
--- a/docs/ingestion.md
+++ b/docs/ingestion.md
@@ -78,17 +78,34 @@ organization webhook under **Organization settings → Webhooks**:
A repository webhook covers only that repository. An organization webhook
covers repositories in that organization and is the recommended deployment.
-Multiple organizations may use the same endpoint when each owner has its own
-entry in `GITHUB_AGENT_BRIDGE_WEBHOOK_SECRETS_BY_OWNER`.
+Multiple organizations and multiple hooks may use the same endpoint when each
+owner has its own entry in `GITHUB_AGENT_BRIDGE_WEBHOOK_SECRETS_BY_OWNER`.
+GitHub's `X-GitHub-Hook-ID` header keeps their inventory and activity separate.
The endpoint stores only routing metadata, a SHA-256 payload hash, and the
canonical event key in `webhook_shadow_receipts`; it deliberately stores no raw
-payload and never creates a queue job. Authenticated operators can inspect
-counts, duplicate deliveries, and cross-source event-key matches at
-`GET /api/webhooks/github/status`. Here “operators” means users authorized as
-dashboard administrators through `GITHUB_AGENT_BRIDGE_DASHBOARD_ADMIN_USERS`
-or `GITHUB_AGENT_BRIDGE_DASHBOARD_ADMIN_TEAMS`; other authenticated dashboard
-users receive HTTP 403 and unauthenticated requests receive HTTP 401.
+payload and never creates a queue job. The monitoring API is split so opening
+the overview does not load hook inventory or delivery history:
+
+- `GET /api/webhooks/github/summary` returns mode, receipt counts, retries, and
+ cross-source matches. The previous `/status` path remains a summary-only
+ compatibility alias.
+- `GET /api/webhooks/github/timeseries?from=