Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199import { ok } from "@atcute/client";import type { Did, Nsid } from "@atcute/lexicons/syntax";import type { OAuthUserAgent } from "@atcute/oauth-browser-client";import { serviceClient } from "$lib/api/_request";import { serviceDidForHost } from "$lib/auth/agent";import type { Permission } from "$lib/auth/scopes";import { mainSchema as createWebhookSchema } from "$lib/api/lexicons/types/org/tangled/temp/webhook/createWebhook";import { mainSchema as deleteWebhookSchema } from "$lib/api/lexicons/types/org/tangled/temp/webhook/deleteWebhook";import { mainSchema as getDeliveriesSchema, type Delivery} from "$lib/api/lexicons/types/org/tangled/temp/webhook/getDeliveriesForWebhooks";import { mainSchema as listWebhooksSchema, type Webhook} from "$lib/api/lexicons/types/org/tangled/temp/webhook/listWebhooks";import { mainSchema as retryDeliverySchema } from "$lib/api/lexicons/types/org/tangled/temp/webhook/retryDelivery";import { mainSchema as toggleWebhookSchema } from "$lib/api/lexicons/types/org/tangled/temp/webhook/toggleWebhook";import { mainSchema as updateWebhookSchema } from "$lib/api/lexicons/types/org/tangled/temp/webhook/updateWebhook";import { didOf } from "$lib/api/syntax";
export type { Delivery, Webhook };
export const WEBHOOK_EVENTS = [ { id: "push", label: "Push events" }, { id: "repository:renamed", label: "Repository renamed" }, { id: "pull_request:created", label: "Pull request opened" }, { id: "pull_request:resubmitted", label: "Pull request resubmitted" }, { id: "pull_request:merged", label: "Pull request merged" }, { id: "pull_request:closed", label: "Pull request closed" }, { id: "pull_request:reopened", label: "Pull request reopened" }] as const;
export type WebhookEvent = (typeof WEBHOOK_EVENTS)[number]["id"];export type WebhookEventSelection = Record<WebhookEvent, boolean>;export type WebhookActivation = "active" | "inactive";
export const webhookActivation = (active: boolean): WebhookActivation => active ? "active" : "inactive";export const webhookIsActive = (activation: WebhookActivation): boolean => activation === "active";
const WEBHOOK_METHODS = [ createWebhookSchema.nsid, deleteWebhookSchema.nsid, getDeliveriesSchema.nsid, listWebhooksSchema.nsid, retryDeliverySchema.nsid, toggleWebhookSchema.nsid, updateWebhookSchema.nsid] as const;
export const webhookPermissions = (spindle: URL): readonly Permission[] => { const aud = didOf(serviceDidForHost(spindle.host)); return WEBHOOK_METHODS.map((lxm) => ({ resource: "rpc", lxm: lxm as Nsid, aud }));};
export const webhookEventSelection = ( events: readonly string[] = ["push"]): WebhookEventSelection => Object.fromEntries( WEBHOOK_EVENTS.map(({ id }) => [id, events.includes(id)]) ) as WebhookEventSelection;
export const selectedWebhookEvents = (selection: WebhookEventSelection): WebhookEvent[] => WEBHOOK_EVENTS.flatMap(({ id }) => (selection[id] ? [id] : []));
export const isWebhookUrl = (value: string): boolean => { try { return ["http:", "https:"].includes(new URL(value.trim()).protocol); } catch { return false; }};
type GenericUri = `${string}:${string}`;
const client = (agent: OAuthUserAgent, spindle: URL) => serviceClient(agent, spindle.toString()).xrpc;const url = (value: string): GenericUri => { const normalized = value.trim(); if (!isWebhookUrl(normalized)) throw new Error("Webhook URL must use HTTP or HTTPS."); return normalized as GenericUri;};
export const listWebhooks = async ( agent: OAuthUserAgent, spindle: URL, repoDid: Did): Promise<Webhook[]> => { const { webhooks } = await ok( client(agent, spindle).call(listWebhooksSchema, { params: { repoDid } }) ); return webhooks ?? [];};
export interface CreateWebhook { url: string; events: WebhookEvent[]; secret?: string; active?: boolean;}
export const createWebhook = async ( agent: OAuthUserAgent, spindle: URL, repoDid: Did, webhook: CreateWebhook): Promise<number> => { const { id } = await ok( client(agent, spindle).call(createWebhookSchema, { input: { ...webhook, repoDid, url: url(webhook.url) } }) ); return id;};
export interface UpdateWebhook { url?: string; events?: WebhookEvent[]; secret?: string; active?: boolean;}
export const updateWebhook = async ( agent: OAuthUserAgent, spindle: URL, repoDid: Did, id: number, webhook: UpdateWebhook): Promise<void> => { const { url: webhookUrl, ...changes } = webhook; await ok( client(agent, spindle).call(updateWebhookSchema, { input: { ...changes, repoDid, id, ...(webhookUrl === undefined ? {} : { url: url(webhookUrl) }) } }) );};
export const deleteWebhook = async ( agent: OAuthUserAgent, spindle: URL, repoDid: Did, id: number): Promise<void> => { await ok( client(agent, spindle).call(deleteWebhookSchema, { input: { repoDid, id } }) );};
export const toggleWebhook = async ( agent: OAuthUserAgent, spindle: URL, repoDid: Did, id: number): Promise<boolean> => { const { active } = await ok( client(agent, spindle).call(toggleWebhookSchema, { input: { repoDid, id } }) ); return active;};
export const listWebhookDeliveries = async ( agent: OAuthUserAgent, spindle: URL, repoDid: Did, ids: number[], limit = 100): Promise<Delivery[]> => { const { deliveries } = await ok( client(agent, spindle).call(getDeliveriesSchema, { params: { repoDid, ids, limit } }) ); return deliveries ?? [];};
export const retryWebhookDelivery = async ( agent: OAuthUserAgent, spindle: URL, repoDid: Did, webhookId: number, deliveryId: string): Promise<void> => { await ok( client(agent, spindle).call(retryDeliverySchema, { input: { repoDid, webhookId, deliveryId } }) );};