sync: update from private repo (a5db2ab0)
CI / build-and-test (push) Successful in 8m58s

This commit is contained in:
oss-sync
2026-07-10 00:51:05 +00:00
parent 2044f0a2c4
commit a67c40d33c
45 changed files with 3599 additions and 15 deletions
+90
View File
@@ -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;