65 lines · 2.3 KB
import { env } from "cloudflare:workers";
import { repoDb } from "./scoped-db";
import type { DeliveryRecord, StoredDelivery } from "./webhook-log-do";

function log(repoId: string) {
  return env.WEBHOOK_LOG.get(env.WEBHOOK_LOG.idFromName(repoId));
}

export function recordWebhookDelivery(repoId: string, delivery: StoredDelivery): Promise<void> {
  return log(repoId).record(repoId, delivery);
}

/**
 * Newest deliveries for a repo (or one hook). Rows written to D1 before the log moved to the per-repo
 * object are merged in until the 30-day retention sweep removes them.
 */
export async function listWebhookDeliveries(
  repoId: string,
  hookId: string | null,
  limit: number,
): Promise<DeliveryRecord[]> {
  const [current, legacy] = await Promise.all([
    log(repoId).list(hookId, limit),
    repoDb(repoId).all<DeliveryRecord>(
      `SELECT d.id, d.webhook_id, d.event, d.status_code, d.error, d.duration_ms, d.attempt, d.created_at
       FROM webhook_deliveries d JOIN webhooks w ON w.id = d.webhook_id
       WHERE w.repo_id = ?1 AND (?2 IS NULL OR d.webhook_id = ?2) ORDER BY d.created_at DESC LIMIT ?3`,
      repoId,
      hookId,
      limit,
    ),
  ]);
  return [...current, ...legacy].sort((left, right) => right.created_at - left.created_at).slice(0, limit);
}

/** A delivery with its stored request body, only if it belongs to one of the repo's current hooks. */
export async function findWebhookDelivery(
  repoId: string,
  deliveryId: string,
  hookId: string | null,