feat(api): integrate identity, notification scope and connection settings into control plane

- Wire identity, metrics and update services into the assembled API.

- Add connection authorization modes and scoped console authorization.

- Preserve notification group IDs for filtered delivery.

- Extend maintenance, backup, resource and module flows with runtime metadata and upstream safety.
This commit is contained in:
chick
2026-09-07 00:45:18 +08:00
parent 7168e9dba2
commit 635527dd26
22 changed files with 754 additions and 46 deletions
@@ -8,6 +8,7 @@ import type Database from 'better-sqlite3';
export interface ConnectionSettings {
readonly heartbeatSeconds: number;
readonly offlineSeconds: number;
readonly authorizationMode: 'auto' | 'manual';
}
export const MIN_HEARTBEAT_SECONDS = 5;
@@ -17,11 +18,16 @@ export const MAX_OFFLINE_SECONDS = 1_800;
export const DEFAULT_CONNECTION_SETTINGS: Readonly<ConnectionSettings> = Object.freeze({
heartbeatSeconds: 30,
offlineSeconds: 90,
authorizationMode: 'auto',
});
const SETTING_KEY = 'connection.settings';
const FIELDS: readonly (keyof ConnectionSettings)[] = ['heartbeatSeconds', 'offlineSeconds'];
const FIELDS: readonly (keyof ConnectionSettings)[] = [
'heartbeatSeconds',
'offlineSeconds',
'authorizationMode',
];
function safeInteger(value: unknown, name: string): number {
if (!Number.isSafeInteger(value))
@@ -40,6 +46,13 @@ export function validateConnectionSettings(value: unknown): ConnectionSettings {
);
if (unknown.length > 0) throw new TypeError(`Unknown connection setting: ${unknown[0]}`);
const authorizationMode =
source.authorizationMode === undefined
? DEFAULT_CONNECTION_SETTINGS.authorizationMode
: source.authorizationMode;
if (authorizationMode !== 'auto' && authorizationMode !== 'manual')
throw new TypeError('authorizationMode must be auto or manual');
const heartbeatSeconds = safeInteger(
source.heartbeatSeconds ?? DEFAULT_CONNECTION_SETTINGS.heartbeatSeconds,
'heartbeatSeconds',
@@ -59,7 +72,7 @@ export function validateConnectionSettings(value: unknown): ConnectionSettings {
if (offlineSeconds > MAX_OFFLINE_SECONDS)
throw new RangeError(`offlineSeconds must not exceed ${MAX_OFFLINE_SECONDS}`);
return { heartbeatSeconds, offlineSeconds };
return { heartbeatSeconds, offlineSeconds, authorizationMode };
}
interface SettingsRow {