@hookbase/cli 1.0.0 → 1.0.2

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.
Files changed (113) hide show
  1. package/dist/commands/api-keys.d.ts.map +1 -1
  2. package/dist/commands/api-keys.js +106 -50
  3. package/dist/commands/api-keys.js.map +1 -1
  4. package/dist/commands/applications.d.ts +27 -0
  5. package/dist/commands/applications.d.ts.map +1 -0
  6. package/dist/commands/applications.js +216 -0
  7. package/dist/commands/applications.js.map +1 -0
  8. package/dist/commands/cron-groups.d.ts +26 -0
  9. package/dist/commands/cron-groups.d.ts.map +1 -0
  10. package/dist/commands/cron-groups.js +282 -0
  11. package/dist/commands/cron-groups.js.map +1 -0
  12. package/dist/commands/cron.d.ts +60 -0
  13. package/dist/commands/cron.d.ts.map +1 -0
  14. package/dist/commands/cron.js +953 -0
  15. package/dist/commands/cron.js.map +1 -0
  16. package/dist/commands/deliveries.d.ts.map +1 -1
  17. package/dist/commands/deliveries.js +36 -29
  18. package/dist/commands/deliveries.js.map +1 -1
  19. package/dist/commands/destinations.d.ts.map +1 -1
  20. package/dist/commands/destinations.js +82 -52
  21. package/dist/commands/destinations.js.map +1 -1
  22. package/dist/commands/endpoints.d.ts +39 -0
  23. package/dist/commands/endpoints.d.ts.map +1 -0
  24. package/dist/commands/endpoints.js +349 -0
  25. package/dist/commands/endpoints.js.map +1 -0
  26. package/dist/commands/events.d.ts.map +1 -1
  27. package/dist/commands/events.js +15 -14
  28. package/dist/commands/events.js.map +1 -1
  29. package/dist/commands/groups/inbound.d.ts +8 -0
  30. package/dist/commands/groups/inbound.d.ts.map +1 -0
  31. package/dist/commands/groups/inbound.js +226 -0
  32. package/dist/commands/groups/inbound.js.map +1 -0
  33. package/dist/commands/groups/outbound.d.ts +8 -0
  34. package/dist/commands/groups/outbound.d.ts.map +1 -0
  35. package/dist/commands/groups/outbound.js +228 -0
  36. package/dist/commands/groups/outbound.js.map +1 -0
  37. package/dist/commands/groups/tools.d.ts +6 -0
  38. package/dist/commands/groups/tools.d.ts.map +1 -0
  39. package/dist/commands/groups/tools.js +243 -0
  40. package/dist/commands/groups/tools.js.map +1 -0
  41. package/dist/commands/logs.js +3 -3
  42. package/dist/commands/logs.js.map +1 -1
  43. package/dist/commands/outbound.d.ts +40 -0
  44. package/dist/commands/outbound.d.ts.map +1 -0
  45. package/dist/commands/outbound.js +389 -0
  46. package/dist/commands/outbound.js.map +1 -0
  47. package/dist/commands/routes.d.ts.map +1 -1
  48. package/dist/commands/routes.js +98 -72
  49. package/dist/commands/routes.js.map +1 -1
  50. package/dist/commands/send.d.ts +9 -0
  51. package/dist/commands/send.d.ts.map +1 -0
  52. package/dist/commands/send.js +132 -0
  53. package/dist/commands/send.js.map +1 -0
  54. package/dist/commands/sources.d.ts.map +1 -1
  55. package/dist/commands/sources.js +78 -42
  56. package/dist/commands/sources.js.map +1 -1
  57. package/dist/commands/tunnels.d.ts.map +1 -1
  58. package/dist/commands/tunnels.js +76 -40
  59. package/dist/commands/tunnels.js.map +1 -1
  60. package/dist/index.js +143 -309
  61. package/dist/index.js.map +1 -1
  62. package/dist/lib/api.d.ts +368 -5
  63. package/dist/lib/api.d.ts.map +1 -1
  64. package/dist/lib/api.js +308 -14
  65. package/dist/lib/api.js.map +1 -1
  66. package/dist/lib/config.d.ts +9 -0
  67. package/dist/lib/config.d.ts.map +1 -1
  68. package/dist/lib/config.js +22 -0
  69. package/dist/lib/config.js.map +1 -1
  70. package/dist/lib/logger.d.ts.map +1 -1
  71. package/dist/lib/logger.js +32 -15
  72. package/dist/lib/logger.js.map +1 -1
  73. package/dist/tui/App.d.ts.map +1 -1
  74. package/dist/tui/App.js +397 -47
  75. package/dist/tui/App.js.map +1 -1
  76. package/dist/tui/Dashboard.js +1 -1
  77. package/dist/tui/Dashboard.js.map +1 -1
  78. package/dist/tui/views/Analytics.d.ts.map +1 -1
  79. package/dist/tui/views/Analytics.js +11 -2
  80. package/dist/tui/views/Analytics.js.map +1 -1
  81. package/dist/tui/views/ApiKeys.d.ts +10 -0
  82. package/dist/tui/views/ApiKeys.d.ts.map +1 -0
  83. package/dist/tui/views/ApiKeys.js +211 -0
  84. package/dist/tui/views/ApiKeys.js.map +1 -0
  85. package/dist/tui/views/Cron.d.ts +10 -0
  86. package/dist/tui/views/Cron.d.ts.map +1 -0
  87. package/dist/tui/views/Cron.js +312 -0
  88. package/dist/tui/views/Cron.js.map +1 -0
  89. package/dist/tui/views/Destinations.d.ts.map +1 -1
  90. package/dist/tui/views/Destinations.js +38 -19
  91. package/dist/tui/views/Destinations.js.map +1 -1
  92. package/dist/tui/views/Events.d.ts.map +1 -1
  93. package/dist/tui/views/Events.js +22 -4
  94. package/dist/tui/views/Events.js.map +1 -1
  95. package/dist/tui/views/Outbound.d.ts +8 -0
  96. package/dist/tui/views/Outbound.d.ts.map +1 -0
  97. package/dist/tui/views/Outbound.js +543 -0
  98. package/dist/tui/views/Outbound.js.map +1 -0
  99. package/dist/tui/views/Overview.d.ts +4 -0
  100. package/dist/tui/views/Overview.d.ts.map +1 -1
  101. package/dist/tui/views/Overview.js +35 -11
  102. package/dist/tui/views/Overview.js.map +1 -1
  103. package/dist/tui/views/Routes.d.ts +12 -0
  104. package/dist/tui/views/Routes.d.ts.map +1 -0
  105. package/dist/tui/views/Routes.js +220 -0
  106. package/dist/tui/views/Routes.js.map +1 -0
  107. package/dist/tui/views/Sources.d.ts.map +1 -1
  108. package/dist/tui/views/Sources.js +22 -12
  109. package/dist/tui/views/Sources.js.map +1 -1
  110. package/dist/tui/views/Tunnels.d.ts.map +1 -1
  111. package/dist/tui/views/Tunnels.js +72 -13
  112. package/dist/tui/views/Tunnels.js.map +1 -1
  113. package/package.json +4 -4
@@ -0,0 +1,543 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect, useRef } from 'react';
3
+ import { Box, Text, useInput } from 'ink';
4
+ import TextInput from 'ink-text-input';
5
+ import SelectInput from 'ink-select-input';
6
+ import Spinner from 'ink-spinner';
7
+ import * as api from '../../lib/api.js';
8
+ function CreateApplication({ onBack, onCreated }) {
9
+ const [step, setStep] = useState('name');
10
+ const [name, setName] = useState('');
11
+ const [description, setDescription] = useState('');
12
+ const [error, setError] = useState(null);
13
+ const [createdApp, setCreatedApp] = useState(null);
14
+ useInput((input, key) => {
15
+ if (key.escape && step !== 'creating') {
16
+ onBack();
17
+ }
18
+ });
19
+ const handleCreate = async () => {
20
+ setStep('creating');
21
+ try {
22
+ const result = await api.createWebhookApplication({
23
+ name: name.trim(),
24
+ description: description.trim() || undefined,
25
+ });
26
+ if (result.error) {
27
+ setError(result.error);
28
+ setStep('name');
29
+ }
30
+ else {
31
+ setCreatedApp(result.data?.data || result.data?.application || null);
32
+ setStep('done');
33
+ setTimeout(onCreated, 1500);
34
+ }
35
+ }
36
+ catch (err) {
37
+ setError(err instanceof Error ? err.message : 'Failed to create');
38
+ setStep('name');
39
+ }
40
+ };
41
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Create Application" }), _jsx(Text, { dimColor: true, children: " - Esc to cancel" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, children: [step === 'name' && (_jsxs(Box, { children: [_jsx(Text, { children: "Name: " }), _jsx(TextInput, { value: name, onChange: setName, onSubmit: () => name.trim() && setStep('description'), placeholder: "My Webhook App" })] })), step === 'description' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["Name: ", name] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { children: "Description (optional, Enter to skip): " }), _jsx(TextInput, { value: description, onChange: setDescription, onSubmit: handleCreate, placeholder: "" })] })] })), step === 'creating' && (_jsxs(Box, { children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { children: " Creating application..." })] })), step === 'done' && createdApp && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "green", bold: true, children: "Application created!" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "ID: " }), _jsx(Text, { children: createdApp.id })] }), _jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "Name: " }), _jsx(Text, { children: createdApp.name })] })] })), error && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["Error: ", error] }) }))] })] }));
42
+ }
43
+ function CreateEndpoint({ applications, onBack, onCreated }) {
44
+ const [step, setStep] = useState('app');
45
+ const [selectedAppId, setSelectedAppId] = useState('');
46
+ const [url, setUrl] = useState('');
47
+ const [error, setError] = useState(null);
48
+ const [createdEndpoint, setCreatedEndpoint] = useState(null);
49
+ const [secret, setSecret] = useState(null);
50
+ useInput((input, key) => {
51
+ if (key.escape && step !== 'creating') {
52
+ onBack();
53
+ }
54
+ });
55
+ const appItems = applications.map(a => ({
56
+ label: a.name,
57
+ value: a.id,
58
+ }));
59
+ const handleAppSelect = (item) => {
60
+ setSelectedAppId(item.value);
61
+ setStep('url');
62
+ };
63
+ const handleCreate = async () => {
64
+ if (!url.trim())
65
+ return;
66
+ setStep('creating');
67
+ try {
68
+ const result = await api.createWebhookEndpoint({
69
+ applicationId: selectedAppId,
70
+ url: url.trim(),
71
+ });
72
+ if (result.error) {
73
+ setError(result.error);
74
+ setStep('url');
75
+ }
76
+ else {
77
+ const resData = result.data?.data || result.data;
78
+ setCreatedEndpoint(resData || null);
79
+ setSecret(resData?.secret || result.data?.secret || null);
80
+ setStep('done');
81
+ setTimeout(onCreated, 3000);
82
+ }
83
+ }
84
+ catch (err) {
85
+ setError(err instanceof Error ? err.message : 'Failed to create');
86
+ setStep('url');
87
+ }
88
+ };
89
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Create Endpoint" }), _jsx(Text, { dimColor: true, children: " - Esc to cancel" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, children: [step === 'app' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: "Select application:" }), appItems.length === 0 ? (_jsx(Text, { color: "yellow", children: "No applications. Create an application first." })) : (_jsx(SelectInput, { items: appItems, onSelect: handleAppSelect }))] })), step === 'url' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["App: ", applications.find(a => a.id === selectedAppId)?.name] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { children: "Endpoint URL: " }), _jsx(TextInput, { value: url, onChange: setUrl, onSubmit: handleCreate, placeholder: "https://api.example.com/webhook" })] })] })), step === 'creating' && (_jsxs(Box, { children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { children: " Creating endpoint..." })] })), step === 'done' && createdEndpoint && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "green", bold: true, children: "Endpoint created!" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "ID: " }), _jsx(Text, { children: createdEndpoint.id })] }), _jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "URL: " }), _jsx(Text, { color: "blue", children: createdEndpoint.url })] }), secret && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", bold: true, children: "Save this secret - it will not be shown again:" }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "cyan", bold: true, children: secret }) })] }))] })), error && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["Error: ", error] }) }))] })] }));
90
+ }
91
+ // Helper to get active status from app (API uses isDisabled, not is_active)
92
+ function getAppIsActive(app) {
93
+ if ('isDisabled' in app)
94
+ return !app.isDisabled;
95
+ if ('is_disabled' in app)
96
+ return !app.is_disabled;
97
+ if ('is_active' in app)
98
+ return !!app.is_active;
99
+ return true;
100
+ }
101
+ function getDate(obj, ...keys) {
102
+ for (const k of keys) {
103
+ if (obj[k])
104
+ return new Date(obj[k]).toLocaleString();
105
+ }
106
+ return '-';
107
+ }
108
+ function AppDetail({ appId, applications, onBack, onRefresh }) {
109
+ const app = applications.find((a) => a.id === appId);
110
+ const [confirmDelete, setConfirmDelete] = useState(false);
111
+ const [deleting, setDeleting] = useState(false);
112
+ const [toggling, setToggling] = useState(false);
113
+ const [message, setMessage] = useState(null);
114
+ const [localActive, setLocalActive] = useState(null);
115
+ const busy = useRef(false);
116
+ const isActive = localActive !== null ? localActive : (app ? getAppIsActive(app) : false);
117
+ useInput(async (input, key) => {
118
+ if (busy.current)
119
+ return;
120
+ if (key.escape || input === 'b') {
121
+ if (confirmDelete) {
122
+ setConfirmDelete(false);
123
+ }
124
+ else {
125
+ onBack();
126
+ }
127
+ }
128
+ if (input === 't' && !confirmDelete && app) {
129
+ busy.current = true;
130
+ setToggling(true);
131
+ const newDisabled = isActive;
132
+ try {
133
+ const result = await api.updateWebhookApplication(appId, { isDisabled: newDisabled });
134
+ if (result.error) {
135
+ setMessage(`Error: ${result.error}`);
136
+ }
137
+ else {
138
+ setLocalActive(!newDisabled);
139
+ setMessage(!newDisabled ? 'Application enabled' : 'Application disabled');
140
+ onRefresh();
141
+ }
142
+ }
143
+ catch (err) {
144
+ setMessage('Failed to toggle');
145
+ }
146
+ setToggling(false);
147
+ setTimeout(() => { busy.current = false; }, 300);
148
+ }
149
+ if (input === 'd' && !confirmDelete) {
150
+ setConfirmDelete(true);
151
+ }
152
+ if (input === 'y' && confirmDelete) {
153
+ busy.current = true;
154
+ setDeleting(true);
155
+ try {
156
+ const result = await api.deleteWebhookApplication(appId);
157
+ if (result.error) {
158
+ setMessage(`Error: ${result.error}`);
159
+ setConfirmDelete(false);
160
+ setTimeout(() => { busy.current = false; }, 300);
161
+ }
162
+ else {
163
+ setMessage('Application deleted');
164
+ setTimeout(() => { onRefresh(); onBack(); }, 1500);
165
+ }
166
+ }
167
+ catch (err) {
168
+ setMessage('Failed to delete');
169
+ setConfirmDelete(false);
170
+ setTimeout(() => { busy.current = false; }, 300);
171
+ }
172
+ setDeleting(false);
173
+ }
174
+ if (input === 'n' && confirmDelete) {
175
+ setConfirmDelete(false);
176
+ }
177
+ });
178
+ if (!app) {
179
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "red", children: "Application not found" }), _jsx(Text, { dimColor: true, children: "Press Esc to go back" })] }));
180
+ }
181
+ const a = app;
182
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Application Details" }), _jsx(Text, { dimColor: true, children: " - Esc: back | t: toggle | d: delete" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "ID:" }) }), _jsx(Text, { children: app.id })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Name:" }) }), _jsx(Text, { bold: true, children: app.name })] }), (a.uid || a.externalId) && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "UID:" }) }), _jsx(Text, { children: a.uid || a.externalId })] })), (a.description || a.metadata) && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Description:" }) }), _jsx(Text, { children: a.description || '-' })] })), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Status:" }) }), _jsx(Text, { color: isActive ? 'green' : 'red', children: isActive ? 'Active' : 'Disabled' })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Endpoints:" }) }), _jsx(Text, { children: a.endpoint_count ?? a.endpointCount ?? 0 })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Messages:" }) }), _jsx(Text, { children: a.message_count ?? a.messageCount ?? 0 })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Created:" }) }), _jsx(Text, { dimColor: true, children: getDate(a, 'createdAt', 'created_at') })] }), toggling && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Updating..."] }) })), confirmDelete && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "red", bold: true, children: "Delete this application?" }), _jsx(Text, { children: "Press 'y' to confirm, 'n' or Esc to cancel" })] })), deleting && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Deleting..."] }) })), message && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: message.startsWith('Error') ? 'red' : 'green', children: message }) }))] })] }));
183
+ }
184
+ function EndpointDetail({ endpointId, endpoints, onBack, onRefresh }) {
185
+ const endpoint = endpoints.find((e) => e.id === endpointId);
186
+ const [testing, setTesting] = useState(false);
187
+ const [testResult, setTestResult] = useState(null);
188
+ const [confirmDelete, setConfirmDelete] = useState(false);
189
+ const [deleting, setDeleting] = useState(false);
190
+ const [message, setMessage] = useState(null);
191
+ const busy = useRef(false);
192
+ useInput(async (input, key) => {
193
+ if (busy.current)
194
+ return;
195
+ if (key.escape || input === 'b') {
196
+ if (confirmDelete) {
197
+ setConfirmDelete(false);
198
+ }
199
+ else {
200
+ onBack();
201
+ }
202
+ }
203
+ if (input === 't' && !confirmDelete) {
204
+ busy.current = true;
205
+ setTesting(true);
206
+ try {
207
+ const result = await api.testWebhookEndpoint(endpointId);
208
+ if (result.error) {
209
+ setTestResult({ success: false, status: 0, time: 0, error: result.error });
210
+ }
211
+ else {
212
+ const d = result.data?.data || result.data;
213
+ setTestResult({
214
+ success: d?.success === true,
215
+ status: (d?.statusCode ?? d?.status_code ?? 0),
216
+ time: (d?.duration ?? d?.responseTime ?? d?.response_time ?? 0),
217
+ error: d?.error,
218
+ });
219
+ }
220
+ }
221
+ catch (err) {
222
+ setTestResult({ success: false, status: 0, time: 0, error: 'Test failed' });
223
+ }
224
+ setTesting(false);
225
+ setTimeout(() => { busy.current = false; }, 300);
226
+ }
227
+ if (input === 'd' && !confirmDelete) {
228
+ setConfirmDelete(true);
229
+ }
230
+ if (input === 'y' && confirmDelete) {
231
+ busy.current = true;
232
+ setDeleting(true);
233
+ try {
234
+ const result = await api.deleteWebhookEndpoint(endpointId);
235
+ if (result.error) {
236
+ setMessage(`Error: ${result.error}`);
237
+ setConfirmDelete(false);
238
+ setTimeout(() => { busy.current = false; }, 300);
239
+ }
240
+ else {
241
+ setMessage('Endpoint deleted');
242
+ setTimeout(() => { onRefresh(); onBack(); }, 1500);
243
+ }
244
+ }
245
+ catch (err) {
246
+ setMessage('Failed to delete');
247
+ setConfirmDelete(false);
248
+ }
249
+ setDeleting(false);
250
+ }
251
+ if (input === 'n' && confirmDelete) {
252
+ setConfirmDelete(false);
253
+ }
254
+ });
255
+ if (!endpoint) {
256
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "red", children: "Endpoint not found" }), _jsx(Text, { dimColor: true, children: "Press Esc to go back" })] }));
257
+ }
258
+ const ep = endpoint;
259
+ const epActive = ep.is_active || ep.isActive || !ep.isDisabled;
260
+ const eventTypes = Array.isArray(ep.event_types || ep.eventTypes)
261
+ ? (ep.event_types || ep.eventTypes).join(', ')
262
+ : '*';
263
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Endpoint Details" }), _jsx(Text, { dimColor: true, children: " - Esc: back | t: test | d: delete" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "ID:" }) }), _jsx(Text, { children: endpoint.id })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "URL:" }) }), _jsx(Text, { color: "blue", children: endpoint.url })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Application:" }) }), _jsx(Text, { children: ep.application_name || ep.applicationName || ep.application_id || ep.applicationId })] }), (ep.description) && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Description:" }) }), _jsx(Text, { children: ep.description })] })), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Status:" }) }), _jsx(Text, { color: epActive ? 'green' : 'red', children: epActive ? 'Active' : 'Disabled' })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Circuit:" }) }), (() => {
264
+ const state = ep.circuit_state || ep.circuitState;
265
+ const color = state === 'closed' ? 'green' : state === 'open' ? 'red' : 'yellow';
266
+ return _jsx(Text, { color: color, children: state || 'unknown' });
267
+ })()] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Event Types:" }) }), _jsx(Text, { children: eventTypes })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Timeout:" }) }), _jsxs(Text, { children: [ep.timeout_ms || ep.timeoutMs || 30000, "ms"] })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Messages:" }) }), _jsx(Text, { children: ep.message_count ?? ep.messageCount ?? 0 })] }), (ep.success_rate !== undefined || ep.successRate !== undefined) && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Success Rate:" }) }), _jsxs(Text, { children: [((ep.success_rate ?? ep.successRate) * 100).toFixed(1), "%"] })] })), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Created:" }) }), _jsx(Text, { dimColor: true, children: getDate(ep, 'createdAt', 'created_at') })] }), testing && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Testing..."] }) })), testResult && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Test Result:" }), testResult.error ? (_jsxs(Text, { color: "red", children: ["Error: ", testResult.error] })) : (_jsxs(Text, { color: testResult.success ? 'green' : 'red', children: [testResult.success ? 'Passed' : 'Failed', " - Status: ", testResult.status > 0 ? testResult.status : 'N/A', " | Time: ", testResult.time, "ms"] }))] })), confirmDelete && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "red", bold: true, children: "Delete this endpoint?" }), _jsx(Text, { children: "Press 'y' to confirm, 'n' or Esc to cancel" })] })), deleting && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [_jsx(Spinner, { type: "dots" }), " Deleting..."] }) })), message && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: message.startsWith('Error') ? 'red' : 'green', children: message }) }))] })] }));
268
+ }
269
+ export function OutboundView({ subView, onNavigate, onRefresh }) {
270
+ const [activeSubTab, setActiveSubTab] = useState('apps');
271
+ const [selectedIndex, setSelectedIndex] = useState(0);
272
+ const [applications, setApplications] = useState([]);
273
+ const [endpoints, setEndpoints] = useState([]);
274
+ const [messages, setMessages] = useState([]);
275
+ const [dlqMessages, setDlqMessages] = useState([]);
276
+ const [loading, setLoading] = useState(true);
277
+ const [error, setError] = useState(null);
278
+ const [statusMessage, setStatusMessage] = useState(null);
279
+ const SUB_TABS = [
280
+ { key: 'apps', label: 'Applications' },
281
+ { key: 'endpoints', label: 'Endpoints' },
282
+ { key: 'messages', label: 'Messages' },
283
+ { key: 'dlq', label: 'DLQ' },
284
+ ];
285
+ const fetchData = async (isInitial = false) => {
286
+ if (isInitial) {
287
+ setLoading(true);
288
+ }
289
+ setError(null);
290
+ try {
291
+ const [appsRes, endpointsRes, messagesRes, dlqRes] = await Promise.all([
292
+ api.getWebhookApplications(),
293
+ api.getWebhookEndpoints(),
294
+ api.getWebhookMessages({ limit: 50 }),
295
+ api.getDlqMessages({ limit: 50 }),
296
+ ]);
297
+ if (appsRes.error)
298
+ throw new Error(appsRes.error);
299
+ if (endpointsRes.error)
300
+ throw new Error(endpointsRes.error);
301
+ // API returns { data: [...] } for all list endpoints
302
+ setApplications(appsRes.data?.data || appsRes.data?.applications || []);
303
+ setEndpoints(endpointsRes.data?.data || endpointsRes.data?.endpoints || []);
304
+ setMessages(messagesRes.data?.data || messagesRes.data?.messages || []);
305
+ setDlqMessages(dlqRes.data?.data || dlqRes.data?.messages || []);
306
+ }
307
+ catch (err) {
308
+ setError(err instanceof Error ? err.message : 'Failed to fetch data');
309
+ }
310
+ finally {
311
+ setLoading(false);
312
+ }
313
+ };
314
+ useEffect(() => {
315
+ fetchData(true);
316
+ }, []);
317
+ const getCurrentListLength = () => {
318
+ switch (activeSubTab) {
319
+ case 'apps': return applications.length + 1; // +1 for create item
320
+ case 'endpoints': return endpoints.length + 1; // +1 for create item
321
+ case 'messages': return messages.length;
322
+ case 'dlq': return dlqMessages.length;
323
+ default: return 0;
324
+ }
325
+ };
326
+ const getCurrentDataList = () => {
327
+ switch (activeSubTab) {
328
+ case 'apps': return applications;
329
+ case 'endpoints': return endpoints;
330
+ case 'messages': return messages;
331
+ case 'dlq': return dlqMessages;
332
+ default: return [];
333
+ }
334
+ };
335
+ useInput((input, key) => {
336
+ if (subView)
337
+ return;
338
+ const listLen = getCurrentListLength();
339
+ // Sub-tab navigation with [ / ] or left/right arrows
340
+ if (input === '[' || input === ']' || key.leftArrow || key.rightArrow) {
341
+ const currentIdx = SUB_TABS.findIndex(t => t.key === activeSubTab);
342
+ const direction = (input === ']' || key.rightArrow) ? 1 : -1;
343
+ const newIdx = (currentIdx + direction + SUB_TABS.length) % SUB_TABS.length;
344
+ setActiveSubTab(SUB_TABS[newIdx].key);
345
+ setSelectedIndex(0);
346
+ return;
347
+ }
348
+ // List navigation
349
+ if (key.downArrow || input === 'j') {
350
+ setSelectedIndex(prev => Math.min(prev + 1, listLen - 1));
351
+ }
352
+ if (key.upArrow || input === 'k') {
353
+ setSelectedIndex(prev => Math.max(prev - 1, 0));
354
+ }
355
+ // View details / select create
356
+ if (key.return && listLen > 0) {
357
+ if ((activeSubTab === 'apps' || activeSubTab === 'endpoints') && selectedIndex === 0) {
358
+ onNavigate(activeSubTab === 'apps' ? 'create-app' : 'create-endpoint');
359
+ return;
360
+ }
361
+ const dataList = getCurrentDataList();
362
+ const dataIdx = (activeSubTab === 'apps' || activeSubTab === 'endpoints') ? selectedIndex - 1 : selectedIndex;
363
+ if (dataIdx >= 0 && dataIdx < dataList.length) {
364
+ const item = dataList[dataIdx];
365
+ onNavigate(`${activeSubTab}:${item.id}`);
366
+ }
367
+ }
368
+ // Create new
369
+ if (input === 'n') {
370
+ if (activeSubTab === 'apps') {
371
+ onNavigate('create-app');
372
+ return;
373
+ }
374
+ if (activeSubTab === 'endpoints') {
375
+ onNavigate('create-endpoint');
376
+ return;
377
+ }
378
+ }
379
+ // Refresh
380
+ if (input === 'r') {
381
+ fetchData();
382
+ }
383
+ // Test endpoint (offset by 1 for create item)
384
+ if (input === 't' && activeSubTab === 'endpoints' && selectedIndex > 0 && endpoints.length > 0) {
385
+ const endpoint = endpoints[selectedIndex - 1];
386
+ if (endpoint)
387
+ testEndpoint(endpoint.id);
388
+ }
389
+ // Retry message/DLQ
390
+ if (input === 'y') {
391
+ if (activeSubTab === 'messages' && messages.length > 0) {
392
+ retryMessage(messages[selectedIndex].id);
393
+ }
394
+ else if (activeSubTab === 'dlq' && dlqMessages.length > 0) {
395
+ retryDlqMessage(dlqMessages[selectedIndex].id);
396
+ }
397
+ }
398
+ });
399
+ const testEndpoint = async (endpointId) => {
400
+ setStatusMessage('Testing endpoint...');
401
+ const result = await api.testWebhookEndpoint(endpointId);
402
+ if (result.error) {
403
+ setStatusMessage(`Test failed: ${result.error}`);
404
+ }
405
+ else if (result.data?.success) {
406
+ const d = result.data?.data || result.data;
407
+ setStatusMessage(`Test passed: ${d.statusCode || d.status_code || '?'} (${d.duration ?? d.responseTime ?? 0}ms)`);
408
+ }
409
+ else {
410
+ setStatusMessage(`Test failed: ${result.data?.error || 'Unknown error'}`);
411
+ }
412
+ setTimeout(() => setStatusMessage(null), 3000);
413
+ };
414
+ const retryMessage = async (messageId) => {
415
+ setStatusMessage('Retrying message...');
416
+ const result = await api.retryWebhookMessage(messageId);
417
+ if (result.error) {
418
+ setStatusMessage(`Retry failed: ${result.error}`);
419
+ }
420
+ else {
421
+ setStatusMessage('Message queued for retry');
422
+ fetchData();
423
+ }
424
+ setTimeout(() => setStatusMessage(null), 3000);
425
+ };
426
+ const retryDlqMessage = async (messageId) => {
427
+ setStatusMessage('Retrying DLQ message...');
428
+ const result = await api.retryDlqMessage(messageId);
429
+ if (result.error) {
430
+ setStatusMessage(`Retry failed: ${result.error}`);
431
+ }
432
+ else {
433
+ setStatusMessage('DLQ message queued for retry');
434
+ fetchData();
435
+ }
436
+ setTimeout(() => setStatusMessage(null), 3000);
437
+ };
438
+ const formatStatus = (status) => {
439
+ switch (status) {
440
+ case 'delivered': return _jsx(Text, { color: "green", children: status });
441
+ case 'pending': return _jsx(Text, { color: "yellow", children: status });
442
+ case 'processing': return _jsx(Text, { color: "cyan", children: status });
443
+ case 'failed': return _jsx(Text, { color: "red", children: status });
444
+ case 'exhausted': return _jsx(Text, { color: "red", children: status });
445
+ default: return _jsx(Text, { dimColor: true, children: status });
446
+ }
447
+ };
448
+ const formatCircuitState = (state) => {
449
+ switch (state) {
450
+ case 'closed': return _jsx(Text, { color: "green", children: "closed" });
451
+ case 'open': return _jsx(Text, { color: "red", children: "open" });
452
+ case 'half_open': return _jsx(Text, { color: "yellow", children: "half_open" });
453
+ default: return _jsx(Text, { dimColor: true, children: "-" });
454
+ }
455
+ };
456
+ if (loading) {
457
+ return (_jsxs(Box, { children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { children: " Loading outbound webhooks..." })] }));
458
+ }
459
+ if (error) {
460
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "red", children: ["Error: ", error] }), _jsx(Text, { dimColor: true, children: "Press 'r' to retry" })] }));
461
+ }
462
+ // Render create views
463
+ if (subView === 'create-app') {
464
+ return (_jsx(CreateApplication, { onBack: () => onNavigate(null), onCreated: () => { fetchData(); onNavigate(null); } }));
465
+ }
466
+ if (subView === 'create-endpoint') {
467
+ return (_jsx(CreateEndpoint, { applications: applications, onBack: () => onNavigate(null), onCreated: () => { fetchData(); onNavigate(null); } }));
468
+ }
469
+ // Render detail view
470
+ if (subView) {
471
+ const [type, id] = subView.split(':');
472
+ if (type === 'apps') {
473
+ return (_jsx(AppDetail, { appId: id, applications: applications, onBack: () => onNavigate(null), onRefresh: fetchData }));
474
+ }
475
+ if (type === 'endpoints') {
476
+ return (_jsx(EndpointDetail, { endpointId: id, endpoints: endpoints, onBack: () => onNavigate(null), onRefresh: fetchData }));
477
+ }
478
+ if (type === 'messages') {
479
+ const message = messages.find(m => m.id === id);
480
+ if (!message)
481
+ return _jsx(Text, { color: "red", children: "Message not found" });
482
+ const m = message;
483
+ const eventType = m.event_type || m.eventType || '-';
484
+ const respStatus = m.response_status || m.responseStatus;
485
+ const errorMsg = m.error_message || m.errorMessage;
486
+ const nextRetry = m.next_retry_at || m.nextRetryAt;
487
+ const deliveredAt = m.delivered_at || m.deliveredAt;
488
+ const createdAt = m.created_at || m.createdAt || '';
489
+ const endpointId = m.endpoint_id || m.endpointId || '-';
490
+ const appId = m.application_id || m.applicationId || '-';
491
+ const ep = endpoints.find(e => e.id === endpointId);
492
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Message Details" }), _jsx(Text, { dimColor: true, children: " - Esc: back | y: retry" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "ID:" }) }), _jsx(Text, { children: message.id })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Event Type:" }) }), _jsx(Text, { children: eventType })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Endpoint:" }) }), _jsx(Text, { color: "blue", children: ep ? ep.url : endpointId })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Application:" }) }), _jsx(Text, { children: appId })] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Status:" }) }), formatStatus(message.status)] }), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Attempts:" }) }), _jsxs(Text, { children: [m.attempt_count ?? m.attemptCount ?? 0, "/", m.max_attempts ?? m.maxAttempts ?? 5] })] }), respStatus && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Response:" }) }), _jsx(Text, { color: respStatus >= 200 && respStatus < 300 ? 'green' : 'red', children: respStatus })] })), errorMsg && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Error:" }) }), _jsx(Text, { color: "red", children: errorMsg })] })), nextRetry && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Next Retry:" }) }), _jsx(Text, { color: "yellow", children: new Date(nextRetry).toLocaleString() })] })), deliveredAt && (_jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Delivered:" }) }), _jsx(Text, { color: "green", children: new Date(deliveredAt).toLocaleString() })] })), _jsxs(Box, { children: [_jsx(Box, { width: 16, children: _jsx(Text, { dimColor: true, children: "Created:" }) }), _jsx(Text, { dimColor: true, children: new Date(createdAt).toLocaleString() })] })] })] }));
493
+ }
494
+ if (type === 'dlq') {
495
+ const dlqMessage = dlqMessages.find(m => m.id === id);
496
+ if (!dlqMessage)
497
+ return _jsx(Text, { color: "red", children: "DLQ message not found" });
498
+ const d = dlqMessage;
499
+ const eventType = d.event_type || d.eventType || '-';
500
+ const reason = d.reason || '-';
501
+ const errorMsg = d.error_message || d.errorMessage;
502
+ const lastResp = d.last_response_status || d.lastResponseStatus;
503
+ const origId = d.original_message_id || d.originalMessageId || '-';
504
+ const endpointId = d.endpoint_id || d.endpointId || '-';
505
+ const createdAt = d.created_at || d.createdAt || '';
506
+ const ep = endpoints.find(e => e.id === endpointId);
507
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, children: "DLQ Message Details" }), _jsx(Text, { dimColor: true, children: " - Esc: back | y: retry" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "ID:" }) }), _jsx(Text, { children: dlqMessage.id })] }), _jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Original Msg:" }) }), _jsx(Text, { dimColor: true, children: origId })] }), _jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Event Type:" }) }), _jsx(Text, { children: eventType })] }), _jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Endpoint:" }) }), _jsx(Text, { color: "blue", children: ep ? ep.url : endpointId })] }), _jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Reason:" }) }), _jsx(Text, { color: "red", children: reason })] }), _jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Attempts:" }) }), _jsx(Text, { children: d.attempt_count ?? d.attemptCount ?? 0 })] }), lastResp && (_jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Last Response:" }) }), _jsx(Text, { color: "red", children: lastResp })] })), errorMsg && (_jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Error:" }) }), _jsx(Text, { color: "red", children: errorMsg })] })), _jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { dimColor: true, children: "Created:" }) }), _jsx(Text, { dimColor: true, children: new Date(createdAt).toLocaleString() })] })] })] }));
508
+ }
509
+ return _jsx(Text, { color: "red", children: "Unknown view" });
510
+ }
511
+ // Render list view
512
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [SUB_TABS.map((tab) => (_jsx(Box, { marginRight: 2, children: _jsxs(Text, { bold: activeSubTab === tab.key, color: activeSubTab === tab.key ? 'cyan' : 'gray', children: [activeSubTab === tab.key ? '▸ ' : ' ', tab.label] }) }, tab.key))), _jsx(Box, { flexGrow: 1 }), _jsx(Text, { dimColor: true, children: "[]/\u2190\u2192: switch | \u2191/\u2193: select | Enter: view" })] }), statusMessage && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "yellow", children: statusMessage }) })), activeSubTab === 'apps' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { bold: true, children: ["Applications (", applications.length, ")"] }), _jsx(Text, { dimColor: true, children: " | n: new | Enter: details" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: selectedIndex === 0 ? 'cyan' : undefined, bold: selectedIndex === 0, children: selectedIndex === 0 ? '▶' : ' ' }) }), _jsx(Text, { color: "green", children: "+ New Application" })] }), applications.map((app, idx) => {
513
+ const listIdx = idx + 1;
514
+ const isSelected = listIdx === selectedIndex;
515
+ return (_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: isSelected ? '▶' : ' ' }) }), _jsx(Box, { width: 24, children: _jsxs(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: [app.name.slice(0, 22), app.name.length > 22 ? '…' : ''] }) }), _jsx(Box, { width: 14, children: _jsxs(Text, { dimColor: true, children: [app.endpoint_count || 0, " endpoints"] }) }), _jsx(Box, { width: 10, children: _jsxs(Text, { dimColor: true, children: [app.message_count || 0, " msgs"] }) }), _jsx(Box, { width: 8, children: _jsx(Text, { color: getAppIsActive(app) ? 'green' : 'red', children: getAppIsActive(app) ? 'Active' : 'Off' }) })] }, app.id));
516
+ })] })] })), activeSubTab === 'endpoints' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { bold: true, children: ["Endpoints (", endpoints.length, ")"] }), _jsx(Text, { dimColor: true, children: " | n: new | t: test | Enter: details" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: selectedIndex === 0 ? 'cyan' : undefined, bold: selectedIndex === 0, children: selectedIndex === 0 ? '▶' : ' ' }) }), _jsx(Text, { color: "green", children: "+ New Endpoint" })] }), endpoints.map((ep, idx) => {
517
+ const listIdx = idx + 1;
518
+ const isSelected = listIdx === selectedIndex;
519
+ return (_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: isSelected ? '▶' : ' ' }) }), _jsx(Box, { width: 46, children: _jsxs(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: [ep.url.slice(0, 44), ep.url.length > 44 ? '…' : ''] }) }), _jsx(Box, { width: 12, children: formatCircuitState(ep.circuitState || ep.circuit_state) }), _jsx(Box, { width: 8, children: _jsx(Text, { color: ep.is_active ? 'green' : 'red', children: ep.is_active ? 'Active' : 'Off' }) })] }, ep.id));
520
+ })] })] })), activeSubTab === 'messages' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { bold: true, children: ["Recent Messages (", messages.length, ")"] }), _jsx(Text, { dimColor: true, children: " | Enter: details | y: retry" })] }), messages.length === 0 ? (_jsx(Text, { dimColor: true, children: "No messages. Send events with: hookbase outbound send" })) : (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { borderBottom: true, marginBottom: 0, children: [_jsx(Box, { width: 2, children: _jsx(Text, { children: " " }) }), _jsx(Box, { width: 10, children: _jsx(Text, { bold: true, dimColor: true, children: "Time" }) }), _jsx(Box, { width: 22, children: _jsx(Text, { bold: true, dimColor: true, children: "Event Type" }) }), _jsx(Box, { width: 12, children: _jsx(Text, { bold: true, dimColor: true, children: "Status" }) }), _jsx(Box, { width: 10, children: _jsx(Text, { bold: true, dimColor: true, children: "Response" }) }), _jsx(Box, { width: 12, children: _jsx(Text, { bold: true, dimColor: true, children: "Attempts" }) }), _jsx(Box, { width: 14, children: _jsx(Text, { bold: true, dimColor: true, children: "ID" }) })] }), messages.slice(0, 15).map((msg, idx) => {
521
+ const m = msg;
522
+ const isSelected = idx === selectedIndex;
523
+ const createdAt = m.created_at || m.createdAt || '';
524
+ const d = createdAt ? new Date(createdAt) : null;
525
+ const time = d ? `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}:${d.getSeconds().toString().padStart(2, '0')}` : '-';
526
+ const eventType = m.event_type || m.eventType || '-';
527
+ const respStatus = m.response_status || m.responseStatus;
528
+ const attempts = `${m.attempt_count ?? m.attemptCount ?? 0}/${m.max_attempts ?? m.maxAttempts ?? 5}`;
529
+ return (_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: isSelected ? '▶' : ' ' }) }), _jsx(Box, { width: 10, children: _jsx(Text, { dimColor: true, children: time }) }), _jsx(Box, { width: 22, children: _jsx(Text, { color: isSelected ? 'cyan' : undefined, children: eventType.slice(0, 20) }) }), _jsx(Box, { width: 12, children: formatStatus(msg.status) }), _jsx(Box, { width: 10, children: _jsx(Text, { color: respStatus >= 200 && respStatus < 300 ? 'green' : respStatus ? 'red' : 'gray', children: respStatus || '-' }) }), _jsx(Box, { width: 12, children: _jsx(Text, { dimColor: true, children: attempts }) }), _jsxs(Text, { dimColor: true, children: [msg.id.slice(0, 12), "\u2026"] })] }, msg.id));
530
+ })] }))] })), activeSubTab === 'dlq' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { bold: true, children: ["Dead Letter Queue (", dlqMessages.length, ")"] }), _jsx(Text, { dimColor: true, children: " | Enter: details | y: retry" })] }), dlqMessages.length === 0 ? (_jsx(Text, { color: "green", children: "No messages in DLQ" })) : (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [_jsxs(Box, { borderBottom: true, marginBottom: 0, children: [_jsx(Box, { width: 2, children: _jsx(Text, { children: " " }) }), _jsx(Box, { width: 10, children: _jsx(Text, { bold: true, dimColor: true, children: "Time" }) }), _jsx(Box, { width: 20, children: _jsx(Text, { bold: true, dimColor: true, children: "Event Type" }) }), _jsx(Box, { width: 20, children: _jsx(Text, { bold: true, dimColor: true, children: "Reason" }) }), _jsx(Box, { width: 10, children: _jsx(Text, { bold: true, dimColor: true, children: "Response" }) }), _jsx(Box, { width: 10, children: _jsx(Text, { bold: true, dimColor: true, children: "Attempts" }) }), _jsx(Box, { width: 14, children: _jsx(Text, { bold: true, dimColor: true, children: "ID" }) })] }), dlqMessages.slice(0, 15).map((msg, idx) => {
531
+ const m = msg;
532
+ const isSelected = idx === selectedIndex;
533
+ const createdAt = m.created_at || m.createdAt || '';
534
+ const d = createdAt ? new Date(createdAt) : null;
535
+ const time = d ? `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}:${d.getSeconds().toString().padStart(2, '0')}` : '-';
536
+ const eventType = m.event_type || m.eventType || '-';
537
+ const reason = m.reason || '-';
538
+ const lastResp = m.last_response_status || m.lastResponseStatus;
539
+ const attempts = m.attempt_count ?? m.attemptCount ?? 0;
540
+ return (_jsxs(Box, { children: [_jsx(Box, { width: 2, children: _jsx(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: isSelected ? '▶' : ' ' }) }), _jsx(Box, { width: 10, children: _jsx(Text, { dimColor: true, children: time }) }), _jsx(Box, { width: 20, children: _jsx(Text, { color: isSelected ? 'cyan' : undefined, children: eventType.slice(0, 18) }) }), _jsx(Box, { width: 20, children: _jsx(Text, { color: "red", children: reason.slice(0, 18) }) }), _jsx(Box, { width: 10, children: _jsx(Text, { color: lastResp ? 'red' : 'gray', children: lastResp || '-' }) }), _jsx(Box, { width: 10, children: _jsx(Text, { dimColor: true, children: attempts }) }), _jsxs(Text, { dimColor: true, children: [msg.id.slice(0, 12), "\u2026"] })] }, msg.id));
541
+ })] }))] }))] }));
542
+ }
543
+ //# sourceMappingURL=Outbound.js.map