mirror of
https://github.com/supabase/supabase.git
synced 2026-10-14 05:39:11 +03:00
## What
Wires the existing (mocked) Platform Webhooks UI to the real Management
API backend, per FE-3749.
- New `data/platform-webhooks/` query/mutation hooks, calling the real
`/v2/organizations/{slug}/webhooks/...` and
`/v2/projects/{ref}/webhooks/...` endpoints
- Updated `PlatformWebhooks.types.ts` to match the real API contract
(field names, shapes)
- Added a signing secret field to the create-endpoint form (API requires
a user-provided secret, not server-generated like the mock assumed)
- Removed the event-type column from the deliveries table (the real
list-deliveries endpoint doesn't return event type, only the
single-delivery endpoint does)
- Removed `PlatformWebhooks.mock.ts` / `.store.ts` and their tests
## Why
UI was built ~80% against mock data months ago; this closes the gap to a
real, working feature.
## Known open items (not blocking, tracked separately)
- `name` field has no backend storage yet — client-only for now, open
question with Ali/Paweł
- Deliveries table only fetches the backend's default single page — real
server-side pagination not yet wired (see FE-3750)
## Follow-up PR (stacked)
Tests for the new `data/platform-webhooks/` hooks (MSW-based), per the
ticket's own scope split.
## Testing
Manually tested end-to-end against local backend: created/edited/deleted
an endpoint, verified the real signature using webhook.site,
independently recomputed the HMAC and confirmed it matches the
`webhook-signature` header.
Linear: FE-3749
---------
Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
62 lines
1.7 KiB
TypeScript
62 lines
1.7 KiB
TypeScript
import type { WebhookScope } from './PlatformWebhooks.types'
|
|
|
|
export const shouldHandleEndpointNotFound = ({
|
|
endpointId,
|
|
hasSelectedEndpoint,
|
|
pendingCreatedEndpointId,
|
|
}: {
|
|
endpointId?: string
|
|
hasSelectedEndpoint: boolean
|
|
pendingCreatedEndpointId: string | null
|
|
}) => {
|
|
if (!endpointId) return false
|
|
if (hasSelectedEndpoint) return false
|
|
return endpointId !== pendingCreatedEndpointId
|
|
}
|
|
|
|
/**
|
|
* Only redirect away once the flags have loaded and the route params are populated; before
|
|
* that, the flag reads `false` and `slug`/`ref` are undefined even for enabled users.
|
|
*/
|
|
export const shouldRedirectFromWebhooks = ({
|
|
areFlagsReady,
|
|
isScopeReady,
|
|
isEnabled,
|
|
}: {
|
|
areFlagsReady: boolean
|
|
isScopeReady: boolean
|
|
isEnabled: boolean
|
|
}) => areFlagsReady && isScopeReady && !isEnabled
|
|
|
|
interface PendingSigningSecretReveal {
|
|
endpointId: string
|
|
signingSecret: string
|
|
}
|
|
|
|
const pendingSigningSecretRevealByScope: Partial<Record<WebhookScope, PendingSigningSecretReveal>> =
|
|
{}
|
|
|
|
export const setPendingSigningSecretReveal = (
|
|
scope: WebhookScope,
|
|
value: PendingSigningSecretReveal
|
|
) => {
|
|
pendingSigningSecretRevealByScope[scope] = value
|
|
}
|
|
|
|
export const getPendingSigningSecretReveal = (scope: WebhookScope, endpointId?: string) => {
|
|
const pending = pendingSigningSecretRevealByScope[scope]
|
|
if (!pending) return null
|
|
if (endpointId && pending.endpointId !== endpointId) return null
|
|
return pending
|
|
}
|
|
|
|
export const clearPendingSigningSecretReveal = (scope: WebhookScope) => {
|
|
delete pendingSigningSecretRevealByScope[scope]
|
|
}
|
|
|
|
export const resetPendingSigningSecretRevealForTests = () => {
|
|
for (const key of Object.keys(pendingSigningSecretRevealByScope) as WebhookScope[]) {
|
|
delete pendingSigningSecretRevealByScope[key]
|
|
}
|
|
}
|