This commit is contained in:
@@ -267,6 +267,96 @@ export async function removeSpacePythonPackage(
|
||||
return data as { packages: SpacePythonPackage[] };
|
||||
}
|
||||
|
||||
// ─── Per-space webhook notifications (issue #797, PR1: Discord only) ─────
|
||||
export type SpaceWebhookProvider = 'discord' | 'slack' | 'teams';
|
||||
export type SpaceWebhookEvent = 'succeeded' | 'failed' | 'waiting_human';
|
||||
|
||||
export interface SpaceWebhook {
|
||||
id: string;
|
||||
provider: SpaceWebhookProvider;
|
||||
label: string;
|
||||
events: SpaceWebhookEvent[];
|
||||
includeDetails: boolean;
|
||||
enabled: boolean;
|
||||
disabledReason: string | null;
|
||||
lastSuccessAt: string | null;
|
||||
lastFailureAt: string | null;
|
||||
failureCount: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
// NOTE: no `url` / `urlEnc` field — the server never returns the webhook
|
||||
// URL once saved (write-only secret).
|
||||
}
|
||||
|
||||
export async function fetchSpaceWebhooks(spaceId: string): Promise<SpaceWebhook[]> {
|
||||
const res = await fetch(`${BASE}/local/spaces/${spaceId}/webhooks`);
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) throw new Error(data?.error ?? 'Failed to fetch webhooks');
|
||||
return (data?.webhooks ?? []) as SpaceWebhook[];
|
||||
}
|
||||
|
||||
export async function createSpaceWebhook(
|
||||
spaceId: string,
|
||||
input: { provider: SpaceWebhookProvider; label: string; url: string; events: SpaceWebhookEvent[]; includeDetails?: boolean },
|
||||
): Promise<SpaceWebhook> {
|
||||
const res = await fetch(`${BASE}/local/spaces/${spaceId}/webhooks`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) throw new Error(data?.error ?? 'Failed to create webhook');
|
||||
return data as SpaceWebhook;
|
||||
}
|
||||
|
||||
export async function updateSpaceWebhook(
|
||||
spaceId: string,
|
||||
webhookId: string,
|
||||
patch: { label?: string; url?: string; events?: SpaceWebhookEvent[]; includeDetails?: boolean },
|
||||
): Promise<SpaceWebhook> {
|
||||
const res = await fetch(`${BASE}/local/spaces/${spaceId}/webhooks/${webhookId}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(patch),
|
||||
});
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) throw new Error(data?.error ?? 'Failed to update webhook');
|
||||
return data as SpaceWebhook;
|
||||
}
|
||||
|
||||
export async function setSpaceWebhookEnabled(
|
||||
spaceId: string,
|
||||
webhookId: string,
|
||||
enabled: boolean,
|
||||
): Promise<SpaceWebhook> {
|
||||
const res = await fetch(`${BASE}/local/spaces/${spaceId}/webhooks/${webhookId}`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ enabled }),
|
||||
});
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) throw new Error(data?.error ?? 'Failed to update webhook');
|
||||
return data as SpaceWebhook;
|
||||
}
|
||||
|
||||
export async function deleteSpaceWebhook(spaceId: string, webhookId: string): Promise<void> {
|
||||
const res = await fetch(`${BASE}/local/spaces/${spaceId}/webhooks/${webhookId}`, { method: 'DELETE' });
|
||||
if (!res.ok) {
|
||||
const d = await res.json().catch(() => ({}));
|
||||
throw new Error(d?.error ?? 'Failed to delete webhook');
|
||||
}
|
||||
}
|
||||
|
||||
export async function testSendSpaceWebhook(
|
||||
spaceId: string,
|
||||
webhookId: string,
|
||||
): Promise<{ ok: boolean; error?: string }> {
|
||||
const res = await fetch(`${BASE}/local/spaces/${spaceId}/webhooks/${webhookId}/test`, { method: 'POST' });
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (!res.ok) return { ok: false, error: data?.error ?? 'Failed to send test notification' };
|
||||
return data as { ok: boolean; error?: string };
|
||||
}
|
||||
|
||||
export async function createSpace(input: {
|
||||
title: string;
|
||||
description?: string;
|
||||
|
||||
Reference in New Issue
Block a user