SnowLuma v2.4.2 source snapshot
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run

This commit is contained in:
TanTan committed 2026-11-13 09:02:00 +08:00
commit fa9c73363d
1367 files changed
+355735

No files matched your search

+325
View File
@@ -0,0 +1,325 @@
import { isObject } from '@snowluma/common/coerce';
import type { LogStoragePolicy, LogStorageStatus } from '@snowluma/common/log-file-transport';
import {
DEFAULT_LOG_MAX_TOTAL_MB,
DEFAULT_LOG_PER_UIN,
DEFAULT_LOG_RETAIN_DAYS,
MAX_LOG_RETAIN_DAYS,
MAX_LOG_TOTAL_MB,
type RuntimeConfig,
} from '@snowluma/common/runtime';
import { publicLogStorageStatus, type PublicLogStorageStatus } from './storage-management';
export type LogStorageSettingsField = 'logMaxTotalMb' | 'logRetainDays' | 'logPerUin';
export interface LogStorageSettings {
logMaxTotalMb: number;
logRetainDays: number;
logPerUin: boolean;
}
export interface LogStorageSettingsState {
saved: LogStorageSettings;
effective: LogStorageSettings;
envOverrides: LogStorageSettingsField[];
}
export interface LogStorageSettingsUpdateResult {
settings: LogStorageSettingsState;
status: PublicLogStorageStatus;
}
export class StorageSettingsInputError extends Error {
constructor(message: string) {
super(message);
this.name = 'StorageSettingsInputError';
}
}
export class StorageSettingsLockedError extends Error {
constructor(readonly fields: LogStorageSettingsField[]) {
super(`settings are locked by environment variables: ${fields.join(', ')}`);
this.name = 'StorageSettingsLockedError';
}
}
export class StorageSettingsTransactionError extends Error {
constructor(
message: string,
readonly operationError: unknown,
readonly rollbackErrors: unknown[],
) {
super(message, { cause: operationError });
this.name = 'StorageSettingsTransactionError';
}
}
export interface LogStorageSettingsDependencies {
readPersisted(): RuntimeConfig;
readEnvOverrides(): Partial<RuntimeConfig>;
readEffective(): LogStorageStatus;
persist(patch: Partial<RuntimeConfig>): RuntimeConfig;
apply(policy: LogStoragePolicy): Promise<LogStorageStatus>;
}
const SETTINGS_FIELDS: LogStorageSettingsField[] = ['logMaxTotalMb', 'logRetainDays', 'logPerUin'];
const SETTINGS_FIELD_SET = new Set<string>(SETTINGS_FIELDS);
export class LogStorageSettingsManager {
private updateQueue: Promise<void> = Promise.resolve();
constructor(private readonly deps: LogStorageSettingsDependencies) {}
read(): LogStorageSettingsState {
return settingsState(
this.deps.readPersisted(),
this.deps.readEnvOverrides(),
settingsFromStatus(this.deps.readEffective()),
);
}
update(body: unknown): Promise<LogStorageSettingsUpdateResult> {
const operation = this.updateQueue.then(() => this.performUpdate(body));
this.updateQueue = operation.then(
() => undefined,
() => undefined,
);
return operation;
}
private async performUpdate(body: unknown): Promise<LogStorageSettingsUpdateResult> {
const patch = coerceLogStorageSettingsPatch(body);
const previousRuntime = this.deps.readPersisted();
const envOverrides = this.deps.readEnvOverrides();
const previous = settingsState(
previousRuntime,
envOverrides,
settingsFromStatus(this.deps.readEffective()),
);
const locked = SETTINGS_FIELDS.filter((field) => field in patch && field in envOverrides);
if (locked.length > 0) {
throw new StorageSettingsLockedError(locked);
}
const nextSaved = { ...previous.saved, ...patch };
const nextEffective = { ...previous.effective, ...patch };
const previousPolicy = toPolicy(previous.effective);
const nextPolicy = toPolicy(nextEffective);
let status: LogStorageStatus;
try {
status = await this.deps.apply(nextPolicy);
assertApplied(status, nextPolicy);
} catch (error) {
const rollbackErrors = await this.rollbackRuntime(previousPolicy);
throw new StorageSettingsTransactionError(
rollbackErrors.length > 0
? 'failed to apply log settings and runtime rollback was incomplete'
: 'failed to apply log settings; runtime state was rolled back',
error,
rollbackErrors,
);
}
let persistedRuntime: RuntimeConfig;
try {
persistedRuntime = this.deps.persist(patch);
assertPersistedSettings(persistedRuntime, nextSaved);
} catch (error) {
const rollbackErrors = await this.rollbackAll(previousPolicy, previousRuntime);
throw new StorageSettingsTransactionError(
rollbackErrors.length > 0
? 'failed to persist log settings and rollback was incomplete'
: 'failed to persist log settings; previous settings were restored',
error,
rollbackErrors,
);
}
return {
settings: settingsState(persistedRuntime, envOverrides, settingsFromStatus(status)),
status: publicLogStorageStatus(status),
};
}
private async rollbackRuntime(policy: LogStoragePolicy): Promise<unknown[]> {
try {
const status = await this.deps.apply(policy);
assertApplied(status, policy);
return [];
} catch (error) {
return [error];
}
}
private async rollbackAll(
policy: LogStoragePolicy,
runtime: RuntimeConfig,
): Promise<unknown[]> {
const errors = await this.rollbackRuntime(policy);
try {
this.deps.persist(runtime);
} catch (error) {
errors.push(error);
}
return errors;
}
}
function coerceLogStorageSettingsPatch(body: unknown): Partial<LogStorageSettings> {
if (!isObject(body)) {
throw new StorageSettingsInputError('body must be an object');
}
const keys = Object.keys(body);
if (keys.length === 0) {
throw new StorageSettingsInputError('at least one setting is required');
}
const unknown = keys.filter((key) => !SETTINGS_FIELD_SET.has(key));
if (unknown.length > 0) {
throw new StorageSettingsInputError(`unknown setting: ${unknown.join(', ')}`);
}
const patch: Partial<LogStorageSettings> = {};
if ('logMaxTotalMb' in body) {
const value = body.logMaxTotalMb;
if (
typeof value !== 'number' ||
!Number.isSafeInteger(value) ||
value < 1 ||
value > MAX_LOG_TOTAL_MB
) {
throw new StorageSettingsInputError(
`logMaxTotalMb must be an integer in 1..${MAX_LOG_TOTAL_MB}`,
);
}
patch.logMaxTotalMb = value;
}
if ('logRetainDays' in body) {
const value = body.logRetainDays;
if (
typeof value !== 'number' ||
!Number.isSafeInteger(value) ||
value < 0 ||
value > MAX_LOG_RETAIN_DAYS
) {
throw new StorageSettingsInputError(
`logRetainDays must be an integer in 0..${MAX_LOG_RETAIN_DAYS}`,
);
}
patch.logRetainDays = value;
}
if ('logPerUin' in body) {
if (typeof body.logPerUin !== 'boolean') {
throw new StorageSettingsInputError('logPerUin must be a boolean');
}
patch.logPerUin = body.logPerUin;
}
return patch;
}
function settingsState(
runtime: RuntimeConfig,
envOverrides: Partial<RuntimeConfig>,
liveEffective?: LogStorageSettings,
): LogStorageSettingsState {
const saved = settingsFromRuntime(runtime);
const envOverridesList = SETTINGS_FIELDS.filter((field) => field in envOverrides);
const effective = liveEffective ?? {
...saved,
...settingsPatchFromRuntime(envOverrides),
};
return { saved, effective, envOverrides: envOverridesList };
}
function settingsFromStatus(status: LogStorageStatus): LogStorageSettings {
const maxTotalMb = status.maxTotalBytes / (1024 * 1024);
if (!Number.isSafeInteger(maxTotalMb)) {
throw new Error('live log storage limit is not an integer number of megabytes');
}
return {
logMaxTotalMb: maxTotalMb,
logRetainDays: status.retainDays,
logPerUin: status.perUinEnabled,
};
}
function settingsFromRuntime(runtime: RuntimeConfig): LogStorageSettings {
return {
logMaxTotalMb: runtime.logMaxTotalMb ?? DEFAULT_LOG_MAX_TOTAL_MB,
logRetainDays: runtime.logRetainDays ?? DEFAULT_LOG_RETAIN_DAYS,
logPerUin: runtime.logPerUin ?? DEFAULT_LOG_PER_UIN,
};
}
function settingsPatchFromRuntime(runtime: Partial<RuntimeConfig>): Partial<LogStorageSettings> {
const patch: Partial<LogStorageSettings> = {};
if (runtime.logMaxTotalMb !== undefined) {
patch.logMaxTotalMb = runtime.logMaxTotalMb;
}
if (runtime.logRetainDays !== undefined) {
patch.logRetainDays = runtime.logRetainDays;
}
if (runtime.logPerUin !== undefined) {
patch.logPerUin = runtime.logPerUin;
}
return patch;
}
function toPolicy(settings: LogStorageSettings): LogStoragePolicy {
return {
maxTotalMb: settings.logMaxTotalMb,
retainDays: settings.logRetainDays,
perUinEnabled: settings.logPerUin,
};
}
function assertApplied(status: LogStorageStatus, policy: LogStoragePolicy): void {
const expectedBytes = policy.maxTotalMb * 1024 * 1024;
if (
status.state === 'warning' ||
status.state === 'degraded' ||
status.lastError !== undefined ||
status.maxTotalBytes !== expectedBytes ||
status.retainDays !== policy.retainDays ||
status.perUinEnabled !== policy.perUinEnabled
) {
throw new Error(status.lastError ?? 'log storage policy did not become effective');
}
}
function assertPersistedSettings(runtime: RuntimeConfig, expected: LogStorageSettings): void {
const actual = settingsFromRuntime(runtime);
if (
actual.logMaxTotalMb !== expected.logMaxTotalMb ||
actual.logRetainDays !== expected.logRetainDays ||
actual.logPerUin !== expected.logPerUin
) {
throw new Error('persisted log storage settings do not match the requested values');
}
}