mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-07-26 11:49:16 +00:00
83b3d932e5
* feat: add Apprise as a fourth notification channel Support keyed and stateless Apprise endpoints with secret-safe public DTOs, fail-closed malformed config, and mode-specific Settings UI. Docs and screenshots updated for four-channel Channels and routing. * fix: harden Apprise secrets at rest and preserve-on-write saves Encrypt Apprise endpoint and config with CryptoService so a downgrade cannot leak via SELECT *. Align channel and routing saves so blank destination fields omit config on same-mode URL edits, enforce keyed notify IDs, and keep secrets_redacted truthful. * fix: harden Apprise route type changes and mixed-version config UI Require a raw channel_url when switching notification-route types so ciphertext cannot strand under Discord/Slack/webhook. Default missing remote apprise status, replace Channels state on node switch, and exercise the production config-column migrator. * fix: tolerate stub fleet configuration payloads without agents Normalize remote Apprise agent status only when notifications.agents is present so successful Pilot/stub fetches stay online instead of throwing into the offline catch path. * fix: correct TypeScript in configuration normalize tests * fix: ignore stale Channels agent bodies after node switch Compare the active node after response JSON parsing so a slow body cannot overwrite the newly selected node's channel state. * fix: isolate corrupt Apprise crypto and keep keyed Tags visible Decrypt failures on one Apprise row no longer 500 agent/route lists or suppress sibling channel dispatch. Treat public /notify/<redacted> as keyed so Tags remain editable after reload.
48 lines
1.4 KiB
TypeScript
48 lines
1.4 KiB
TypeScript
/** Agent slot on dashboard/fleet configuration responses. */
|
|
export interface AgentStatus {
|
|
configured: boolean;
|
|
enabled: boolean;
|
|
}
|
|
|
|
export type ConfigurationAgents = {
|
|
discord: AgentStatus;
|
|
slack: AgentStatus;
|
|
webhook: AgentStatus;
|
|
apprise: AgentStatus;
|
|
};
|
|
|
|
/**
|
|
* Older remotes omit `apprise`. Default the slot so mixed-version hubs do not
|
|
* treat the response as malformed or crash UI consumers.
|
|
*/
|
|
export function normalizeConfigurationAgents(agents: {
|
|
discord: AgentStatus;
|
|
slack: AgentStatus;
|
|
webhook: AgentStatus;
|
|
apprise?: AgentStatus;
|
|
}): ConfigurationAgents {
|
|
return {
|
|
discord: agents.discord,
|
|
slack: agents.slack,
|
|
webhook: agents.webhook,
|
|
apprise: agents.apprise ?? { configured: false, enabled: false },
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Normalize a remote `/dashboard/configuration` body when it carries an agents
|
|
* block. Stub or partial JSON without `notifications.agents` is returned as-is
|
|
* so a successful fetch still marks the node online.
|
|
*/
|
|
export function normalizeRemoteConfigurationStatus<T extends object>(raw: T): T {
|
|
const notifications = (raw as { notifications?: { agents?: Parameters<typeof normalizeConfigurationAgents>[0] } }).notifications;
|
|
if (!notifications?.agents) return raw;
|
|
return {
|
|
...raw,
|
|
notifications: {
|
|
...notifications,
|
|
agents: normalizeConfigurationAgents(notifications.agents),
|
|
},
|
|
};
|
|
}
|