@zyphr-dev/webhook-portal 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +301 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +107 -0
- package/dist/index.js +298 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +1 -0
- package/package.json +76 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
|
|
6
|
+
const DEFAULT_BASE_URL = 'https://api.zyphr.dev/v1/waas-portal';
|
|
7
|
+
function usePortalApi({ token, baseUrl }) {
|
|
8
|
+
const base = baseUrl || DEFAULT_BASE_URL;
|
|
9
|
+
const tokenRef = react.useRef(token);
|
|
10
|
+
tokenRef.current = token;
|
|
11
|
+
const request = react.useCallback(async (path, options) => {
|
|
12
|
+
const res = await fetch(`${base}${path}`, {
|
|
13
|
+
...options,
|
|
14
|
+
headers: {
|
|
15
|
+
'Content-Type': 'application/json',
|
|
16
|
+
Authorization: `Bearer ${tokenRef.current}`,
|
|
17
|
+
...options?.headers,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
if (!res.ok) {
|
|
21
|
+
const body = await res.json().catch(() => ({}));
|
|
22
|
+
throw new Error(body?.error?.message || `Request failed: ${res.status}`);
|
|
23
|
+
}
|
|
24
|
+
if (res.status === 204)
|
|
25
|
+
return undefined;
|
|
26
|
+
return res.json();
|
|
27
|
+
}, [base]);
|
|
28
|
+
const listEventTypes = react.useCallback(async () => {
|
|
29
|
+
const res = await request('/event-types');
|
|
30
|
+
return res.data;
|
|
31
|
+
}, [request]);
|
|
32
|
+
const listEndpoints = react.useCallback(async (limit = 20, offset = 0) => {
|
|
33
|
+
const res = await request(`/endpoints?limit=${limit}&offset=${offset}`);
|
|
34
|
+
return { endpoints: res.data, total: res.meta.total || 0 };
|
|
35
|
+
}, [request]);
|
|
36
|
+
const createEndpoint = react.useCallback(async (data) => {
|
|
37
|
+
const res = await request('/endpoints', {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
body: JSON.stringify(data),
|
|
40
|
+
});
|
|
41
|
+
return res.data;
|
|
42
|
+
}, [request]);
|
|
43
|
+
const updateEndpoint = react.useCallback(async (endpointId, data) => {
|
|
44
|
+
const res = await request(`/endpoints/${endpointId}`, {
|
|
45
|
+
method: 'PUT',
|
|
46
|
+
body: JSON.stringify(data),
|
|
47
|
+
});
|
|
48
|
+
return res.data;
|
|
49
|
+
}, [request]);
|
|
50
|
+
const deleteEndpoint = react.useCallback(async (endpointId) => {
|
|
51
|
+
await request(`/endpoints/${endpointId}`, { method: 'DELETE' });
|
|
52
|
+
}, [request]);
|
|
53
|
+
const rotateSecret = react.useCallback(async (endpointId) => {
|
|
54
|
+
const res = await request(`/endpoints/${endpointId}/rotate-secret`, { method: 'POST' });
|
|
55
|
+
return res.data.secret;
|
|
56
|
+
}, [request]);
|
|
57
|
+
const listDeliveries = react.useCallback(async (endpointId, params) => {
|
|
58
|
+
const query = new URLSearchParams();
|
|
59
|
+
if (params?.limit)
|
|
60
|
+
query.set('limit', String(params.limit));
|
|
61
|
+
if (params?.offset)
|
|
62
|
+
query.set('offset', String(params.offset));
|
|
63
|
+
if (params?.status)
|
|
64
|
+
query.set('status', params.status);
|
|
65
|
+
const qs = query.toString();
|
|
66
|
+
const res = await request(`/endpoints/${endpointId}/deliveries${qs ? `?${qs}` : ''}`);
|
|
67
|
+
return { deliveries: res.data, total: res.meta.total || 0 };
|
|
68
|
+
}, [request]);
|
|
69
|
+
const getDelivery = react.useCallback(async (endpointId, deliveryId) => {
|
|
70
|
+
const res = await request(`/endpoints/${endpointId}/deliveries/${deliveryId}`);
|
|
71
|
+
return res.data;
|
|
72
|
+
}, [request]);
|
|
73
|
+
const retryDelivery = react.useCallback(async (endpointId, deliveryId) => {
|
|
74
|
+
await request(`/endpoints/${endpointId}/deliveries/${deliveryId}/retry`, {
|
|
75
|
+
method: 'POST',
|
|
76
|
+
});
|
|
77
|
+
}, [request]);
|
|
78
|
+
return {
|
|
79
|
+
listEventTypes,
|
|
80
|
+
listEndpoints,
|
|
81
|
+
createEndpoint,
|
|
82
|
+
updateEndpoint,
|
|
83
|
+
deleteEndpoint,
|
|
84
|
+
rotateSecret,
|
|
85
|
+
listDeliveries,
|
|
86
|
+
getDelivery,
|
|
87
|
+
retryDelivery,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function EndpointList({ api, eventTypes, onSelect, onCreated, onDeleted, onUpdated, onError, }) {
|
|
92
|
+
const [endpoints, setEndpoints] = react.useState([]);
|
|
93
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
94
|
+
const [showCreate, setShowCreate] = react.useState(false);
|
|
95
|
+
const [newUrl, setNewUrl] = react.useState('');
|
|
96
|
+
const [newEvents, setNewEvents] = react.useState([]);
|
|
97
|
+
const [newDesc, setNewDesc] = react.useState('');
|
|
98
|
+
const [isCreating, setIsCreating] = react.useState(false);
|
|
99
|
+
const [createdSecret, setCreatedSecret] = react.useState(null);
|
|
100
|
+
const fetchEndpoints = react.useCallback(async () => {
|
|
101
|
+
try {
|
|
102
|
+
setIsLoading(true);
|
|
103
|
+
const result = await api.listEndpoints(100, 0);
|
|
104
|
+
setEndpoints(result.endpoints);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
onError?.(err instanceof Error ? err : new Error('Failed to load endpoints'));
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
setIsLoading(false);
|
|
111
|
+
}
|
|
112
|
+
}, [api, onError]);
|
|
113
|
+
react.useEffect(() => { fetchEndpoints(); }, [fetchEndpoints]);
|
|
114
|
+
const handleCreate = async () => {
|
|
115
|
+
if (!newUrl || newEvents.length === 0)
|
|
116
|
+
return;
|
|
117
|
+
setIsCreating(true);
|
|
118
|
+
try {
|
|
119
|
+
const endpoint = await api.createEndpoint({
|
|
120
|
+
url: newUrl,
|
|
121
|
+
events: newEvents,
|
|
122
|
+
description: newDesc || undefined,
|
|
123
|
+
});
|
|
124
|
+
setCreatedSecret(endpoint.secret);
|
|
125
|
+
setNewUrl('');
|
|
126
|
+
setNewEvents([]);
|
|
127
|
+
setNewDesc('');
|
|
128
|
+
await fetchEndpoints();
|
|
129
|
+
onCreated?.(endpoint);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
onError?.(err instanceof Error ? err : new Error('Failed to create endpoint'));
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
setIsCreating(false);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const handleDelete = async (ep) => {
|
|
139
|
+
try {
|
|
140
|
+
await api.deleteEndpoint(ep.id);
|
|
141
|
+
await fetchEndpoints();
|
|
142
|
+
onDeleted?.(ep);
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
onError?.(err instanceof Error ? err : new Error('Failed to delete endpoint'));
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const handleToggleStatus = async (ep) => {
|
|
149
|
+
const newStatus = ep.status === 'active' ? 'paused' : 'active';
|
|
150
|
+
try {
|
|
151
|
+
const updated = await api.updateEndpoint(ep.id, { status: newStatus });
|
|
152
|
+
await fetchEndpoints();
|
|
153
|
+
onUpdated?.(updated);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
onError?.(err instanceof Error ? err : new Error('Failed to update endpoint'));
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
const toggleEvent = (eventType) => {
|
|
160
|
+
setNewEvents(prev => prev.includes(eventType) ? prev.filter(e => e !== eventType) : [...prev, eventType]);
|
|
161
|
+
};
|
|
162
|
+
const statusBadgeClass = (status) => {
|
|
163
|
+
switch (status) {
|
|
164
|
+
case 'active': return 'zwp-badge zwp-badge--green';
|
|
165
|
+
case 'paused': return 'zwp-badge zwp-badge--yellow';
|
|
166
|
+
case 'disabled': return 'zwp-badge zwp-badge--red';
|
|
167
|
+
default: return 'zwp-badge';
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
if (isLoading) {
|
|
171
|
+
return jsxRuntime.jsx("div", { className: "zwp-loading", children: "Loading endpoints..." });
|
|
172
|
+
}
|
|
173
|
+
return (jsxRuntime.jsxs("div", { className: "zwp-endpoint-list", children: [jsxRuntime.jsxs("div", { className: "zwp-section-header", children: [jsxRuntime.jsx("h3", { className: "zwp-heading", children: "Endpoints" }), jsxRuntime.jsx("button", { className: "zwp-btn zwp-btn--primary", onClick: () => { setShowCreate(!showCreate); setCreatedSecret(null); }, children: showCreate ? 'Cancel' : 'Add Endpoint' })] }), createdSecret && (jsxRuntime.jsxs("div", { className: "zwp-alert zwp-alert--warning", children: [jsxRuntime.jsx("strong", { children: "Signing Secret" }), jsxRuntime.jsx("p", { children: "Store this secret securely. It will not be shown again." }), jsxRuntime.jsx("code", { className: "zwp-secret", children: createdSecret }), jsxRuntime.jsx("button", { className: "zwp-btn zwp-btn--sm", onClick: () => { navigator.clipboard.writeText(createdSecret); }, children: "Copy" })] })), showCreate && (jsxRuntime.jsxs("div", { className: "zwp-create-form", children: [jsxRuntime.jsxs("div", { className: "zwp-field", children: [jsxRuntime.jsx("label", { className: "zwp-label", children: "URL" }), jsxRuntime.jsx("input", { className: "zwp-input", type: "url", placeholder: "https://your-app.com/webhooks", value: newUrl, onChange: e => setNewUrl(e.target.value) })] }), jsxRuntime.jsxs("div", { className: "zwp-field", children: [jsxRuntime.jsx("label", { className: "zwp-label", children: "Description (optional)" }), jsxRuntime.jsx("input", { className: "zwp-input", type: "text", placeholder: "Production endpoint", value: newDesc, onChange: e => setNewDesc(e.target.value) })] }), jsxRuntime.jsxs("div", { className: "zwp-field", children: [jsxRuntime.jsx("label", { className: "zwp-label", children: "Events" }), jsxRuntime.jsx("div", { className: "zwp-event-picker", children: eventTypes.map(et => (jsxRuntime.jsxs("label", { className: "zwp-checkbox-label", children: [jsxRuntime.jsx("input", { type: "checkbox", checked: newEvents.includes(et.event_type), onChange: () => toggleEvent(et.event_type) }), jsxRuntime.jsx("span", { className: "zwp-event-name", children: et.name }), jsxRuntime.jsx("span", { className: "zwp-event-type", children: et.event_type })] }, et.event_type))) })] }), jsxRuntime.jsx("button", { className: "zwp-btn zwp-btn--primary", onClick: handleCreate, disabled: isCreating || !newUrl || newEvents.length === 0, children: isCreating ? 'Creating...' : 'Create Endpoint' })] })), endpoints.length === 0 ? (jsxRuntime.jsxs("div", { className: "zwp-empty", children: [jsxRuntime.jsx("p", { children: "No endpoints configured yet." }), jsxRuntime.jsx("p", { children: "Add an endpoint to start receiving webhook deliveries." })] })) : (jsxRuntime.jsx("div", { className: "zwp-list", children: endpoints.map(ep => (jsxRuntime.jsxs("div", { className: "zwp-endpoint-card", onClick: () => onSelect(ep), children: [jsxRuntime.jsxs("div", { className: "zwp-endpoint-header", children: [jsxRuntime.jsx("code", { className: "zwp-endpoint-url", children: ep.url }), jsxRuntime.jsx("span", { className: statusBadgeClass(ep.status), children: ep.status })] }), ep.description && (jsxRuntime.jsx("p", { className: "zwp-endpoint-desc", children: ep.description })), jsxRuntime.jsxs("div", { className: "zwp-endpoint-meta", children: [jsxRuntime.jsxs("span", { children: [ep.events.length, " event", ep.events.length !== 1 ? 's' : ''] }), jsxRuntime.jsxs("span", { children: ["Created ", new Date(ep.created_at).toLocaleDateString()] })] }), jsxRuntime.jsxs("div", { className: "zwp-endpoint-actions", onClick: e => e.stopPropagation(), children: [jsxRuntime.jsx("button", { className: "zwp-btn zwp-btn--sm zwp-btn--ghost", onClick: () => handleToggleStatus(ep), children: ep.status === 'active' ? 'Pause' : 'Resume' }), jsxRuntime.jsx("button", { className: "zwp-btn zwp-btn--sm zwp-btn--danger", onClick: () => handleDelete(ep), children: "Delete" })] })] }, ep.id))) }))] }));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function EndpointDetail({ api, endpoint, onBack, onRetried, onError }) {
|
|
177
|
+
const [deliveries, setDeliveries] = react.useState([]);
|
|
178
|
+
const [total, setTotal] = react.useState(0);
|
|
179
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
180
|
+
const [statusFilter, setStatusFilter] = react.useState('');
|
|
181
|
+
const [page, setPage] = react.useState(0);
|
|
182
|
+
const [retrying, setRetrying] = react.useState(null);
|
|
183
|
+
const PAGE_SIZE = 20;
|
|
184
|
+
const fetchDeliveries = react.useCallback(async () => {
|
|
185
|
+
try {
|
|
186
|
+
setIsLoading(true);
|
|
187
|
+
const result = await api.listDeliveries(endpoint.id, {
|
|
188
|
+
limit: PAGE_SIZE,
|
|
189
|
+
offset: page * PAGE_SIZE,
|
|
190
|
+
status: statusFilter || undefined,
|
|
191
|
+
});
|
|
192
|
+
setDeliveries(result.deliveries);
|
|
193
|
+
setTotal(result.total);
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
onError?.(err instanceof Error ? err : new Error('Failed to load deliveries'));
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
setIsLoading(false);
|
|
200
|
+
}
|
|
201
|
+
}, [api, endpoint.id, page, statusFilter, onError]);
|
|
202
|
+
react.useEffect(() => { fetchDeliveries(); }, [fetchDeliveries]);
|
|
203
|
+
const handleRetry = async (deliveryId) => {
|
|
204
|
+
setRetrying(deliveryId);
|
|
205
|
+
try {
|
|
206
|
+
await api.retryDelivery(endpoint.id, deliveryId);
|
|
207
|
+
await fetchDeliveries();
|
|
208
|
+
onRetried?.(deliveryId);
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
onError?.(err instanceof Error ? err : new Error('Failed to retry delivery'));
|
|
212
|
+
}
|
|
213
|
+
finally {
|
|
214
|
+
setRetrying(null);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
const handleRotateSecret = async () => {
|
|
218
|
+
try {
|
|
219
|
+
const secret = await api.rotateSecret(endpoint.id);
|
|
220
|
+
alert(`New secret: ${secret}\n\nStore this securely. It will not be shown again.`);
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
onError?.(err instanceof Error ? err : new Error('Failed to rotate secret'));
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
const statusBadgeClass = (status) => {
|
|
227
|
+
switch (status) {
|
|
228
|
+
case 'delivered': return 'zwp-badge zwp-badge--green';
|
|
229
|
+
case 'failed':
|
|
230
|
+
case 'exhausted': return 'zwp-badge zwp-badge--red';
|
|
231
|
+
case 'retrying':
|
|
232
|
+
case 'pending': return 'zwp-badge zwp-badge--yellow';
|
|
233
|
+
default: return 'zwp-badge';
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
const canRetry = (status) => status === 'failed' || status === 'exhausted';
|
|
237
|
+
const totalPages = Math.ceil(total / PAGE_SIZE);
|
|
238
|
+
return (jsxRuntime.jsxs("div", { className: "zwp-endpoint-detail", children: [jsxRuntime.jsx("button", { className: "zwp-btn zwp-btn--ghost zwp-back-btn", onClick: onBack, children: "\u2190 Back to endpoints" }), jsxRuntime.jsxs("div", { className: "zwp-detail-header", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("code", { className: "zwp-endpoint-url", children: endpoint.url }), jsxRuntime.jsxs("div", { className: "zwp-endpoint-meta", children: [jsxRuntime.jsxs("span", { children: [endpoint.events.length, " event", endpoint.events.length !== 1 ? 's' : ''] }), jsxRuntime.jsxs("span", { children: ["Status: ", endpoint.status] })] })] }), jsxRuntime.jsx("button", { className: "zwp-btn zwp-btn--sm", onClick: handleRotateSecret, children: "Rotate Secret" })] }), jsxRuntime.jsxs("div", { className: "zwp-events-list", children: [jsxRuntime.jsx("h4", { className: "zwp-subheading", children: "Subscribed Events" }), jsxRuntime.jsx("div", { className: "zwp-tags", children: endpoint.events.map(e => (jsxRuntime.jsx("span", { className: "zwp-tag", children: e }, e))) })] }), jsxRuntime.jsxs("div", { className: "zwp-deliveries", children: [jsxRuntime.jsxs("div", { className: "zwp-section-header", children: [jsxRuntime.jsx("h4", { className: "zwp-subheading", children: "Delivery Log" }), jsxRuntime.jsxs("select", { className: "zwp-select", value: statusFilter, onChange: e => { setStatusFilter(e.target.value); setPage(0); }, children: [jsxRuntime.jsx("option", { value: "", children: "All statuses" }), jsxRuntime.jsx("option", { value: "delivered", children: "Delivered" }), jsxRuntime.jsx("option", { value: "failed", children: "Failed" }), jsxRuntime.jsx("option", { value: "exhausted", children: "Exhausted" }), jsxRuntime.jsx("option", { value: "retrying", children: "Retrying" }), jsxRuntime.jsx("option", { value: "pending", children: "Pending" })] })] }), isLoading ? (jsxRuntime.jsx("div", { className: "zwp-loading", children: "Loading deliveries..." })) : deliveries.length === 0 ? (jsxRuntime.jsx("div", { className: "zwp-empty", children: jsxRuntime.jsx("p", { children: "No deliveries yet." }) })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("table", { className: "zwp-table", children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [jsxRuntime.jsx("th", { children: "Event" }), jsxRuntime.jsx("th", { children: "Status" }), jsxRuntime.jsx("th", { children: "Attempts" }), jsxRuntime.jsx("th", { children: "Response" }), jsxRuntime.jsx("th", { children: "Time" }), jsxRuntime.jsx("th", {})] }) }), jsxRuntime.jsx("tbody", { children: deliveries.map(d => (jsxRuntime.jsxs("tr", { children: [jsxRuntime.jsx("td", { children: jsxRuntime.jsx("code", { className: "zwp-event-code", children: d.event_type }) }), jsxRuntime.jsx("td", { children: jsxRuntime.jsx("span", { className: statusBadgeClass(d.status), children: d.status }) }), jsxRuntime.jsxs("td", { children: [d.attempts, "/", d.max_attempts] }), jsxRuntime.jsx("td", { children: d.last_response_status || '—' }), jsxRuntime.jsx("td", { className: "zwp-time", children: d.last_attempted_at
|
|
239
|
+
? new Date(d.last_attempted_at).toLocaleString()
|
|
240
|
+
: new Date(d.created_at).toLocaleString() }), jsxRuntime.jsx("td", { children: canRetry(d.status) && (jsxRuntime.jsx("button", { className: "zwp-btn zwp-btn--sm", onClick: () => handleRetry(d.id), disabled: retrying === d.id, children: retrying === d.id ? '...' : 'Retry' })) })] }, d.id))) })] }), totalPages > 1 && (jsxRuntime.jsxs("div", { className: "zwp-pagination", children: [jsxRuntime.jsx("button", { className: "zwp-btn zwp-btn--sm", onClick: () => setPage(p => p - 1), disabled: page === 0, children: "Previous" }), jsxRuntime.jsxs("span", { className: "zwp-page-info", children: ["Page ", page + 1, " of ", totalPages] }), jsxRuntime.jsx("button", { className: "zwp-btn zwp-btn--sm", onClick: () => setPage(p => p + 1), disabled: page >= totalPages - 1, children: "Next" })] }))] }))] })] }));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const PREVIEW_ENDPOINTS = [
|
|
244
|
+
{
|
|
245
|
+
id: 'preview-1',
|
|
246
|
+
url: 'https://api.example.com/webhooks',
|
|
247
|
+
description: 'Production endpoint',
|
|
248
|
+
events: ['order.created', 'order.updated', 'payment.completed'],
|
|
249
|
+
status: 'active',
|
|
250
|
+
consecutive_failures: 0,
|
|
251
|
+
created_at: new Date().toISOString(),
|
|
252
|
+
updated_at: new Date().toISOString(),
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
id: 'preview-2',
|
|
256
|
+
url: 'https://staging.example.com/hooks',
|
|
257
|
+
events: ['order.created'],
|
|
258
|
+
status: 'paused',
|
|
259
|
+
consecutive_failures: 0,
|
|
260
|
+
created_at: new Date(Date.now() - 86400000).toISOString(),
|
|
261
|
+
updated_at: new Date(Date.now() - 86400000).toISOString(),
|
|
262
|
+
},
|
|
263
|
+
];
|
|
264
|
+
function PreviewEndpointList() {
|
|
265
|
+
return (jsxRuntime.jsxs("div", { className: "zwp-endpoint-list", children: [jsxRuntime.jsxs("div", { className: "zwp-section-header", children: [jsxRuntime.jsx("h3", { className: "zwp-heading", children: "Endpoints" }), jsxRuntime.jsx("button", { className: "zwp-btn zwp-btn--primary", disabled: true, children: "Add Endpoint" })] }), jsxRuntime.jsx("div", { className: "zwp-list", children: PREVIEW_ENDPOINTS.map(ep => (jsxRuntime.jsxs("div", { className: "zwp-endpoint-card", style: { cursor: 'default' }, children: [jsxRuntime.jsxs("div", { className: "zwp-endpoint-header", children: [jsxRuntime.jsx("code", { className: "zwp-endpoint-url", children: ep.url }), jsxRuntime.jsx("span", { className: `zwp-badge ${ep.status === 'active' ? 'zwp-badge--green' : 'zwp-badge--yellow'}`, children: ep.status })] }), ep.description && jsxRuntime.jsx("p", { className: "zwp-endpoint-desc", children: ep.description }), jsxRuntime.jsxs("div", { className: "zwp-endpoint-meta", children: [jsxRuntime.jsxs("span", { children: [ep.events.length, " event", ep.events.length !== 1 ? 's' : ''] }), jsxRuntime.jsxs("span", { children: ["Created ", new Date(ep.created_at).toLocaleDateString()] })] })] }, ep.id))) })] }));
|
|
266
|
+
}
|
|
267
|
+
function WebhookPortal({ token, baseUrl, theme, preview, onEndpointCreated, onEndpointDeleted, onEndpointUpdated, onDeliveryRetried, onError, className, }) {
|
|
268
|
+
const api = usePortalApi({ token, baseUrl });
|
|
269
|
+
const [eventTypes, setEventTypes] = react.useState([]);
|
|
270
|
+
const [selectedEndpoint, setSelectedEndpoint] = react.useState(null);
|
|
271
|
+
const [error, setError] = react.useState(null);
|
|
272
|
+
react.useEffect(() => {
|
|
273
|
+
if (preview)
|
|
274
|
+
return;
|
|
275
|
+
api.listEventTypes()
|
|
276
|
+
.then(setEventTypes)
|
|
277
|
+
.catch(err => {
|
|
278
|
+
const e = err instanceof Error ? err : new Error('Failed to load event types');
|
|
279
|
+
setError(e.message);
|
|
280
|
+
onError?.(e);
|
|
281
|
+
});
|
|
282
|
+
}, [api, onError, preview]);
|
|
283
|
+
const handleError = (err) => {
|
|
284
|
+
setError(err.message);
|
|
285
|
+
onError?.(err);
|
|
286
|
+
setTimeout(() => setError(null), 5000);
|
|
287
|
+
};
|
|
288
|
+
const style = {};
|
|
289
|
+
if (theme?.accent) {
|
|
290
|
+
style['--zwp-accent'] = theme.accent;
|
|
291
|
+
}
|
|
292
|
+
if (theme?.borderRadius !== undefined) {
|
|
293
|
+
style['--zwp-radius'] = `${theme.borderRadius}px`;
|
|
294
|
+
}
|
|
295
|
+
const themeClass = theme?.mode === 'dark' ? 'zwp-dark' : 'zwp-light';
|
|
296
|
+
return (jsxRuntime.jsxs("div", { className: `zwp-portal ${themeClass} ${className || ''}`, style: style, children: [error && (jsxRuntime.jsxs("div", { className: "zwp-alert zwp-alert--error", children: [error, jsxRuntime.jsx("button", { className: "zwp-alert-close", onClick: () => setError(null), children: "\u00D7" })] })), preview ? (jsxRuntime.jsx(PreviewEndpointList, {})) : selectedEndpoint ? (jsxRuntime.jsx(EndpointDetail, { api: api, endpoint: selectedEndpoint, onBack: () => setSelectedEndpoint(null), onRetried: onDeliveryRetried, onError: handleError })) : (jsxRuntime.jsx(EndpointList, { api: api, eventTypes: eventTypes, onSelect: setSelectedEndpoint, onCreated: onEndpointCreated, onDeleted: onEndpointDeleted, onUpdated: onEndpointUpdated, onError: handleError }))] }));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
exports.WebhookPortal = WebhookPortal;
|
|
300
|
+
exports.usePortalApi = usePortalApi;
|
|
301
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/hooks/usePortalApi.ts","../src/components/EndpointList.tsx","../src/components/EndpointDetail.tsx","../src/components/WebhookPortal.tsx"],"sourcesContent":["import { useCallback, useRef } from 'react';\nimport type {\n PortalApiResponse,\n PortalEventType,\n PortalEndpoint,\n PortalEndpointWithSecret,\n PortalDelivery,\n PortalDeliveryDetail,\n} from '../types';\n\nconst DEFAULT_BASE_URL = 'https://api.zyphr.dev/v1/waas-portal';\n\ninterface UsePortalApiOptions {\n token: string;\n baseUrl?: string;\n}\n\nexport function usePortalApi({ token, baseUrl }: UsePortalApiOptions) {\n const base = baseUrl || DEFAULT_BASE_URL;\n const tokenRef = useRef(token);\n tokenRef.current = token;\n\n const request = useCallback(async <T>(path: string, options?: RequestInit): Promise<T> => {\n const res = await fetch(`${base}${path}`, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${tokenRef.current}`,\n ...options?.headers,\n },\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n throw new Error(body?.error?.message || `Request failed: ${res.status}`);\n }\n\n if (res.status === 204) return undefined as T;\n return res.json();\n }, [base]);\n\n const listEventTypes = useCallback(async () => {\n const res = await request<PortalApiResponse<PortalEventType[]>>('/event-types');\n return res.data;\n }, [request]);\n\n const listEndpoints = useCallback(async (limit = 20, offset = 0) => {\n const res = await request<PortalApiResponse<PortalEndpoint[]>>(\n `/endpoints?limit=${limit}&offset=${offset}`\n );\n return { endpoints: res.data, total: res.meta.total || 0 };\n }, [request]);\n\n const createEndpoint = useCallback(async (data: {\n url: string;\n events: string[];\n description?: string;\n }) => {\n const res = await request<PortalApiResponse<PortalEndpointWithSecret>>('/endpoints', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n return res.data;\n }, [request]);\n\n const updateEndpoint = useCallback(async (endpointId: string, data: {\n url?: string;\n events?: string[];\n status?: 'active' | 'paused' | 'disabled';\n description?: string;\n }) => {\n const res = await request<PortalApiResponse<PortalEndpoint>>(`/endpoints/${endpointId}`, {\n method: 'PUT',\n body: JSON.stringify(data),\n });\n return res.data;\n }, [request]);\n\n const deleteEndpoint = useCallback(async (endpointId: string) => {\n await request(`/endpoints/${endpointId}`, { method: 'DELETE' });\n }, [request]);\n\n const rotateSecret = useCallback(async (endpointId: string) => {\n const res = await request<PortalApiResponse<{ secret: string }>>(\n `/endpoints/${endpointId}/rotate-secret`,\n { method: 'POST' }\n );\n return res.data.secret;\n }, [request]);\n\n const listDeliveries = useCallback(async (endpointId: string, params?: {\n limit?: number;\n offset?: number;\n status?: string;\n }) => {\n const query = new URLSearchParams();\n if (params?.limit) query.set('limit', String(params.limit));\n if (params?.offset) query.set('offset', String(params.offset));\n if (params?.status) query.set('status', params.status);\n const qs = query.toString();\n\n const res = await request<PortalApiResponse<PortalDelivery[]>>(\n `/endpoints/${endpointId}/deliveries${qs ? `?${qs}` : ''}`\n );\n return { deliveries: res.data, total: res.meta.total || 0 };\n }, [request]);\n\n const getDelivery = useCallback(async (endpointId: string, deliveryId: string) => {\n const res = await request<PortalApiResponse<PortalDeliveryDetail>>(\n `/endpoints/${endpointId}/deliveries/${deliveryId}`\n );\n return res.data;\n }, [request]);\n\n const retryDelivery = useCallback(async (endpointId: string, deliveryId: string) => {\n await request(`/endpoints/${endpointId}/deliveries/${deliveryId}/retry`, {\n method: 'POST',\n });\n }, [request]);\n\n return {\n listEventTypes,\n listEndpoints,\n createEndpoint,\n updateEndpoint,\n deleteEndpoint,\n rotateSecret,\n listDeliveries,\n getDelivery,\n retryDelivery,\n };\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport type { PortalEndpoint, PortalEventType } from '../types';\nimport type { usePortalApi } from '../hooks/usePortalApi';\n\ninterface EndpointListProps {\n api: ReturnType<typeof usePortalApi>;\n eventTypes: PortalEventType[];\n onSelect: (endpoint: PortalEndpoint) => void;\n onCreated?: (endpoint: PortalEndpoint) => void;\n onDeleted?: (endpoint: PortalEndpoint) => void;\n onUpdated?: (endpoint: PortalEndpoint) => void;\n onError?: (error: Error) => void;\n}\n\nexport function EndpointList({\n api,\n eventTypes,\n onSelect,\n onCreated,\n onDeleted,\n onUpdated,\n onError,\n}: EndpointListProps) {\n const [endpoints, setEndpoints] = useState<PortalEndpoint[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [showCreate, setShowCreate] = useState(false);\n const [newUrl, setNewUrl] = useState('');\n const [newEvents, setNewEvents] = useState<string[]>([]);\n const [newDesc, setNewDesc] = useState('');\n const [isCreating, setIsCreating] = useState(false);\n const [createdSecret, setCreatedSecret] = useState<string | null>(null);\n\n const fetchEndpoints = useCallback(async () => {\n try {\n setIsLoading(true);\n const result = await api.listEndpoints(100, 0);\n setEndpoints(result.endpoints);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to load endpoints'));\n } finally {\n setIsLoading(false);\n }\n }, [api, onError]);\n\n useEffect(() => { fetchEndpoints(); }, [fetchEndpoints]);\n\n const handleCreate = async () => {\n if (!newUrl || newEvents.length === 0) return;\n setIsCreating(true);\n try {\n const endpoint = await api.createEndpoint({\n url: newUrl,\n events: newEvents,\n description: newDesc || undefined,\n });\n setCreatedSecret(endpoint.secret);\n setNewUrl('');\n setNewEvents([]);\n setNewDesc('');\n await fetchEndpoints();\n onCreated?.(endpoint);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to create endpoint'));\n } finally {\n setIsCreating(false);\n }\n };\n\n const handleDelete = async (ep: PortalEndpoint) => {\n try {\n await api.deleteEndpoint(ep.id);\n await fetchEndpoints();\n onDeleted?.(ep);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to delete endpoint'));\n }\n };\n\n const handleToggleStatus = async (ep: PortalEndpoint) => {\n const newStatus = ep.status === 'active' ? 'paused' : 'active';\n try {\n const updated = await api.updateEndpoint(ep.id, { status: newStatus });\n await fetchEndpoints();\n onUpdated?.(updated);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to update endpoint'));\n }\n };\n\n const toggleEvent = (eventType: string) => {\n setNewEvents(prev =>\n prev.includes(eventType) ? prev.filter(e => e !== eventType) : [...prev, eventType]\n );\n };\n\n const statusBadgeClass = (status: string) => {\n switch (status) {\n case 'active': return 'zwp-badge zwp-badge--green';\n case 'paused': return 'zwp-badge zwp-badge--yellow';\n case 'disabled': return 'zwp-badge zwp-badge--red';\n default: return 'zwp-badge';\n }\n };\n\n if (isLoading) {\n return <div className=\"zwp-loading\">Loading endpoints...</div>;\n }\n\n return (\n <div className=\"zwp-endpoint-list\">\n <div className=\"zwp-section-header\">\n <h3 className=\"zwp-heading\">Endpoints</h3>\n <button\n className=\"zwp-btn zwp-btn--primary\"\n onClick={() => { setShowCreate(!showCreate); setCreatedSecret(null); }}\n >\n {showCreate ? 'Cancel' : 'Add Endpoint'}\n </button>\n </div>\n\n {createdSecret && (\n <div className=\"zwp-alert zwp-alert--warning\">\n <strong>Signing Secret</strong>\n <p>Store this secret securely. It will not be shown again.</p>\n <code className=\"zwp-secret\">{createdSecret}</code>\n <button\n className=\"zwp-btn zwp-btn--sm\"\n onClick={() => { navigator.clipboard.writeText(createdSecret); }}\n >\n Copy\n </button>\n </div>\n )}\n\n {showCreate && (\n <div className=\"zwp-create-form\">\n <div className=\"zwp-field\">\n <label className=\"zwp-label\">URL</label>\n <input\n className=\"zwp-input\"\n type=\"url\"\n placeholder=\"https://your-app.com/webhooks\"\n value={newUrl}\n onChange={e => setNewUrl(e.target.value)}\n />\n </div>\n <div className=\"zwp-field\">\n <label className=\"zwp-label\">Description (optional)</label>\n <input\n className=\"zwp-input\"\n type=\"text\"\n placeholder=\"Production endpoint\"\n value={newDesc}\n onChange={e => setNewDesc(e.target.value)}\n />\n </div>\n <div className=\"zwp-field\">\n <label className=\"zwp-label\">Events</label>\n <div className=\"zwp-event-picker\">\n {eventTypes.map(et => (\n <label key={et.event_type} className=\"zwp-checkbox-label\">\n <input\n type=\"checkbox\"\n checked={newEvents.includes(et.event_type)}\n onChange={() => toggleEvent(et.event_type)}\n />\n <span className=\"zwp-event-name\">{et.name}</span>\n <span className=\"zwp-event-type\">{et.event_type}</span>\n </label>\n ))}\n </div>\n </div>\n <button\n className=\"zwp-btn zwp-btn--primary\"\n onClick={handleCreate}\n disabled={isCreating || !newUrl || newEvents.length === 0}\n >\n {isCreating ? 'Creating...' : 'Create Endpoint'}\n </button>\n </div>\n )}\n\n {endpoints.length === 0 ? (\n <div className=\"zwp-empty\">\n <p>No endpoints configured yet.</p>\n <p>Add an endpoint to start receiving webhook deliveries.</p>\n </div>\n ) : (\n <div className=\"zwp-list\">\n {endpoints.map(ep => (\n <div key={ep.id} className=\"zwp-endpoint-card\" onClick={() => onSelect(ep)}>\n <div className=\"zwp-endpoint-header\">\n <code className=\"zwp-endpoint-url\">{ep.url}</code>\n <span className={statusBadgeClass(ep.status)}>{ep.status}</span>\n </div>\n {ep.description && (\n <p className=\"zwp-endpoint-desc\">{ep.description}</p>\n )}\n <div className=\"zwp-endpoint-meta\">\n <span>{ep.events.length} event{ep.events.length !== 1 ? 's' : ''}</span>\n <span>Created {new Date(ep.created_at).toLocaleDateString()}</span>\n </div>\n <div className=\"zwp-endpoint-actions\" onClick={e => e.stopPropagation()}>\n <button\n className=\"zwp-btn zwp-btn--sm zwp-btn--ghost\"\n onClick={() => handleToggleStatus(ep)}\n >\n {ep.status === 'active' ? 'Pause' : 'Resume'}\n </button>\n <button\n className=\"zwp-btn zwp-btn--sm zwp-btn--danger\"\n onClick={() => handleDelete(ep)}\n >\n Delete\n </button>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport type { PortalEndpoint, PortalDelivery } from '../types';\nimport type { usePortalApi } from '../hooks/usePortalApi';\n\ninterface EndpointDetailProps {\n api: ReturnType<typeof usePortalApi>;\n endpoint: PortalEndpoint;\n onBack: () => void;\n onRetried?: (deliveryId: string) => void;\n onError?: (error: Error) => void;\n}\n\nexport function EndpointDetail({ api, endpoint, onBack, onRetried, onError }: EndpointDetailProps) {\n const [deliveries, setDeliveries] = useState<PortalDelivery[]>([]);\n const [total, setTotal] = useState(0);\n const [isLoading, setIsLoading] = useState(true);\n const [statusFilter, setStatusFilter] = useState('');\n const [page, setPage] = useState(0);\n const [retrying, setRetrying] = useState<string | null>(null);\n const PAGE_SIZE = 20;\n\n const fetchDeliveries = useCallback(async () => {\n try {\n setIsLoading(true);\n const result = await api.listDeliveries(endpoint.id, {\n limit: PAGE_SIZE,\n offset: page * PAGE_SIZE,\n status: statusFilter || undefined,\n });\n setDeliveries(result.deliveries);\n setTotal(result.total);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to load deliveries'));\n } finally {\n setIsLoading(false);\n }\n }, [api, endpoint.id, page, statusFilter, onError]);\n\n useEffect(() => { fetchDeliveries(); }, [fetchDeliveries]);\n\n const handleRetry = async (deliveryId: string) => {\n setRetrying(deliveryId);\n try {\n await api.retryDelivery(endpoint.id, deliveryId);\n await fetchDeliveries();\n onRetried?.(deliveryId);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to retry delivery'));\n } finally {\n setRetrying(null);\n }\n };\n\n const handleRotateSecret = async () => {\n try {\n const secret = await api.rotateSecret(endpoint.id);\n alert(`New secret: ${secret}\\n\\nStore this securely. It will not be shown again.`);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to rotate secret'));\n }\n };\n\n const statusBadgeClass = (status: string) => {\n switch (status) {\n case 'delivered': return 'zwp-badge zwp-badge--green';\n case 'failed': case 'exhausted': return 'zwp-badge zwp-badge--red';\n case 'retrying': case 'pending': return 'zwp-badge zwp-badge--yellow';\n default: return 'zwp-badge';\n }\n };\n\n const canRetry = (status: string) => status === 'failed' || status === 'exhausted';\n const totalPages = Math.ceil(total / PAGE_SIZE);\n\n return (\n <div className=\"zwp-endpoint-detail\">\n <button className=\"zwp-btn zwp-btn--ghost zwp-back-btn\" onClick={onBack}>\n ← Back to endpoints\n </button>\n\n <div className=\"zwp-detail-header\">\n <div>\n <code className=\"zwp-endpoint-url\">{endpoint.url}</code>\n <div className=\"zwp-endpoint-meta\">\n <span>{endpoint.events.length} event{endpoint.events.length !== 1 ? 's' : ''}</span>\n <span>Status: {endpoint.status}</span>\n </div>\n </div>\n <button className=\"zwp-btn zwp-btn--sm\" onClick={handleRotateSecret}>\n Rotate Secret\n </button>\n </div>\n\n <div className=\"zwp-events-list\">\n <h4 className=\"zwp-subheading\">Subscribed Events</h4>\n <div className=\"zwp-tags\">\n {endpoint.events.map(e => (\n <span key={e} className=\"zwp-tag\">{e}</span>\n ))}\n </div>\n </div>\n\n <div className=\"zwp-deliveries\">\n <div className=\"zwp-section-header\">\n <h4 className=\"zwp-subheading\">Delivery Log</h4>\n <select\n className=\"zwp-select\"\n value={statusFilter}\n onChange={e => { setStatusFilter(e.target.value); setPage(0); }}\n >\n <option value=\"\">All statuses</option>\n <option value=\"delivered\">Delivered</option>\n <option value=\"failed\">Failed</option>\n <option value=\"exhausted\">Exhausted</option>\n <option value=\"retrying\">Retrying</option>\n <option value=\"pending\">Pending</option>\n </select>\n </div>\n\n {isLoading ? (\n <div className=\"zwp-loading\">Loading deliveries...</div>\n ) : deliveries.length === 0 ? (\n <div className=\"zwp-empty\">\n <p>No deliveries yet.</p>\n </div>\n ) : (\n <>\n <table className=\"zwp-table\">\n <thead>\n <tr>\n <th>Event</th>\n <th>Status</th>\n <th>Attempts</th>\n <th>Response</th>\n <th>Time</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n {deliveries.map(d => (\n <tr key={d.id}>\n <td><code className=\"zwp-event-code\">{d.event_type}</code></td>\n <td><span className={statusBadgeClass(d.status)}>{d.status}</span></td>\n <td>{d.attempts}/{d.max_attempts}</td>\n <td>{d.last_response_status || '—'}</td>\n <td className=\"zwp-time\">\n {d.last_attempted_at\n ? new Date(d.last_attempted_at).toLocaleString()\n : new Date(d.created_at).toLocaleString()}\n </td>\n <td>\n {canRetry(d.status) && (\n <button\n className=\"zwp-btn zwp-btn--sm\"\n onClick={() => handleRetry(d.id)}\n disabled={retrying === d.id}\n >\n {retrying === d.id ? '...' : 'Retry'}\n </button>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n\n {totalPages > 1 && (\n <div className=\"zwp-pagination\">\n <button\n className=\"zwp-btn zwp-btn--sm\"\n onClick={() => setPage(p => p - 1)}\n disabled={page === 0}\n >\n Previous\n </button>\n <span className=\"zwp-page-info\">\n Page {page + 1} of {totalPages}\n </span>\n <button\n className=\"zwp-btn zwp-btn--sm\"\n onClick={() => setPage(p => p + 1)}\n disabled={page >= totalPages - 1}\n >\n Next\n </button>\n </div>\n )}\n </>\n )}\n </div>\n </div>\n );\n}\n","import { useState, useEffect } from 'react';\nimport type { WebhookPortalProps, PortalEndpoint, PortalEventType } from '../types';\nimport { usePortalApi } from '../hooks/usePortalApi';\nimport { EndpointList } from './EndpointList';\nimport { EndpointDetail } from './EndpointDetail';\n\nconst PREVIEW_ENDPOINTS: PortalEndpoint[] = [\n {\n id: 'preview-1',\n url: 'https://api.example.com/webhooks',\n description: 'Production endpoint',\n events: ['order.created', 'order.updated', 'payment.completed'],\n status: 'active',\n consecutive_failures: 0,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n },\n {\n id: 'preview-2',\n url: 'https://staging.example.com/hooks',\n events: ['order.created'],\n status: 'paused',\n consecutive_failures: 0,\n created_at: new Date(Date.now() - 86400000).toISOString(),\n updated_at: new Date(Date.now() - 86400000).toISOString(),\n },\n];\n\nfunction PreviewEndpointList() {\n return (\n <div className=\"zwp-endpoint-list\">\n <div className=\"zwp-section-header\">\n <h3 className=\"zwp-heading\">Endpoints</h3>\n <button className=\"zwp-btn zwp-btn--primary\" disabled>Add Endpoint</button>\n </div>\n <div className=\"zwp-list\">\n {PREVIEW_ENDPOINTS.map(ep => (\n <div key={ep.id} className=\"zwp-endpoint-card\" style={{ cursor: 'default' }}>\n <div className=\"zwp-endpoint-header\">\n <code className=\"zwp-endpoint-url\">{ep.url}</code>\n <span className={`zwp-badge ${ep.status === 'active' ? 'zwp-badge--green' : 'zwp-badge--yellow'}`}>\n {ep.status}\n </span>\n </div>\n {ep.description && <p className=\"zwp-endpoint-desc\">{ep.description}</p>}\n <div className=\"zwp-endpoint-meta\">\n <span>{ep.events.length} event{ep.events.length !== 1 ? 's' : ''}</span>\n <span>Created {new Date(ep.created_at).toLocaleDateString()}</span>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nexport function WebhookPortal({\n token,\n baseUrl,\n theme,\n preview,\n onEndpointCreated,\n onEndpointDeleted,\n onEndpointUpdated,\n onDeliveryRetried,\n onError,\n className,\n}: WebhookPortalProps) {\n const api = usePortalApi({ token, baseUrl });\n const [eventTypes, setEventTypes] = useState<PortalEventType[]>([]);\n const [selectedEndpoint, setSelectedEndpoint] = useState<PortalEndpoint | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (preview) return;\n api.listEventTypes()\n .then(setEventTypes)\n .catch(err => {\n const e = err instanceof Error ? err : new Error('Failed to load event types');\n setError(e.message);\n onError?.(e);\n });\n }, [api, onError, preview]);\n\n const handleError = (err: Error) => {\n setError(err.message);\n onError?.(err);\n setTimeout(() => setError(null), 5000);\n };\n\n const style: Record<string, string> = {};\n if (theme?.accent) {\n style['--zwp-accent'] = theme.accent;\n }\n if (theme?.borderRadius !== undefined) {\n style['--zwp-radius'] = `${theme.borderRadius}px`;\n }\n\n const themeClass = theme?.mode === 'dark' ? 'zwp-dark' : 'zwp-light';\n\n return (\n <div\n className={`zwp-portal ${themeClass} ${className || ''}`}\n style={style}\n >\n {error && (\n <div className=\"zwp-alert zwp-alert--error\">\n {error}\n <button className=\"zwp-alert-close\" onClick={() => setError(null)}>×</button>\n </div>\n )}\n\n {preview ? (\n <PreviewEndpointList />\n ) : selectedEndpoint ? (\n <EndpointDetail\n api={api}\n endpoint={selectedEndpoint}\n onBack={() => setSelectedEndpoint(null)}\n onRetried={onDeliveryRetried}\n onError={handleError}\n />\n ) : (\n <EndpointList\n api={api}\n eventTypes={eventTypes}\n onSelect={setSelectedEndpoint}\n onCreated={onEndpointCreated}\n onDeleted={onEndpointDeleted}\n onUpdated={onEndpointUpdated}\n onError={handleError}\n />\n )}\n </div>\n );\n}\n"],"names":["useRef","useCallback","useState","useEffect","_jsx","_jsxs","_Fragment"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface PortalEventType {
|
|
4
|
+
event_type: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
category?: string;
|
|
8
|
+
example_payload?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
interface PortalEndpoint {
|
|
11
|
+
id: string;
|
|
12
|
+
url: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
events: string[];
|
|
15
|
+
status: 'active' | 'paused' | 'disabled';
|
|
16
|
+
retry_policy?: {
|
|
17
|
+
max_attempts?: number;
|
|
18
|
+
intervals?: number[];
|
|
19
|
+
};
|
|
20
|
+
consecutive_failures?: number;
|
|
21
|
+
last_failure_at?: string;
|
|
22
|
+
disabled_at?: string;
|
|
23
|
+
disabled_reason?: string;
|
|
24
|
+
created_at: string;
|
|
25
|
+
updated_at: string;
|
|
26
|
+
}
|
|
27
|
+
interface PortalEndpointWithSecret extends PortalEndpoint {
|
|
28
|
+
secret: string;
|
|
29
|
+
}
|
|
30
|
+
interface PortalDelivery {
|
|
31
|
+
id: string;
|
|
32
|
+
event_id: string;
|
|
33
|
+
event_type: string;
|
|
34
|
+
status: 'pending' | 'delivering' | 'delivered' | 'failed' | 'retrying' | 'exhausted';
|
|
35
|
+
attempts: number;
|
|
36
|
+
max_attempts: number;
|
|
37
|
+
last_response_status?: number;
|
|
38
|
+
latency_ms?: number;
|
|
39
|
+
last_error?: string;
|
|
40
|
+
first_attempted_at?: string;
|
|
41
|
+
last_attempted_at?: string;
|
|
42
|
+
completed_at?: string;
|
|
43
|
+
created_at: string;
|
|
44
|
+
}
|
|
45
|
+
interface PortalDeliveryDetail extends PortalDelivery {
|
|
46
|
+
payload?: Record<string, unknown>;
|
|
47
|
+
last_response_body?: string;
|
|
48
|
+
}
|
|
49
|
+
interface PortalTheme {
|
|
50
|
+
mode?: 'light' | 'dark';
|
|
51
|
+
accent?: string;
|
|
52
|
+
borderRadius?: number;
|
|
53
|
+
}
|
|
54
|
+
interface WebhookPortalProps {
|
|
55
|
+
token: string;
|
|
56
|
+
baseUrl?: string;
|
|
57
|
+
theme?: PortalTheme;
|
|
58
|
+
locale?: string;
|
|
59
|
+
/** Render with mock data and no API calls. Useful for previewing theme/accent. */
|
|
60
|
+
preview?: boolean;
|
|
61
|
+
onEndpointCreated?: (endpoint: PortalEndpoint) => void;
|
|
62
|
+
onEndpointDeleted?: (endpoint: PortalEndpoint) => void;
|
|
63
|
+
onEndpointUpdated?: (endpoint: PortalEndpoint) => void;
|
|
64
|
+
onDeliveryRetried?: (deliveryId: string) => void;
|
|
65
|
+
onError?: (error: Error) => void;
|
|
66
|
+
className?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
declare function WebhookPortal({ token, baseUrl, theme, preview, onEndpointCreated, onEndpointDeleted, onEndpointUpdated, onDeliveryRetried, onError, className, }: WebhookPortalProps): react_jsx_runtime.JSX.Element;
|
|
70
|
+
|
|
71
|
+
interface UsePortalApiOptions {
|
|
72
|
+
token: string;
|
|
73
|
+
baseUrl?: string;
|
|
74
|
+
}
|
|
75
|
+
declare function usePortalApi({ token, baseUrl }: UsePortalApiOptions): {
|
|
76
|
+
listEventTypes: () => Promise<PortalEventType[]>;
|
|
77
|
+
listEndpoints: (limit?: number, offset?: number) => Promise<{
|
|
78
|
+
endpoints: PortalEndpoint[];
|
|
79
|
+
total: number;
|
|
80
|
+
}>;
|
|
81
|
+
createEndpoint: (data: {
|
|
82
|
+
url: string;
|
|
83
|
+
events: string[];
|
|
84
|
+
description?: string;
|
|
85
|
+
}) => Promise<PortalEndpointWithSecret>;
|
|
86
|
+
updateEndpoint: (endpointId: string, data: {
|
|
87
|
+
url?: string;
|
|
88
|
+
events?: string[];
|
|
89
|
+
status?: "active" | "paused" | "disabled";
|
|
90
|
+
description?: string;
|
|
91
|
+
}) => Promise<PortalEndpoint>;
|
|
92
|
+
deleteEndpoint: (endpointId: string) => Promise<void>;
|
|
93
|
+
rotateSecret: (endpointId: string) => Promise<string>;
|
|
94
|
+
listDeliveries: (endpointId: string, params?: {
|
|
95
|
+
limit?: number;
|
|
96
|
+
offset?: number;
|
|
97
|
+
status?: string;
|
|
98
|
+
}) => Promise<{
|
|
99
|
+
deliveries: PortalDelivery[];
|
|
100
|
+
total: number;
|
|
101
|
+
}>;
|
|
102
|
+
getDelivery: (endpointId: string, deliveryId: string) => Promise<PortalDeliveryDetail>;
|
|
103
|
+
retryDelivery: (endpointId: string, deliveryId: string) => Promise<void>;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export { WebhookPortal, usePortalApi };
|
|
107
|
+
export type { PortalDelivery, PortalDeliveryDetail, PortalEndpoint, PortalEndpointWithSecret, PortalEventType, PortalTheme, WebhookPortalProps };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useRef, useCallback, useState, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_BASE_URL = 'https://api.zyphr.dev/v1/waas-portal';
|
|
5
|
+
function usePortalApi({ token, baseUrl }) {
|
|
6
|
+
const base = baseUrl || DEFAULT_BASE_URL;
|
|
7
|
+
const tokenRef = useRef(token);
|
|
8
|
+
tokenRef.current = token;
|
|
9
|
+
const request = useCallback(async (path, options) => {
|
|
10
|
+
const res = await fetch(`${base}${path}`, {
|
|
11
|
+
...options,
|
|
12
|
+
headers: {
|
|
13
|
+
'Content-Type': 'application/json',
|
|
14
|
+
Authorization: `Bearer ${tokenRef.current}`,
|
|
15
|
+
...options?.headers,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
if (!res.ok) {
|
|
19
|
+
const body = await res.json().catch(() => ({}));
|
|
20
|
+
throw new Error(body?.error?.message || `Request failed: ${res.status}`);
|
|
21
|
+
}
|
|
22
|
+
if (res.status === 204)
|
|
23
|
+
return undefined;
|
|
24
|
+
return res.json();
|
|
25
|
+
}, [base]);
|
|
26
|
+
const listEventTypes = useCallback(async () => {
|
|
27
|
+
const res = await request('/event-types');
|
|
28
|
+
return res.data;
|
|
29
|
+
}, [request]);
|
|
30
|
+
const listEndpoints = useCallback(async (limit = 20, offset = 0) => {
|
|
31
|
+
const res = await request(`/endpoints?limit=${limit}&offset=${offset}`);
|
|
32
|
+
return { endpoints: res.data, total: res.meta.total || 0 };
|
|
33
|
+
}, [request]);
|
|
34
|
+
const createEndpoint = useCallback(async (data) => {
|
|
35
|
+
const res = await request('/endpoints', {
|
|
36
|
+
method: 'POST',
|
|
37
|
+
body: JSON.stringify(data),
|
|
38
|
+
});
|
|
39
|
+
return res.data;
|
|
40
|
+
}, [request]);
|
|
41
|
+
const updateEndpoint = useCallback(async (endpointId, data) => {
|
|
42
|
+
const res = await request(`/endpoints/${endpointId}`, {
|
|
43
|
+
method: 'PUT',
|
|
44
|
+
body: JSON.stringify(data),
|
|
45
|
+
});
|
|
46
|
+
return res.data;
|
|
47
|
+
}, [request]);
|
|
48
|
+
const deleteEndpoint = useCallback(async (endpointId) => {
|
|
49
|
+
await request(`/endpoints/${endpointId}`, { method: 'DELETE' });
|
|
50
|
+
}, [request]);
|
|
51
|
+
const rotateSecret = useCallback(async (endpointId) => {
|
|
52
|
+
const res = await request(`/endpoints/${endpointId}/rotate-secret`, { method: 'POST' });
|
|
53
|
+
return res.data.secret;
|
|
54
|
+
}, [request]);
|
|
55
|
+
const listDeliveries = useCallback(async (endpointId, params) => {
|
|
56
|
+
const query = new URLSearchParams();
|
|
57
|
+
if (params?.limit)
|
|
58
|
+
query.set('limit', String(params.limit));
|
|
59
|
+
if (params?.offset)
|
|
60
|
+
query.set('offset', String(params.offset));
|
|
61
|
+
if (params?.status)
|
|
62
|
+
query.set('status', params.status);
|
|
63
|
+
const qs = query.toString();
|
|
64
|
+
const res = await request(`/endpoints/${endpointId}/deliveries${qs ? `?${qs}` : ''}`);
|
|
65
|
+
return { deliveries: res.data, total: res.meta.total || 0 };
|
|
66
|
+
}, [request]);
|
|
67
|
+
const getDelivery = useCallback(async (endpointId, deliveryId) => {
|
|
68
|
+
const res = await request(`/endpoints/${endpointId}/deliveries/${deliveryId}`);
|
|
69
|
+
return res.data;
|
|
70
|
+
}, [request]);
|
|
71
|
+
const retryDelivery = useCallback(async (endpointId, deliveryId) => {
|
|
72
|
+
await request(`/endpoints/${endpointId}/deliveries/${deliveryId}/retry`, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
});
|
|
75
|
+
}, [request]);
|
|
76
|
+
return {
|
|
77
|
+
listEventTypes,
|
|
78
|
+
listEndpoints,
|
|
79
|
+
createEndpoint,
|
|
80
|
+
updateEndpoint,
|
|
81
|
+
deleteEndpoint,
|
|
82
|
+
rotateSecret,
|
|
83
|
+
listDeliveries,
|
|
84
|
+
getDelivery,
|
|
85
|
+
retryDelivery,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function EndpointList({ api, eventTypes, onSelect, onCreated, onDeleted, onUpdated, onError, }) {
|
|
90
|
+
const [endpoints, setEndpoints] = useState([]);
|
|
91
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
92
|
+
const [showCreate, setShowCreate] = useState(false);
|
|
93
|
+
const [newUrl, setNewUrl] = useState('');
|
|
94
|
+
const [newEvents, setNewEvents] = useState([]);
|
|
95
|
+
const [newDesc, setNewDesc] = useState('');
|
|
96
|
+
const [isCreating, setIsCreating] = useState(false);
|
|
97
|
+
const [createdSecret, setCreatedSecret] = useState(null);
|
|
98
|
+
const fetchEndpoints = useCallback(async () => {
|
|
99
|
+
try {
|
|
100
|
+
setIsLoading(true);
|
|
101
|
+
const result = await api.listEndpoints(100, 0);
|
|
102
|
+
setEndpoints(result.endpoints);
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
onError?.(err instanceof Error ? err : new Error('Failed to load endpoints'));
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
setIsLoading(false);
|
|
109
|
+
}
|
|
110
|
+
}, [api, onError]);
|
|
111
|
+
useEffect(() => { fetchEndpoints(); }, [fetchEndpoints]);
|
|
112
|
+
const handleCreate = async () => {
|
|
113
|
+
if (!newUrl || newEvents.length === 0)
|
|
114
|
+
return;
|
|
115
|
+
setIsCreating(true);
|
|
116
|
+
try {
|
|
117
|
+
const endpoint = await api.createEndpoint({
|
|
118
|
+
url: newUrl,
|
|
119
|
+
events: newEvents,
|
|
120
|
+
description: newDesc || undefined,
|
|
121
|
+
});
|
|
122
|
+
setCreatedSecret(endpoint.secret);
|
|
123
|
+
setNewUrl('');
|
|
124
|
+
setNewEvents([]);
|
|
125
|
+
setNewDesc('');
|
|
126
|
+
await fetchEndpoints();
|
|
127
|
+
onCreated?.(endpoint);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
onError?.(err instanceof Error ? err : new Error('Failed to create endpoint'));
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
setIsCreating(false);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const handleDelete = async (ep) => {
|
|
137
|
+
try {
|
|
138
|
+
await api.deleteEndpoint(ep.id);
|
|
139
|
+
await fetchEndpoints();
|
|
140
|
+
onDeleted?.(ep);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
onError?.(err instanceof Error ? err : new Error('Failed to delete endpoint'));
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
const handleToggleStatus = async (ep) => {
|
|
147
|
+
const newStatus = ep.status === 'active' ? 'paused' : 'active';
|
|
148
|
+
try {
|
|
149
|
+
const updated = await api.updateEndpoint(ep.id, { status: newStatus });
|
|
150
|
+
await fetchEndpoints();
|
|
151
|
+
onUpdated?.(updated);
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
onError?.(err instanceof Error ? err : new Error('Failed to update endpoint'));
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const toggleEvent = (eventType) => {
|
|
158
|
+
setNewEvents(prev => prev.includes(eventType) ? prev.filter(e => e !== eventType) : [...prev, eventType]);
|
|
159
|
+
};
|
|
160
|
+
const statusBadgeClass = (status) => {
|
|
161
|
+
switch (status) {
|
|
162
|
+
case 'active': return 'zwp-badge zwp-badge--green';
|
|
163
|
+
case 'paused': return 'zwp-badge zwp-badge--yellow';
|
|
164
|
+
case 'disabled': return 'zwp-badge zwp-badge--red';
|
|
165
|
+
default: return 'zwp-badge';
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
if (isLoading) {
|
|
169
|
+
return jsx("div", { className: "zwp-loading", children: "Loading endpoints..." });
|
|
170
|
+
}
|
|
171
|
+
return (jsxs("div", { className: "zwp-endpoint-list", children: [jsxs("div", { className: "zwp-section-header", children: [jsx("h3", { className: "zwp-heading", children: "Endpoints" }), jsx("button", { className: "zwp-btn zwp-btn--primary", onClick: () => { setShowCreate(!showCreate); setCreatedSecret(null); }, children: showCreate ? 'Cancel' : 'Add Endpoint' })] }), createdSecret && (jsxs("div", { className: "zwp-alert zwp-alert--warning", children: [jsx("strong", { children: "Signing Secret" }), jsx("p", { children: "Store this secret securely. It will not be shown again." }), jsx("code", { className: "zwp-secret", children: createdSecret }), jsx("button", { className: "zwp-btn zwp-btn--sm", onClick: () => { navigator.clipboard.writeText(createdSecret); }, children: "Copy" })] })), showCreate && (jsxs("div", { className: "zwp-create-form", children: [jsxs("div", { className: "zwp-field", children: [jsx("label", { className: "zwp-label", children: "URL" }), jsx("input", { className: "zwp-input", type: "url", placeholder: "https://your-app.com/webhooks", value: newUrl, onChange: e => setNewUrl(e.target.value) })] }), jsxs("div", { className: "zwp-field", children: [jsx("label", { className: "zwp-label", children: "Description (optional)" }), jsx("input", { className: "zwp-input", type: "text", placeholder: "Production endpoint", value: newDesc, onChange: e => setNewDesc(e.target.value) })] }), jsxs("div", { className: "zwp-field", children: [jsx("label", { className: "zwp-label", children: "Events" }), jsx("div", { className: "zwp-event-picker", children: eventTypes.map(et => (jsxs("label", { className: "zwp-checkbox-label", children: [jsx("input", { type: "checkbox", checked: newEvents.includes(et.event_type), onChange: () => toggleEvent(et.event_type) }), jsx("span", { className: "zwp-event-name", children: et.name }), jsx("span", { className: "zwp-event-type", children: et.event_type })] }, et.event_type))) })] }), jsx("button", { className: "zwp-btn zwp-btn--primary", onClick: handleCreate, disabled: isCreating || !newUrl || newEvents.length === 0, children: isCreating ? 'Creating...' : 'Create Endpoint' })] })), endpoints.length === 0 ? (jsxs("div", { className: "zwp-empty", children: [jsx("p", { children: "No endpoints configured yet." }), jsx("p", { children: "Add an endpoint to start receiving webhook deliveries." })] })) : (jsx("div", { className: "zwp-list", children: endpoints.map(ep => (jsxs("div", { className: "zwp-endpoint-card", onClick: () => onSelect(ep), children: [jsxs("div", { className: "zwp-endpoint-header", children: [jsx("code", { className: "zwp-endpoint-url", children: ep.url }), jsx("span", { className: statusBadgeClass(ep.status), children: ep.status })] }), ep.description && (jsx("p", { className: "zwp-endpoint-desc", children: ep.description })), jsxs("div", { className: "zwp-endpoint-meta", children: [jsxs("span", { children: [ep.events.length, " event", ep.events.length !== 1 ? 's' : ''] }), jsxs("span", { children: ["Created ", new Date(ep.created_at).toLocaleDateString()] })] }), jsxs("div", { className: "zwp-endpoint-actions", onClick: e => e.stopPropagation(), children: [jsx("button", { className: "zwp-btn zwp-btn--sm zwp-btn--ghost", onClick: () => handleToggleStatus(ep), children: ep.status === 'active' ? 'Pause' : 'Resume' }), jsx("button", { className: "zwp-btn zwp-btn--sm zwp-btn--danger", onClick: () => handleDelete(ep), children: "Delete" })] })] }, ep.id))) }))] }));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function EndpointDetail({ api, endpoint, onBack, onRetried, onError }) {
|
|
175
|
+
const [deliveries, setDeliveries] = useState([]);
|
|
176
|
+
const [total, setTotal] = useState(0);
|
|
177
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
178
|
+
const [statusFilter, setStatusFilter] = useState('');
|
|
179
|
+
const [page, setPage] = useState(0);
|
|
180
|
+
const [retrying, setRetrying] = useState(null);
|
|
181
|
+
const PAGE_SIZE = 20;
|
|
182
|
+
const fetchDeliveries = useCallback(async () => {
|
|
183
|
+
try {
|
|
184
|
+
setIsLoading(true);
|
|
185
|
+
const result = await api.listDeliveries(endpoint.id, {
|
|
186
|
+
limit: PAGE_SIZE,
|
|
187
|
+
offset: page * PAGE_SIZE,
|
|
188
|
+
status: statusFilter || undefined,
|
|
189
|
+
});
|
|
190
|
+
setDeliveries(result.deliveries);
|
|
191
|
+
setTotal(result.total);
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
onError?.(err instanceof Error ? err : new Error('Failed to load deliveries'));
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
setIsLoading(false);
|
|
198
|
+
}
|
|
199
|
+
}, [api, endpoint.id, page, statusFilter, onError]);
|
|
200
|
+
useEffect(() => { fetchDeliveries(); }, [fetchDeliveries]);
|
|
201
|
+
const handleRetry = async (deliveryId) => {
|
|
202
|
+
setRetrying(deliveryId);
|
|
203
|
+
try {
|
|
204
|
+
await api.retryDelivery(endpoint.id, deliveryId);
|
|
205
|
+
await fetchDeliveries();
|
|
206
|
+
onRetried?.(deliveryId);
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
onError?.(err instanceof Error ? err : new Error('Failed to retry delivery'));
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
setRetrying(null);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
const handleRotateSecret = async () => {
|
|
216
|
+
try {
|
|
217
|
+
const secret = await api.rotateSecret(endpoint.id);
|
|
218
|
+
alert(`New secret: ${secret}\n\nStore this securely. It will not be shown again.`);
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
onError?.(err instanceof Error ? err : new Error('Failed to rotate secret'));
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
const statusBadgeClass = (status) => {
|
|
225
|
+
switch (status) {
|
|
226
|
+
case 'delivered': return 'zwp-badge zwp-badge--green';
|
|
227
|
+
case 'failed':
|
|
228
|
+
case 'exhausted': return 'zwp-badge zwp-badge--red';
|
|
229
|
+
case 'retrying':
|
|
230
|
+
case 'pending': return 'zwp-badge zwp-badge--yellow';
|
|
231
|
+
default: return 'zwp-badge';
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
const canRetry = (status) => status === 'failed' || status === 'exhausted';
|
|
235
|
+
const totalPages = Math.ceil(total / PAGE_SIZE);
|
|
236
|
+
return (jsxs("div", { className: "zwp-endpoint-detail", children: [jsx("button", { className: "zwp-btn zwp-btn--ghost zwp-back-btn", onClick: onBack, children: "\u2190 Back to endpoints" }), jsxs("div", { className: "zwp-detail-header", children: [jsxs("div", { children: [jsx("code", { className: "zwp-endpoint-url", children: endpoint.url }), jsxs("div", { className: "zwp-endpoint-meta", children: [jsxs("span", { children: [endpoint.events.length, " event", endpoint.events.length !== 1 ? 's' : ''] }), jsxs("span", { children: ["Status: ", endpoint.status] })] })] }), jsx("button", { className: "zwp-btn zwp-btn--sm", onClick: handleRotateSecret, children: "Rotate Secret" })] }), jsxs("div", { className: "zwp-events-list", children: [jsx("h4", { className: "zwp-subheading", children: "Subscribed Events" }), jsx("div", { className: "zwp-tags", children: endpoint.events.map(e => (jsx("span", { className: "zwp-tag", children: e }, e))) })] }), jsxs("div", { className: "zwp-deliveries", children: [jsxs("div", { className: "zwp-section-header", children: [jsx("h4", { className: "zwp-subheading", children: "Delivery Log" }), jsxs("select", { className: "zwp-select", value: statusFilter, onChange: e => { setStatusFilter(e.target.value); setPage(0); }, children: [jsx("option", { value: "", children: "All statuses" }), jsx("option", { value: "delivered", children: "Delivered" }), jsx("option", { value: "failed", children: "Failed" }), jsx("option", { value: "exhausted", children: "Exhausted" }), jsx("option", { value: "retrying", children: "Retrying" }), jsx("option", { value: "pending", children: "Pending" })] })] }), isLoading ? (jsx("div", { className: "zwp-loading", children: "Loading deliveries..." })) : deliveries.length === 0 ? (jsx("div", { className: "zwp-empty", children: jsx("p", { children: "No deliveries yet." }) })) : (jsxs(Fragment, { children: [jsxs("table", { className: "zwp-table", children: [jsx("thead", { children: jsxs("tr", { children: [jsx("th", { children: "Event" }), jsx("th", { children: "Status" }), jsx("th", { children: "Attempts" }), jsx("th", { children: "Response" }), jsx("th", { children: "Time" }), jsx("th", {})] }) }), jsx("tbody", { children: deliveries.map(d => (jsxs("tr", { children: [jsx("td", { children: jsx("code", { className: "zwp-event-code", children: d.event_type }) }), jsx("td", { children: jsx("span", { className: statusBadgeClass(d.status), children: d.status }) }), jsxs("td", { children: [d.attempts, "/", d.max_attempts] }), jsx("td", { children: d.last_response_status || '—' }), jsx("td", { className: "zwp-time", children: d.last_attempted_at
|
|
237
|
+
? new Date(d.last_attempted_at).toLocaleString()
|
|
238
|
+
: new Date(d.created_at).toLocaleString() }), jsx("td", { children: canRetry(d.status) && (jsx("button", { className: "zwp-btn zwp-btn--sm", onClick: () => handleRetry(d.id), disabled: retrying === d.id, children: retrying === d.id ? '...' : 'Retry' })) })] }, d.id))) })] }), totalPages > 1 && (jsxs("div", { className: "zwp-pagination", children: [jsx("button", { className: "zwp-btn zwp-btn--sm", onClick: () => setPage(p => p - 1), disabled: page === 0, children: "Previous" }), jsxs("span", { className: "zwp-page-info", children: ["Page ", page + 1, " of ", totalPages] }), jsx("button", { className: "zwp-btn zwp-btn--sm", onClick: () => setPage(p => p + 1), disabled: page >= totalPages - 1, children: "Next" })] }))] }))] })] }));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const PREVIEW_ENDPOINTS = [
|
|
242
|
+
{
|
|
243
|
+
id: 'preview-1',
|
|
244
|
+
url: 'https://api.example.com/webhooks',
|
|
245
|
+
description: 'Production endpoint',
|
|
246
|
+
events: ['order.created', 'order.updated', 'payment.completed'],
|
|
247
|
+
status: 'active',
|
|
248
|
+
consecutive_failures: 0,
|
|
249
|
+
created_at: new Date().toISOString(),
|
|
250
|
+
updated_at: new Date().toISOString(),
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
id: 'preview-2',
|
|
254
|
+
url: 'https://staging.example.com/hooks',
|
|
255
|
+
events: ['order.created'],
|
|
256
|
+
status: 'paused',
|
|
257
|
+
consecutive_failures: 0,
|
|
258
|
+
created_at: new Date(Date.now() - 86400000).toISOString(),
|
|
259
|
+
updated_at: new Date(Date.now() - 86400000).toISOString(),
|
|
260
|
+
},
|
|
261
|
+
];
|
|
262
|
+
function PreviewEndpointList() {
|
|
263
|
+
return (jsxs("div", { className: "zwp-endpoint-list", children: [jsxs("div", { className: "zwp-section-header", children: [jsx("h3", { className: "zwp-heading", children: "Endpoints" }), jsx("button", { className: "zwp-btn zwp-btn--primary", disabled: true, children: "Add Endpoint" })] }), jsx("div", { className: "zwp-list", children: PREVIEW_ENDPOINTS.map(ep => (jsxs("div", { className: "zwp-endpoint-card", style: { cursor: 'default' }, children: [jsxs("div", { className: "zwp-endpoint-header", children: [jsx("code", { className: "zwp-endpoint-url", children: ep.url }), jsx("span", { className: `zwp-badge ${ep.status === 'active' ? 'zwp-badge--green' : 'zwp-badge--yellow'}`, children: ep.status })] }), ep.description && jsx("p", { className: "zwp-endpoint-desc", children: ep.description }), jsxs("div", { className: "zwp-endpoint-meta", children: [jsxs("span", { children: [ep.events.length, " event", ep.events.length !== 1 ? 's' : ''] }), jsxs("span", { children: ["Created ", new Date(ep.created_at).toLocaleDateString()] })] })] }, ep.id))) })] }));
|
|
264
|
+
}
|
|
265
|
+
function WebhookPortal({ token, baseUrl, theme, preview, onEndpointCreated, onEndpointDeleted, onEndpointUpdated, onDeliveryRetried, onError, className, }) {
|
|
266
|
+
const api = usePortalApi({ token, baseUrl });
|
|
267
|
+
const [eventTypes, setEventTypes] = useState([]);
|
|
268
|
+
const [selectedEndpoint, setSelectedEndpoint] = useState(null);
|
|
269
|
+
const [error, setError] = useState(null);
|
|
270
|
+
useEffect(() => {
|
|
271
|
+
if (preview)
|
|
272
|
+
return;
|
|
273
|
+
api.listEventTypes()
|
|
274
|
+
.then(setEventTypes)
|
|
275
|
+
.catch(err => {
|
|
276
|
+
const e = err instanceof Error ? err : new Error('Failed to load event types');
|
|
277
|
+
setError(e.message);
|
|
278
|
+
onError?.(e);
|
|
279
|
+
});
|
|
280
|
+
}, [api, onError, preview]);
|
|
281
|
+
const handleError = (err) => {
|
|
282
|
+
setError(err.message);
|
|
283
|
+
onError?.(err);
|
|
284
|
+
setTimeout(() => setError(null), 5000);
|
|
285
|
+
};
|
|
286
|
+
const style = {};
|
|
287
|
+
if (theme?.accent) {
|
|
288
|
+
style['--zwp-accent'] = theme.accent;
|
|
289
|
+
}
|
|
290
|
+
if (theme?.borderRadius !== undefined) {
|
|
291
|
+
style['--zwp-radius'] = `${theme.borderRadius}px`;
|
|
292
|
+
}
|
|
293
|
+
const themeClass = theme?.mode === 'dark' ? 'zwp-dark' : 'zwp-light';
|
|
294
|
+
return (jsxs("div", { className: `zwp-portal ${themeClass} ${className || ''}`, style: style, children: [error && (jsxs("div", { className: "zwp-alert zwp-alert--error", children: [error, jsx("button", { className: "zwp-alert-close", onClick: () => setError(null), children: "\u00D7" })] })), preview ? (jsx(PreviewEndpointList, {})) : selectedEndpoint ? (jsx(EndpointDetail, { api: api, endpoint: selectedEndpoint, onBack: () => setSelectedEndpoint(null), onRetried: onDeliveryRetried, onError: handleError })) : (jsx(EndpointList, { api: api, eventTypes: eventTypes, onSelect: setSelectedEndpoint, onCreated: onEndpointCreated, onDeleted: onEndpointDeleted, onUpdated: onEndpointUpdated, onError: handleError }))] }));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export { WebhookPortal, usePortalApi };
|
|
298
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/hooks/usePortalApi.ts","../src/components/EndpointList.tsx","../src/components/EndpointDetail.tsx","../src/components/WebhookPortal.tsx"],"sourcesContent":["import { useCallback, useRef } from 'react';\nimport type {\n PortalApiResponse,\n PortalEventType,\n PortalEndpoint,\n PortalEndpointWithSecret,\n PortalDelivery,\n PortalDeliveryDetail,\n} from '../types';\n\nconst DEFAULT_BASE_URL = 'https://api.zyphr.dev/v1/waas-portal';\n\ninterface UsePortalApiOptions {\n token: string;\n baseUrl?: string;\n}\n\nexport function usePortalApi({ token, baseUrl }: UsePortalApiOptions) {\n const base = baseUrl || DEFAULT_BASE_URL;\n const tokenRef = useRef(token);\n tokenRef.current = token;\n\n const request = useCallback(async <T>(path: string, options?: RequestInit): Promise<T> => {\n const res = await fetch(`${base}${path}`, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${tokenRef.current}`,\n ...options?.headers,\n },\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n throw new Error(body?.error?.message || `Request failed: ${res.status}`);\n }\n\n if (res.status === 204) return undefined as T;\n return res.json();\n }, [base]);\n\n const listEventTypes = useCallback(async () => {\n const res = await request<PortalApiResponse<PortalEventType[]>>('/event-types');\n return res.data;\n }, [request]);\n\n const listEndpoints = useCallback(async (limit = 20, offset = 0) => {\n const res = await request<PortalApiResponse<PortalEndpoint[]>>(\n `/endpoints?limit=${limit}&offset=${offset}`\n );\n return { endpoints: res.data, total: res.meta.total || 0 };\n }, [request]);\n\n const createEndpoint = useCallback(async (data: {\n url: string;\n events: string[];\n description?: string;\n }) => {\n const res = await request<PortalApiResponse<PortalEndpointWithSecret>>('/endpoints', {\n method: 'POST',\n body: JSON.stringify(data),\n });\n return res.data;\n }, [request]);\n\n const updateEndpoint = useCallback(async (endpointId: string, data: {\n url?: string;\n events?: string[];\n status?: 'active' | 'paused' | 'disabled';\n description?: string;\n }) => {\n const res = await request<PortalApiResponse<PortalEndpoint>>(`/endpoints/${endpointId}`, {\n method: 'PUT',\n body: JSON.stringify(data),\n });\n return res.data;\n }, [request]);\n\n const deleteEndpoint = useCallback(async (endpointId: string) => {\n await request(`/endpoints/${endpointId}`, { method: 'DELETE' });\n }, [request]);\n\n const rotateSecret = useCallback(async (endpointId: string) => {\n const res = await request<PortalApiResponse<{ secret: string }>>(\n `/endpoints/${endpointId}/rotate-secret`,\n { method: 'POST' }\n );\n return res.data.secret;\n }, [request]);\n\n const listDeliveries = useCallback(async (endpointId: string, params?: {\n limit?: number;\n offset?: number;\n status?: string;\n }) => {\n const query = new URLSearchParams();\n if (params?.limit) query.set('limit', String(params.limit));\n if (params?.offset) query.set('offset', String(params.offset));\n if (params?.status) query.set('status', params.status);\n const qs = query.toString();\n\n const res = await request<PortalApiResponse<PortalDelivery[]>>(\n `/endpoints/${endpointId}/deliveries${qs ? `?${qs}` : ''}`\n );\n return { deliveries: res.data, total: res.meta.total || 0 };\n }, [request]);\n\n const getDelivery = useCallback(async (endpointId: string, deliveryId: string) => {\n const res = await request<PortalApiResponse<PortalDeliveryDetail>>(\n `/endpoints/${endpointId}/deliveries/${deliveryId}`\n );\n return res.data;\n }, [request]);\n\n const retryDelivery = useCallback(async (endpointId: string, deliveryId: string) => {\n await request(`/endpoints/${endpointId}/deliveries/${deliveryId}/retry`, {\n method: 'POST',\n });\n }, [request]);\n\n return {\n listEventTypes,\n listEndpoints,\n createEndpoint,\n updateEndpoint,\n deleteEndpoint,\n rotateSecret,\n listDeliveries,\n getDelivery,\n retryDelivery,\n };\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport type { PortalEndpoint, PortalEventType } from '../types';\nimport type { usePortalApi } from '../hooks/usePortalApi';\n\ninterface EndpointListProps {\n api: ReturnType<typeof usePortalApi>;\n eventTypes: PortalEventType[];\n onSelect: (endpoint: PortalEndpoint) => void;\n onCreated?: (endpoint: PortalEndpoint) => void;\n onDeleted?: (endpoint: PortalEndpoint) => void;\n onUpdated?: (endpoint: PortalEndpoint) => void;\n onError?: (error: Error) => void;\n}\n\nexport function EndpointList({\n api,\n eventTypes,\n onSelect,\n onCreated,\n onDeleted,\n onUpdated,\n onError,\n}: EndpointListProps) {\n const [endpoints, setEndpoints] = useState<PortalEndpoint[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [showCreate, setShowCreate] = useState(false);\n const [newUrl, setNewUrl] = useState('');\n const [newEvents, setNewEvents] = useState<string[]>([]);\n const [newDesc, setNewDesc] = useState('');\n const [isCreating, setIsCreating] = useState(false);\n const [createdSecret, setCreatedSecret] = useState<string | null>(null);\n\n const fetchEndpoints = useCallback(async () => {\n try {\n setIsLoading(true);\n const result = await api.listEndpoints(100, 0);\n setEndpoints(result.endpoints);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to load endpoints'));\n } finally {\n setIsLoading(false);\n }\n }, [api, onError]);\n\n useEffect(() => { fetchEndpoints(); }, [fetchEndpoints]);\n\n const handleCreate = async () => {\n if (!newUrl || newEvents.length === 0) return;\n setIsCreating(true);\n try {\n const endpoint = await api.createEndpoint({\n url: newUrl,\n events: newEvents,\n description: newDesc || undefined,\n });\n setCreatedSecret(endpoint.secret);\n setNewUrl('');\n setNewEvents([]);\n setNewDesc('');\n await fetchEndpoints();\n onCreated?.(endpoint);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to create endpoint'));\n } finally {\n setIsCreating(false);\n }\n };\n\n const handleDelete = async (ep: PortalEndpoint) => {\n try {\n await api.deleteEndpoint(ep.id);\n await fetchEndpoints();\n onDeleted?.(ep);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to delete endpoint'));\n }\n };\n\n const handleToggleStatus = async (ep: PortalEndpoint) => {\n const newStatus = ep.status === 'active' ? 'paused' : 'active';\n try {\n const updated = await api.updateEndpoint(ep.id, { status: newStatus });\n await fetchEndpoints();\n onUpdated?.(updated);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to update endpoint'));\n }\n };\n\n const toggleEvent = (eventType: string) => {\n setNewEvents(prev =>\n prev.includes(eventType) ? prev.filter(e => e !== eventType) : [...prev, eventType]\n );\n };\n\n const statusBadgeClass = (status: string) => {\n switch (status) {\n case 'active': return 'zwp-badge zwp-badge--green';\n case 'paused': return 'zwp-badge zwp-badge--yellow';\n case 'disabled': return 'zwp-badge zwp-badge--red';\n default: return 'zwp-badge';\n }\n };\n\n if (isLoading) {\n return <div className=\"zwp-loading\">Loading endpoints...</div>;\n }\n\n return (\n <div className=\"zwp-endpoint-list\">\n <div className=\"zwp-section-header\">\n <h3 className=\"zwp-heading\">Endpoints</h3>\n <button\n className=\"zwp-btn zwp-btn--primary\"\n onClick={() => { setShowCreate(!showCreate); setCreatedSecret(null); }}\n >\n {showCreate ? 'Cancel' : 'Add Endpoint'}\n </button>\n </div>\n\n {createdSecret && (\n <div className=\"zwp-alert zwp-alert--warning\">\n <strong>Signing Secret</strong>\n <p>Store this secret securely. It will not be shown again.</p>\n <code className=\"zwp-secret\">{createdSecret}</code>\n <button\n className=\"zwp-btn zwp-btn--sm\"\n onClick={() => { navigator.clipboard.writeText(createdSecret); }}\n >\n Copy\n </button>\n </div>\n )}\n\n {showCreate && (\n <div className=\"zwp-create-form\">\n <div className=\"zwp-field\">\n <label className=\"zwp-label\">URL</label>\n <input\n className=\"zwp-input\"\n type=\"url\"\n placeholder=\"https://your-app.com/webhooks\"\n value={newUrl}\n onChange={e => setNewUrl(e.target.value)}\n />\n </div>\n <div className=\"zwp-field\">\n <label className=\"zwp-label\">Description (optional)</label>\n <input\n className=\"zwp-input\"\n type=\"text\"\n placeholder=\"Production endpoint\"\n value={newDesc}\n onChange={e => setNewDesc(e.target.value)}\n />\n </div>\n <div className=\"zwp-field\">\n <label className=\"zwp-label\">Events</label>\n <div className=\"zwp-event-picker\">\n {eventTypes.map(et => (\n <label key={et.event_type} className=\"zwp-checkbox-label\">\n <input\n type=\"checkbox\"\n checked={newEvents.includes(et.event_type)}\n onChange={() => toggleEvent(et.event_type)}\n />\n <span className=\"zwp-event-name\">{et.name}</span>\n <span className=\"zwp-event-type\">{et.event_type}</span>\n </label>\n ))}\n </div>\n </div>\n <button\n className=\"zwp-btn zwp-btn--primary\"\n onClick={handleCreate}\n disabled={isCreating || !newUrl || newEvents.length === 0}\n >\n {isCreating ? 'Creating...' : 'Create Endpoint'}\n </button>\n </div>\n )}\n\n {endpoints.length === 0 ? (\n <div className=\"zwp-empty\">\n <p>No endpoints configured yet.</p>\n <p>Add an endpoint to start receiving webhook deliveries.</p>\n </div>\n ) : (\n <div className=\"zwp-list\">\n {endpoints.map(ep => (\n <div key={ep.id} className=\"zwp-endpoint-card\" onClick={() => onSelect(ep)}>\n <div className=\"zwp-endpoint-header\">\n <code className=\"zwp-endpoint-url\">{ep.url}</code>\n <span className={statusBadgeClass(ep.status)}>{ep.status}</span>\n </div>\n {ep.description && (\n <p className=\"zwp-endpoint-desc\">{ep.description}</p>\n )}\n <div className=\"zwp-endpoint-meta\">\n <span>{ep.events.length} event{ep.events.length !== 1 ? 's' : ''}</span>\n <span>Created {new Date(ep.created_at).toLocaleDateString()}</span>\n </div>\n <div className=\"zwp-endpoint-actions\" onClick={e => e.stopPropagation()}>\n <button\n className=\"zwp-btn zwp-btn--sm zwp-btn--ghost\"\n onClick={() => handleToggleStatus(ep)}\n >\n {ep.status === 'active' ? 'Pause' : 'Resume'}\n </button>\n <button\n className=\"zwp-btn zwp-btn--sm zwp-btn--danger\"\n onClick={() => handleDelete(ep)}\n >\n Delete\n </button>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport type { PortalEndpoint, PortalDelivery } from '../types';\nimport type { usePortalApi } from '../hooks/usePortalApi';\n\ninterface EndpointDetailProps {\n api: ReturnType<typeof usePortalApi>;\n endpoint: PortalEndpoint;\n onBack: () => void;\n onRetried?: (deliveryId: string) => void;\n onError?: (error: Error) => void;\n}\n\nexport function EndpointDetail({ api, endpoint, onBack, onRetried, onError }: EndpointDetailProps) {\n const [deliveries, setDeliveries] = useState<PortalDelivery[]>([]);\n const [total, setTotal] = useState(0);\n const [isLoading, setIsLoading] = useState(true);\n const [statusFilter, setStatusFilter] = useState('');\n const [page, setPage] = useState(0);\n const [retrying, setRetrying] = useState<string | null>(null);\n const PAGE_SIZE = 20;\n\n const fetchDeliveries = useCallback(async () => {\n try {\n setIsLoading(true);\n const result = await api.listDeliveries(endpoint.id, {\n limit: PAGE_SIZE,\n offset: page * PAGE_SIZE,\n status: statusFilter || undefined,\n });\n setDeliveries(result.deliveries);\n setTotal(result.total);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to load deliveries'));\n } finally {\n setIsLoading(false);\n }\n }, [api, endpoint.id, page, statusFilter, onError]);\n\n useEffect(() => { fetchDeliveries(); }, [fetchDeliveries]);\n\n const handleRetry = async (deliveryId: string) => {\n setRetrying(deliveryId);\n try {\n await api.retryDelivery(endpoint.id, deliveryId);\n await fetchDeliveries();\n onRetried?.(deliveryId);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to retry delivery'));\n } finally {\n setRetrying(null);\n }\n };\n\n const handleRotateSecret = async () => {\n try {\n const secret = await api.rotateSecret(endpoint.id);\n alert(`New secret: ${secret}\\n\\nStore this securely. It will not be shown again.`);\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error('Failed to rotate secret'));\n }\n };\n\n const statusBadgeClass = (status: string) => {\n switch (status) {\n case 'delivered': return 'zwp-badge zwp-badge--green';\n case 'failed': case 'exhausted': return 'zwp-badge zwp-badge--red';\n case 'retrying': case 'pending': return 'zwp-badge zwp-badge--yellow';\n default: return 'zwp-badge';\n }\n };\n\n const canRetry = (status: string) => status === 'failed' || status === 'exhausted';\n const totalPages = Math.ceil(total / PAGE_SIZE);\n\n return (\n <div className=\"zwp-endpoint-detail\">\n <button className=\"zwp-btn zwp-btn--ghost zwp-back-btn\" onClick={onBack}>\n ← Back to endpoints\n </button>\n\n <div className=\"zwp-detail-header\">\n <div>\n <code className=\"zwp-endpoint-url\">{endpoint.url}</code>\n <div className=\"zwp-endpoint-meta\">\n <span>{endpoint.events.length} event{endpoint.events.length !== 1 ? 's' : ''}</span>\n <span>Status: {endpoint.status}</span>\n </div>\n </div>\n <button className=\"zwp-btn zwp-btn--sm\" onClick={handleRotateSecret}>\n Rotate Secret\n </button>\n </div>\n\n <div className=\"zwp-events-list\">\n <h4 className=\"zwp-subheading\">Subscribed Events</h4>\n <div className=\"zwp-tags\">\n {endpoint.events.map(e => (\n <span key={e} className=\"zwp-tag\">{e}</span>\n ))}\n </div>\n </div>\n\n <div className=\"zwp-deliveries\">\n <div className=\"zwp-section-header\">\n <h4 className=\"zwp-subheading\">Delivery Log</h4>\n <select\n className=\"zwp-select\"\n value={statusFilter}\n onChange={e => { setStatusFilter(e.target.value); setPage(0); }}\n >\n <option value=\"\">All statuses</option>\n <option value=\"delivered\">Delivered</option>\n <option value=\"failed\">Failed</option>\n <option value=\"exhausted\">Exhausted</option>\n <option value=\"retrying\">Retrying</option>\n <option value=\"pending\">Pending</option>\n </select>\n </div>\n\n {isLoading ? (\n <div className=\"zwp-loading\">Loading deliveries...</div>\n ) : deliveries.length === 0 ? (\n <div className=\"zwp-empty\">\n <p>No deliveries yet.</p>\n </div>\n ) : (\n <>\n <table className=\"zwp-table\">\n <thead>\n <tr>\n <th>Event</th>\n <th>Status</th>\n <th>Attempts</th>\n <th>Response</th>\n <th>Time</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n {deliveries.map(d => (\n <tr key={d.id}>\n <td><code className=\"zwp-event-code\">{d.event_type}</code></td>\n <td><span className={statusBadgeClass(d.status)}>{d.status}</span></td>\n <td>{d.attempts}/{d.max_attempts}</td>\n <td>{d.last_response_status || '—'}</td>\n <td className=\"zwp-time\">\n {d.last_attempted_at\n ? new Date(d.last_attempted_at).toLocaleString()\n : new Date(d.created_at).toLocaleString()}\n </td>\n <td>\n {canRetry(d.status) && (\n <button\n className=\"zwp-btn zwp-btn--sm\"\n onClick={() => handleRetry(d.id)}\n disabled={retrying === d.id}\n >\n {retrying === d.id ? '...' : 'Retry'}\n </button>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n\n {totalPages > 1 && (\n <div className=\"zwp-pagination\">\n <button\n className=\"zwp-btn zwp-btn--sm\"\n onClick={() => setPage(p => p - 1)}\n disabled={page === 0}\n >\n Previous\n </button>\n <span className=\"zwp-page-info\">\n Page {page + 1} of {totalPages}\n </span>\n <button\n className=\"zwp-btn zwp-btn--sm\"\n onClick={() => setPage(p => p + 1)}\n disabled={page >= totalPages - 1}\n >\n Next\n </button>\n </div>\n )}\n </>\n )}\n </div>\n </div>\n );\n}\n","import { useState, useEffect } from 'react';\nimport type { WebhookPortalProps, PortalEndpoint, PortalEventType } from '../types';\nimport { usePortalApi } from '../hooks/usePortalApi';\nimport { EndpointList } from './EndpointList';\nimport { EndpointDetail } from './EndpointDetail';\n\nconst PREVIEW_ENDPOINTS: PortalEndpoint[] = [\n {\n id: 'preview-1',\n url: 'https://api.example.com/webhooks',\n description: 'Production endpoint',\n events: ['order.created', 'order.updated', 'payment.completed'],\n status: 'active',\n consecutive_failures: 0,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n },\n {\n id: 'preview-2',\n url: 'https://staging.example.com/hooks',\n events: ['order.created'],\n status: 'paused',\n consecutive_failures: 0,\n created_at: new Date(Date.now() - 86400000).toISOString(),\n updated_at: new Date(Date.now() - 86400000).toISOString(),\n },\n];\n\nfunction PreviewEndpointList() {\n return (\n <div className=\"zwp-endpoint-list\">\n <div className=\"zwp-section-header\">\n <h3 className=\"zwp-heading\">Endpoints</h3>\n <button className=\"zwp-btn zwp-btn--primary\" disabled>Add Endpoint</button>\n </div>\n <div className=\"zwp-list\">\n {PREVIEW_ENDPOINTS.map(ep => (\n <div key={ep.id} className=\"zwp-endpoint-card\" style={{ cursor: 'default' }}>\n <div className=\"zwp-endpoint-header\">\n <code className=\"zwp-endpoint-url\">{ep.url}</code>\n <span className={`zwp-badge ${ep.status === 'active' ? 'zwp-badge--green' : 'zwp-badge--yellow'}`}>\n {ep.status}\n </span>\n </div>\n {ep.description && <p className=\"zwp-endpoint-desc\">{ep.description}</p>}\n <div className=\"zwp-endpoint-meta\">\n <span>{ep.events.length} event{ep.events.length !== 1 ? 's' : ''}</span>\n <span>Created {new Date(ep.created_at).toLocaleDateString()}</span>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nexport function WebhookPortal({\n token,\n baseUrl,\n theme,\n preview,\n onEndpointCreated,\n onEndpointDeleted,\n onEndpointUpdated,\n onDeliveryRetried,\n onError,\n className,\n}: WebhookPortalProps) {\n const api = usePortalApi({ token, baseUrl });\n const [eventTypes, setEventTypes] = useState<PortalEventType[]>([]);\n const [selectedEndpoint, setSelectedEndpoint] = useState<PortalEndpoint | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (preview) return;\n api.listEventTypes()\n .then(setEventTypes)\n .catch(err => {\n const e = err instanceof Error ? err : new Error('Failed to load event types');\n setError(e.message);\n onError?.(e);\n });\n }, [api, onError, preview]);\n\n const handleError = (err: Error) => {\n setError(err.message);\n onError?.(err);\n setTimeout(() => setError(null), 5000);\n };\n\n const style: Record<string, string> = {};\n if (theme?.accent) {\n style['--zwp-accent'] = theme.accent;\n }\n if (theme?.borderRadius !== undefined) {\n style['--zwp-radius'] = `${theme.borderRadius}px`;\n }\n\n const themeClass = theme?.mode === 'dark' ? 'zwp-dark' : 'zwp-light';\n\n return (\n <div\n className={`zwp-portal ${themeClass} ${className || ''}`}\n style={style}\n >\n {error && (\n <div className=\"zwp-alert zwp-alert--error\">\n {error}\n <button className=\"zwp-alert-close\" onClick={() => setError(null)}>×</button>\n </div>\n )}\n\n {preview ? (\n <PreviewEndpointList />\n ) : selectedEndpoint ? (\n <EndpointDetail\n api={api}\n endpoint={selectedEndpoint}\n onBack={() => setSelectedEndpoint(null)}\n onRetried={onDeliveryRetried}\n onError={handleError}\n />\n ) : (\n <EndpointList\n api={api}\n eventTypes={eventTypes}\n onSelect={setSelectedEndpoint}\n onCreated={onEndpointCreated}\n onDeleted={onEndpointDeleted}\n onUpdated={onEndpointUpdated}\n onError={handleError}\n />\n )}\n </div>\n );\n}\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":"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"}
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.zwp-portal{--zwp-accent:#6366f1;--zwp-radius:8px;--zwp-font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;--zwp-mono:"SF Mono",SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospace;box-sizing:border-box;font-family:var(--zwp-font);font-size:14px;line-height:1.5}.zwp-portal *,.zwp-portal :after,.zwp-portal :before{box-sizing:inherit}.zwp-light{--zwp-bg:#fff;--zwp-bg-secondary:#f8f9fa;--zwp-border:#e9ecef;--zwp-text:#212529;--zwp-text-secondary:#6c757d;--zwp-input-bg:#fff;--zwp-hover:#f1f3f5}.zwp-dark{--zwp-bg:#1a1b1e;--zwp-bg-secondary:#25262b;--zwp-border:#373a40;--zwp-text:#c1c2c5;--zwp-text-secondary:#909296;--zwp-input-bg:#25262b;--zwp-hover:#2c2e33}.zwp-portal{background:var(--zwp-bg);border:1px solid var(--zwp-border);border-radius:var(--zwp-radius);color:var(--zwp-text);padding:16px}.zwp-heading{font-size:16px;font-weight:600;margin:0}.zwp-subheading{font-size:14px;font-weight:600;margin:0 0 8px}.zwp-section-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:12px}.zwp-btn{align-items:center;background:var(--zwp-bg-secondary);border:1px solid var(--zwp-border);border-radius:calc(var(--zwp-radius) - 2px);color:var(--zwp-text);cursor:pointer;display:inline-flex;font-family:var(--zwp-font);font-size:13px;gap:6px;padding:8px 16px;transition:background .15s}.zwp-btn:hover{background:var(--zwp-hover)}.zwp-btn:disabled{cursor:not-allowed;opacity:.5}.zwp-btn--primary{background:var(--zwp-accent);border-color:var(--zwp-accent);color:#fff}.zwp-btn--primary:hover{background:var(--zwp-accent);opacity:.9}.zwp-btn--danger{border-color:#e0313133;color:#e03131}.zwp-btn--danger:hover{background:#e0313112}.zwp-btn--ghost{background:transparent;border-color:transparent}.zwp-btn--ghost:hover{background:var(--zwp-hover)}.zwp-btn--sm{font-size:12px;padding:4px 10px}.zwp-input,.zwp-select{background:var(--zwp-input-bg);border:1px solid var(--zwp-border);border-radius:calc(var(--zwp-radius) - 2px);color:var(--zwp-text);font-family:var(--zwp-font);font-size:13px;padding:8px 12px;width:100%}.zwp-input:focus,.zwp-select:focus{border-color:var(--zwp-accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--zwp-accent) 20%,transparent);outline:none}.zwp-select{cursor:pointer}.zwp-field{margin-bottom:12px}.zwp-label{display:block;font-size:13px;font-weight:500;margin-bottom:4px}.zwp-badge{border-radius:9999px;display:inline-block;font-size:11px;font-weight:600;letter-spacing:.02em;padding:2px 8px;text-transform:uppercase}.zwp-badge--green{background:#12b886;color:#fff}.zwp-badge--yellow{background:#fab005;color:#000}.zwp-badge--red{background:#e03131;color:#fff}.zwp-tags{display:flex;flex-wrap:wrap;gap:4px}.zwp-tag{background:var(--zwp-bg-secondary);border:1px solid var(--zwp-border);border-radius:calc(var(--zwp-radius) - 2px);display:inline-block;font-family:var(--zwp-mono);font-size:12px;padding:2px 8px}.zwp-alert{border-radius:var(--zwp-radius);margin-bottom:12px;padding:12px 16px;position:relative}.zwp-alert--error{background:#e0313112;border:1px solid #e0313133;color:#e03131}.zwp-alert--warning{background:#fab00512;border:1px solid #fab00533;color:var(--zwp-text)}.zwp-alert-close{background:none;border:none;color:inherit;cursor:pointer;font-size:16px;position:absolute;right:12px;top:8px}.zwp-secret{background:var(--zwp-bg-secondary);border:1px solid var(--zwp-border);border-radius:calc(var(--zwp-radius) - 2px);display:block;font-family:var(--zwp-mono);font-size:13px;margin:8px 0;padding:8px;word-break:break-all}.zwp-endpoint-card{border:1px solid var(--zwp-border);border-radius:var(--zwp-radius);cursor:pointer;margin-bottom:8px;padding:12px 16px;transition:background .15s}.zwp-endpoint-card:hover{background:var(--zwp-hover)}.zwp-endpoint-header{align-items:center;display:flex;gap:8px;justify-content:space-between}.zwp-endpoint-url{font-family:var(--zwp-mono);font-size:13px;font-weight:500}.zwp-endpoint-desc{margin:4px 0 0}.zwp-endpoint-desc,.zwp-endpoint-meta{color:var(--zwp-text-secondary);font-size:12px}.zwp-endpoint-meta{display:flex;gap:16px;margin-top:8px}.zwp-endpoint-actions{display:flex;gap:8px;margin-top:8px}.zwp-create-form{background:var(--zwp-bg-secondary);border:1px solid var(--zwp-border);border-radius:var(--zwp-radius);margin-bottom:12px;padding:16px}.zwp-event-picker{background:var(--zwp-input-bg);border:1px solid var(--zwp-border);border-radius:calc(var(--zwp-radius) - 2px);display:flex;flex-direction:column;gap:6px;max-height:200px;overflow-y:auto;padding:8px}.zwp-checkbox-label{align-items:center;cursor:pointer;display:flex;font-size:13px;gap:8px}.zwp-event-name{font-weight:500}.zwp-event-type{color:var(--zwp-text-secondary);font-family:var(--zwp-mono);font-size:11px}.zwp-table{border-collapse:collapse;font-size:13px;width:100%}.zwp-table th{border-bottom:2px solid var(--zwp-border);color:var(--zwp-text-secondary);font-size:12px;font-weight:600;letter-spacing:.03em;padding:8px 12px;text-align:left;text-transform:uppercase}.zwp-table td{border-bottom:1px solid var(--zwp-border);padding:8px 12px}.zwp-table tr:hover td{background:var(--zwp-hover)}.zwp-event-code{font-family:var(--zwp-mono);font-size:12px}.zwp-time{color:var(--zwp-text-secondary);font-size:12px;white-space:nowrap}.zwp-pagination{align-items:center;display:flex;gap:12px;justify-content:center;margin-top:12px}.zwp-page-info{color:var(--zwp-text-secondary);font-size:13px}.zwp-back-btn{margin-bottom:12px}.zwp-detail-header{align-items:flex-start;display:flex;justify-content:space-between;margin-bottom:16px}.zwp-events-list{margin-bottom:16px}.zwp-empty,.zwp-loading{color:var(--zwp-text-secondary);padding:24px;text-align:center}
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zyphr-dev/webhook-portal",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Embeddable webhook management portal for Zyphr WaaS",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./styles.css": "./dist/styles.css"
|
|
16
|
+
},
|
|
17
|
+
"sideEffects": [
|
|
18
|
+
"*.css"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "rollup -c",
|
|
29
|
+
"dev": "rollup -c -w",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"clean": "rm -rf dist",
|
|
34
|
+
"prepublishOnly": "yarn clean && yarn build"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"react": ">=17.0.0",
|
|
38
|
+
"react-dom": ">=17.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@rollup/plugin-commonjs": "^25.0.0",
|
|
42
|
+
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
43
|
+
"@rollup/plugin-typescript": "^11.0.0",
|
|
44
|
+
"@types/react": "^19.0.0",
|
|
45
|
+
"@types/react-dom": "^19.0.0",
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
47
|
+
"@typescript-eslint/parser": "^7.0.0",
|
|
48
|
+
"eslint": "^8.57.0",
|
|
49
|
+
"eslint-plugin-react": "^7.34.0",
|
|
50
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
51
|
+
"postcss": "^8.5.6",
|
|
52
|
+
"react": "^19.2.4",
|
|
53
|
+
"react-dom": "^19.2.4",
|
|
54
|
+
"rollup": "^4.0.0",
|
|
55
|
+
"rollup-plugin-dts": "^6.0.0",
|
|
56
|
+
"rollup-plugin-postcss": "^4.0.0",
|
|
57
|
+
"tslib": "^2.6.0",
|
|
58
|
+
"typescript": "^5.3.0",
|
|
59
|
+
"vitest": "^4.0.18"
|
|
60
|
+
},
|
|
61
|
+
"keywords": [
|
|
62
|
+
"zyphr",
|
|
63
|
+
"webhooks",
|
|
64
|
+
"portal",
|
|
65
|
+
"react",
|
|
66
|
+
"embeddable",
|
|
67
|
+
"waas"
|
|
68
|
+
],
|
|
69
|
+
"license": "MIT",
|
|
70
|
+
"homepage": "https://zyphr.dev/docs/guides/waas-embedded-portal",
|
|
71
|
+
"repository": {
|
|
72
|
+
"type": "git",
|
|
73
|
+
"url": "https://github.com/arcraz/zyphr.git",
|
|
74
|
+
"directory": "packages/webhook-portal"
|
|
75
|
+
}
|
|
76
|
+
}
|