thepopebot 1.2.81 → 1.2.82
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/lib/chat/actions.js
CHANGED
|
@@ -1018,12 +1018,19 @@ export async function regenerateWebhookSecret(key) {
|
|
|
1018
1018
|
export async function getTelegramStatus() {
|
|
1019
1019
|
await requireAuth();
|
|
1020
1020
|
try {
|
|
1021
|
-
const { getConfigSecret } = await import('../db/config.js');
|
|
1021
|
+
const { getConfigSecret, getConfigValue } = await import('../db/config.js');
|
|
1022
|
+
const { getConfig } = await import('../config.js');
|
|
1022
1023
|
const { validateBotToken, getTelegramWebhookInfo } = await import('../tools/telegram.js');
|
|
1023
1024
|
|
|
1024
1025
|
const botToken = getConfigSecret('TELEGRAM_BOT_TOKEN');
|
|
1025
1026
|
const webhookSecret = getConfigSecret('TELEGRAM_WEBHOOK_SECRET');
|
|
1026
1027
|
|
|
1028
|
+
const appUrl = getConfig('APP_URL');
|
|
1029
|
+
const defaultWebhookUrl = appUrl
|
|
1030
|
+
? `${appUrl.replace(/\/$/, '')}/api/telegram/webhook`
|
|
1031
|
+
: '';
|
|
1032
|
+
const webhookUrlOverride = getConfigValue('TELEGRAM_WEBHOOK_URL') || null;
|
|
1033
|
+
|
|
1027
1034
|
let botInfo = null;
|
|
1028
1035
|
let webhookInfo = null;
|
|
1029
1036
|
if (botToken) {
|
|
@@ -1049,6 +1056,8 @@ export async function getTelegramStatus() {
|
|
|
1049
1056
|
botTokenSet: !!botToken,
|
|
1050
1057
|
webhookSecretSet: !!webhookSecret,
|
|
1051
1058
|
webhookInfo,
|
|
1059
|
+
defaultWebhookUrl,
|
|
1060
|
+
webhookUrlOverride,
|
|
1052
1061
|
};
|
|
1053
1062
|
} catch (err) {
|
|
1054
1063
|
console.error('Failed to get Telegram status:', err);
|
|
@@ -1078,12 +1087,20 @@ export async function validateTelegramToken(token) {
|
|
|
1078
1087
|
/**
|
|
1079
1088
|
* Register the Telegram webhook with the currently saved bot token.
|
|
1080
1089
|
* Generates a fresh webhook secret, saves it, and calls Telegram's setWebhook.
|
|
1081
|
-
*
|
|
1082
|
-
|
|
1083
|
-
|
|
1090
|
+
*
|
|
1091
|
+
* URL resolution:
|
|
1092
|
+
* - explicit `webhookUrl` arg (persisted as override if it differs from default)
|
|
1093
|
+
* - stored `TELEGRAM_WEBHOOK_URL` override
|
|
1094
|
+
* - `${APP_URL}/api/telegram/webhook` default
|
|
1095
|
+
*
|
|
1096
|
+
* Pass an empty string for `webhookUrl` to clear the override and fall back
|
|
1097
|
+
* to the APP_URL-derived default.
|
|
1098
|
+
*/
|
|
1099
|
+
export async function registerTelegramWebhook(webhookUrl) {
|
|
1084
1100
|
const user = await requireAdmin();
|
|
1085
1101
|
try {
|
|
1086
|
-
const { getConfigSecret, setConfigSecret } =
|
|
1102
|
+
const { getConfigSecret, setConfigSecret, getConfigValue, setConfigValue, deleteConfigValue } =
|
|
1103
|
+
await import('../db/config.js');
|
|
1087
1104
|
const { getConfig } = await import('../config.js');
|
|
1088
1105
|
const { setTelegramWebhook, generateWebhookSecret } = await import('../tools/telegram.js');
|
|
1089
1106
|
|
|
@@ -1091,17 +1108,43 @@ export async function registerTelegramWebhook() {
|
|
|
1091
1108
|
if (!botToken) return { error: 'Bot token must be set first' };
|
|
1092
1109
|
|
|
1093
1110
|
const appUrl = getConfig('APP_URL');
|
|
1094
|
-
|
|
1111
|
+
const defaultUrl = appUrl ? `${appUrl.replace(/\/$/, '')}/api/telegram/webhook` : '';
|
|
1112
|
+
|
|
1113
|
+
// Resolve the URL to register.
|
|
1114
|
+
let urlToRegister;
|
|
1115
|
+
if (typeof webhookUrl === 'string') {
|
|
1116
|
+
const trimmed = webhookUrl.trim();
|
|
1117
|
+
if (!trimmed || trimmed === defaultUrl) {
|
|
1118
|
+
deleteConfigValue('TELEGRAM_WEBHOOK_URL');
|
|
1119
|
+
urlToRegister = trimmed || defaultUrl;
|
|
1120
|
+
} else {
|
|
1121
|
+
setConfigValue('TELEGRAM_WEBHOOK_URL', trimmed, user.id);
|
|
1122
|
+
urlToRegister = trimmed;
|
|
1123
|
+
}
|
|
1124
|
+
} else {
|
|
1125
|
+
urlToRegister = getConfigValue('TELEGRAM_WEBHOOK_URL') || defaultUrl;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
if (!urlToRegister) {
|
|
1129
|
+
return { error: 'Webhook URL is required (set APP_URL or supply a URL)' };
|
|
1130
|
+
}
|
|
1131
|
+
try {
|
|
1132
|
+
const parsed = new URL(urlToRegister);
|
|
1133
|
+
if (parsed.protocol !== 'https:') {
|
|
1134
|
+
return { error: 'Webhook URL must use https://' };
|
|
1135
|
+
}
|
|
1136
|
+
} catch {
|
|
1137
|
+
return { error: 'Webhook URL is not a valid URL' };
|
|
1138
|
+
}
|
|
1095
1139
|
|
|
1096
|
-
const webhookUrl = `${appUrl.replace(/\/$/, '')}/api/telegram/webhook`;
|
|
1097
1140
|
const secret = generateWebhookSecret();
|
|
1098
1141
|
setConfigSecret('TELEGRAM_WEBHOOK_SECRET', secret, user.id);
|
|
1099
1142
|
|
|
1100
|
-
const result = await setTelegramWebhook(botToken,
|
|
1143
|
+
const result = await setTelegramWebhook(botToken, urlToRegister, secret);
|
|
1101
1144
|
if (!result.ok) {
|
|
1102
1145
|
return { error: result.description || 'Failed to register webhook' };
|
|
1103
1146
|
}
|
|
1104
|
-
return { success: true, webhookUrl };
|
|
1147
|
+
return { success: true, webhookUrl: urlToRegister };
|
|
1105
1148
|
} catch (err) {
|
|
1106
1149
|
console.error('Failed to register Telegram webhook:', err);
|
|
1107
1150
|
return { error: err.message };
|
|
@@ -273,6 +273,8 @@ function ApiKeysTelegramPage() {
|
|
|
273
273
|
const [tokenError, setTokenError] = useState(null);
|
|
274
274
|
const [webhookSaving, setWebhookSaving] = useState(false);
|
|
275
275
|
const [webhookError, setWebhookError] = useState(null);
|
|
276
|
+
const [webhookEditing, setWebhookEditing] = useState(false);
|
|
277
|
+
const [webhookUrlInput, setWebhookUrlInput] = useState("");
|
|
276
278
|
const loadStatus = async () => {
|
|
277
279
|
try {
|
|
278
280
|
const result = await getTelegramStatus();
|
|
@@ -284,6 +286,12 @@ function ApiKeysTelegramPage() {
|
|
|
284
286
|
useEffect(() => {
|
|
285
287
|
loadStatus();
|
|
286
288
|
}, []);
|
|
289
|
+
useEffect(() => {
|
|
290
|
+
if (!status || webhookEditing) return;
|
|
291
|
+
setWebhookUrlInput(
|
|
292
|
+
status.webhookUrlOverride || status.webhookInfo?.url || status.defaultWebhookUrl || ""
|
|
293
|
+
);
|
|
294
|
+
}, [status, webhookEditing]);
|
|
287
295
|
if (loading) {
|
|
288
296
|
return /* @__PURE__ */ jsx("div", { className: "h-48 animate-pulse rounded-md bg-border/50" });
|
|
289
297
|
}
|
|
@@ -318,11 +326,33 @@ function ApiKeysTelegramPage() {
|
|
|
318
326
|
const handleRegisterWebhook = async () => {
|
|
319
327
|
setWebhookSaving(true);
|
|
320
328
|
setWebhookError(null);
|
|
321
|
-
const
|
|
322
|
-
|
|
329
|
+
const url = webhookEditing ? webhookUrlInput.trim() : void 0;
|
|
330
|
+
const result = await registerTelegramWebhook(url);
|
|
331
|
+
if (result?.error) {
|
|
332
|
+
setWebhookError(result.error);
|
|
333
|
+
setWebhookSaving(false);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
setWebhookEditing(false);
|
|
337
|
+
setWebhookUrlInput("");
|
|
323
338
|
await loadStatus();
|
|
324
339
|
setWebhookSaving(false);
|
|
325
340
|
};
|
|
341
|
+
const startWebhookEdit = () => {
|
|
342
|
+
setWebhookError(null);
|
|
343
|
+
setWebhookUrlInput(
|
|
344
|
+
status.webhookUrlOverride || status.webhookInfo?.url || status.defaultWebhookUrl || ""
|
|
345
|
+
);
|
|
346
|
+
setWebhookEditing(true);
|
|
347
|
+
};
|
|
348
|
+
const cancelWebhookEdit = () => {
|
|
349
|
+
setWebhookEditing(false);
|
|
350
|
+
setWebhookUrlInput("");
|
|
351
|
+
setWebhookError(null);
|
|
352
|
+
};
|
|
353
|
+
const resetWebhookToDefault = () => {
|
|
354
|
+
setWebhookUrlInput(status.defaultWebhookUrl || "");
|
|
355
|
+
};
|
|
326
356
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
327
357
|
/* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
|
|
328
358
|
/* @__PURE__ */ jsx("h2", { className: "text-base font-medium", children: "Telegram" }),
|
|
@@ -417,33 +447,75 @@ function ApiKeysTelegramPage() {
|
|
|
417
447
|
/* @__PURE__ */ jsx("div", { className: `rounded-lg border bg-card p-4 ${!step1Done ? "opacity-50 pointer-events-none" : ""}`, children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
418
448
|
/* @__PURE__ */ jsx(StepIndicator, { n: 2, state: step2Done ? "done" : step1Done ? "active" : "pending" }),
|
|
419
449
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
420
|
-
/* @__PURE__ */
|
|
421
|
-
/* @__PURE__ */
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
/* @__PURE__ */
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
"
|
|
432
|
-
|
|
450
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
451
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
452
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "Webhook" }),
|
|
453
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: "Register a public URL with Telegram so it can deliver messages to your bot." }),
|
|
454
|
+
step2Done && !webhookEditing && /* @__PURE__ */ jsxs("div", { className: "mt-2 text-xs text-muted-foreground truncate", children: [
|
|
455
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono", children: status.webhookInfo.url }),
|
|
456
|
+
status.webhookInfo.pendingUpdates > 0 && /* @__PURE__ */ jsxs("span", { className: "ml-2 text-yellow-500", children: [
|
|
457
|
+
"(",
|
|
458
|
+
status.webhookInfo.pendingUpdates,
|
|
459
|
+
" pending)"
|
|
460
|
+
] }),
|
|
461
|
+
status.webhookInfo.lastErrorMessage && /* @__PURE__ */ jsxs("div", { className: "mt-1 text-destructive", children: [
|
|
462
|
+
"Last error: ",
|
|
463
|
+
status.webhookInfo.lastErrorMessage
|
|
464
|
+
] })
|
|
433
465
|
] })
|
|
434
|
-
] })
|
|
435
|
-
|
|
436
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-3", children: [
|
|
437
|
-
webhookError && /* @__PURE__ */ jsx("div", { className: "text-xs text-destructive mb-2", children: webhookError }),
|
|
438
|
-
/* @__PURE__ */ jsx(
|
|
466
|
+
] }),
|
|
467
|
+
step2Done && !webhookEditing && /* @__PURE__ */ jsx(
|
|
439
468
|
"button",
|
|
440
469
|
{
|
|
441
|
-
onClick:
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
children: webhookSaving ? "Registering..." : step2Done ? "Re-register Webhook" : "Register Webhook"
|
|
470
|
+
onClick: startWebhookEdit,
|
|
471
|
+
className: "shrink-0 text-xs text-muted-foreground hover:text-foreground underline transition-colors",
|
|
472
|
+
children: "Change"
|
|
445
473
|
}
|
|
446
474
|
)
|
|
475
|
+
] }),
|
|
476
|
+
(!step2Done || webhookEditing) && /* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-col gap-2", children: [
|
|
477
|
+
/* @__PURE__ */ jsx(
|
|
478
|
+
"input",
|
|
479
|
+
{
|
|
480
|
+
type: "text",
|
|
481
|
+
value: webhookUrlInput,
|
|
482
|
+
onChange: (e) => {
|
|
483
|
+
if (!webhookEditing) setWebhookEditing(true);
|
|
484
|
+
setWebhookUrlInput(e.target.value);
|
|
485
|
+
},
|
|
486
|
+
placeholder: "https://example.com/api/telegram/webhook",
|
|
487
|
+
spellCheck: false,
|
|
488
|
+
className: "rounded-md border border-border bg-background px-3 py-1.5 text-sm font-mono focus:outline-none focus:ring-1 focus:ring-foreground"
|
|
489
|
+
}
|
|
490
|
+
),
|
|
491
|
+
webhookError && /* @__PURE__ */ jsx("div", { className: "text-xs text-destructive", children: webhookError }),
|
|
492
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
493
|
+
/* @__PURE__ */ jsx(
|
|
494
|
+
"button",
|
|
495
|
+
{
|
|
496
|
+
onClick: handleRegisterWebhook,
|
|
497
|
+
disabled: !step1Done || webhookSaving || !webhookUrlInput.trim(),
|
|
498
|
+
className: "rounded-md bg-foreground text-background px-2.5 py-1.5 text-xs font-medium hover:bg-foreground/90 disabled:opacity-50 transition-colors",
|
|
499
|
+
children: webhookSaving ? "Registering..." : step2Done ? "Re-register Webhook" : "Register Webhook"
|
|
500
|
+
}
|
|
501
|
+
),
|
|
502
|
+
webhookEditing && step2Done && /* @__PURE__ */ jsx(
|
|
503
|
+
"button",
|
|
504
|
+
{
|
|
505
|
+
onClick: cancelWebhookEdit,
|
|
506
|
+
className: "rounded-md border border-border px-2.5 py-1.5 text-xs font-medium text-muted-foreground hover:text-foreground transition-colors",
|
|
507
|
+
children: "Cancel"
|
|
508
|
+
}
|
|
509
|
+
),
|
|
510
|
+
status.defaultWebhookUrl && webhookUrlInput.trim() !== status.defaultWebhookUrl && /* @__PURE__ */ jsx(
|
|
511
|
+
"button",
|
|
512
|
+
{
|
|
513
|
+
onClick: resetWebhookToDefault,
|
|
514
|
+
className: "ml-auto text-xs text-muted-foreground hover:text-foreground underline transition-colors",
|
|
515
|
+
children: "Reset to default"
|
|
516
|
+
}
|
|
517
|
+
)
|
|
518
|
+
] })
|
|
447
519
|
] })
|
|
448
520
|
] })
|
|
449
521
|
] }) })
|
|
@@ -329,6 +329,8 @@ export function ApiKeysTelegramPage() {
|
|
|
329
329
|
// Step 2 — webhook
|
|
330
330
|
const [webhookSaving, setWebhookSaving] = useState(false);
|
|
331
331
|
const [webhookError, setWebhookError] = useState(null);
|
|
332
|
+
const [webhookEditing, setWebhookEditing] = useState(false);
|
|
333
|
+
const [webhookUrlInput, setWebhookUrlInput] = useState('');
|
|
332
334
|
|
|
333
335
|
const loadStatus = async () => {
|
|
334
336
|
try {
|
|
@@ -343,6 +345,16 @@ export function ApiKeysTelegramPage() {
|
|
|
343
345
|
loadStatus();
|
|
344
346
|
}, []);
|
|
345
347
|
|
|
348
|
+
// Keep the webhook URL input in sync with the saved/effective URL when not
|
|
349
|
+
// actively editing — covers the "unregistered" case where the field needs
|
|
350
|
+
// to be prefilled with the default so the user can just hit Register.
|
|
351
|
+
useEffect(() => {
|
|
352
|
+
if (!status || webhookEditing) return;
|
|
353
|
+
setWebhookUrlInput(
|
|
354
|
+
status.webhookUrlOverride || status.webhookInfo?.url || status.defaultWebhookUrl || ''
|
|
355
|
+
);
|
|
356
|
+
}, [status, webhookEditing]);
|
|
357
|
+
|
|
346
358
|
if (loading) {
|
|
347
359
|
return <div className="h-48 animate-pulse rounded-md bg-border/50" />;
|
|
348
360
|
}
|
|
@@ -383,12 +395,37 @@ export function ApiKeysTelegramPage() {
|
|
|
383
395
|
const handleRegisterWebhook = async () => {
|
|
384
396
|
setWebhookSaving(true);
|
|
385
397
|
setWebhookError(null);
|
|
386
|
-
const
|
|
387
|
-
|
|
398
|
+
const url = webhookEditing ? webhookUrlInput.trim() : undefined;
|
|
399
|
+
const result = await registerTelegramWebhook(url);
|
|
400
|
+
if (result?.error) {
|
|
401
|
+
setWebhookError(result.error);
|
|
402
|
+
setWebhookSaving(false);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
setWebhookEditing(false);
|
|
406
|
+
setWebhookUrlInput('');
|
|
388
407
|
await loadStatus();
|
|
389
408
|
setWebhookSaving(false);
|
|
390
409
|
};
|
|
391
410
|
|
|
411
|
+
const startWebhookEdit = () => {
|
|
412
|
+
setWebhookError(null);
|
|
413
|
+
setWebhookUrlInput(
|
|
414
|
+
status.webhookUrlOverride || status.webhookInfo?.url || status.defaultWebhookUrl || ''
|
|
415
|
+
);
|
|
416
|
+
setWebhookEditing(true);
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
const cancelWebhookEdit = () => {
|
|
420
|
+
setWebhookEditing(false);
|
|
421
|
+
setWebhookUrlInput('');
|
|
422
|
+
setWebhookError(null);
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
const resetWebhookToDefault = () => {
|
|
426
|
+
setWebhookUrlInput(status.defaultWebhookUrl || '');
|
|
427
|
+
};
|
|
428
|
+
|
|
392
429
|
return (
|
|
393
430
|
<div>
|
|
394
431
|
<div className="mb-4">
|
|
@@ -488,9 +525,9 @@ export function ApiKeysTelegramPage() {
|
|
|
488
525
|
<div className="min-w-0">
|
|
489
526
|
<h3 className="text-sm font-medium">Webhook</h3>
|
|
490
527
|
<p className="text-xs text-muted-foreground mt-0.5">
|
|
491
|
-
Register
|
|
528
|
+
Register a public URL with Telegram so it can deliver messages to your bot.
|
|
492
529
|
</p>
|
|
493
|
-
{step2Done && (
|
|
530
|
+
{step2Done && !webhookEditing && (
|
|
494
531
|
<div className="mt-2 text-xs text-muted-foreground truncate">
|
|
495
532
|
<span className="font-mono">{status.webhookInfo.url}</span>
|
|
496
533
|
{status.webhookInfo.pendingUpdates > 0 && (
|
|
@@ -506,24 +543,62 @@ export function ApiKeysTelegramPage() {
|
|
|
506
543
|
</div>
|
|
507
544
|
)}
|
|
508
545
|
</div>
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
546
|
+
{step2Done && !webhookEditing && (
|
|
547
|
+
<button
|
|
548
|
+
onClick={startWebhookEdit}
|
|
549
|
+
className="shrink-0 text-xs text-muted-foreground hover:text-foreground underline transition-colors"
|
|
550
|
+
>
|
|
551
|
+
Change
|
|
552
|
+
</button>
|
|
514
553
|
)}
|
|
515
|
-
<button
|
|
516
|
-
onClick={handleRegisterWebhook}
|
|
517
|
-
disabled={!step1Done || webhookSaving}
|
|
518
|
-
className="rounded-md bg-foreground text-background px-2.5 py-1.5 text-xs font-medium hover:bg-foreground/90 disabled:opacity-50 transition-colors"
|
|
519
|
-
>
|
|
520
|
-
{webhookSaving
|
|
521
|
-
? 'Registering...'
|
|
522
|
-
: step2Done
|
|
523
|
-
? 'Re-register Webhook'
|
|
524
|
-
: 'Register Webhook'}
|
|
525
|
-
</button>
|
|
526
554
|
</div>
|
|
555
|
+
|
|
556
|
+
{(!step2Done || webhookEditing) && (
|
|
557
|
+
<div className="mt-3 flex flex-col gap-2">
|
|
558
|
+
<input
|
|
559
|
+
type="text"
|
|
560
|
+
value={webhookUrlInput}
|
|
561
|
+
onChange={(e) => {
|
|
562
|
+
if (!webhookEditing) setWebhookEditing(true);
|
|
563
|
+
setWebhookUrlInput(e.target.value);
|
|
564
|
+
}}
|
|
565
|
+
placeholder="https://example.com/api/telegram/webhook"
|
|
566
|
+
spellCheck={false}
|
|
567
|
+
className="rounded-md border border-border bg-background px-3 py-1.5 text-sm font-mono focus:outline-none focus:ring-1 focus:ring-foreground"
|
|
568
|
+
/>
|
|
569
|
+
{webhookError && <div className="text-xs text-destructive">{webhookError}</div>}
|
|
570
|
+
<div className="flex items-center gap-2">
|
|
571
|
+
<button
|
|
572
|
+
onClick={handleRegisterWebhook}
|
|
573
|
+
disabled={!step1Done || webhookSaving || !webhookUrlInput.trim()}
|
|
574
|
+
className="rounded-md bg-foreground text-background px-2.5 py-1.5 text-xs font-medium hover:bg-foreground/90 disabled:opacity-50 transition-colors"
|
|
575
|
+
>
|
|
576
|
+
{webhookSaving
|
|
577
|
+
? 'Registering...'
|
|
578
|
+
: step2Done
|
|
579
|
+
? 'Re-register Webhook'
|
|
580
|
+
: 'Register Webhook'}
|
|
581
|
+
</button>
|
|
582
|
+
{webhookEditing && step2Done && (
|
|
583
|
+
<button
|
|
584
|
+
onClick={cancelWebhookEdit}
|
|
585
|
+
className="rounded-md border border-border px-2.5 py-1.5 text-xs font-medium text-muted-foreground hover:text-foreground transition-colors"
|
|
586
|
+
>
|
|
587
|
+
Cancel
|
|
588
|
+
</button>
|
|
589
|
+
)}
|
|
590
|
+
{status.defaultWebhookUrl &&
|
|
591
|
+
webhookUrlInput.trim() !== status.defaultWebhookUrl && (
|
|
592
|
+
<button
|
|
593
|
+
onClick={resetWebhookToDefault}
|
|
594
|
+
className="ml-auto text-xs text-muted-foreground hover:text-foreground underline transition-colors"
|
|
595
|
+
>
|
|
596
|
+
Reset to default
|
|
597
|
+
</button>
|
|
598
|
+
)}
|
|
599
|
+
</div>
|
|
600
|
+
</div>
|
|
601
|
+
)}
|
|
527
602
|
</div>
|
|
528
603
|
</div>
|
|
529
604
|
</div>
|
package/lib/config.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Config resolver. Reads from DB, falls back to defaults.
|
|
3
|
-
* In-memory cache, invalidated on config writes.
|
|
4
3
|
*
|
|
5
4
|
* Usage:
|
|
6
5
|
* import { getConfig } from '../config.js';
|
|
@@ -63,6 +62,7 @@ const CONFIG_KEYS = new Set([
|
|
|
63
62
|
'CODE_MODE_GIT_ACTION',
|
|
64
63
|
'AGENT_MODE_AUTO_RUN',
|
|
65
64
|
'CODE_MODE_AUTO_RUN',
|
|
65
|
+
'TELEGRAM_WEBHOOK_URL',
|
|
66
66
|
]);
|
|
67
67
|
|
|
68
68
|
// Default values
|