Add player moderation workflows and game integration
CI / checks (push) Successful in 7m27s

This commit is contained in:
2026-10-15 21:33:50 -04:00
parent c91d49c298
commit 8b372fa2c1
50 changed files with 4744 additions and 354 deletions
+21 -9
View File
@@ -2,11 +2,18 @@ import { posix } from 'node:path';
import { gameOfServer, relDestForKind, type ArtifactKind } from '../config.js';
export const BANK_CONFIG_FILE = 'electric_cherry_bank.cfg';
export const MODERATION_CONFIG_FILE = 'electric_cherry_moderation.cfg';
export const PRIVATE_CONFIG_FILES = [BANK_CONFIG_FILE, MODERATION_CONFIG_FILE] as const;
export function isPrivateConfigPath(path: string, game = 't5'): boolean {
return (
posix.normalize(path.replaceAll('\\', '/')) ===
posix.join(relDestForKind('config', game), BANK_CONFIG_FILE)
// Moderation bootstrap has one fixed runtime location, even when shared
// artifact destinations were customized for an older installation.
if (posix.normalize(path.replaceAll('\\', '/')) === `configs/${MODERATION_CONFIG_FILE}`)
return true;
return PRIVATE_CONFIG_FILES.some(
(filename) =>
posix.normalize(path.replaceAll('\\', '/')) ===
posix.join(relDestForKind('config', game), filename)
);
}
@@ -23,26 +30,31 @@ export function isPrivateConfigTarget(server: string, kind: string, path: string
export function assertPublicFileTarget(server: string, kind: ArtifactKind, path: string): void {
if (isPrivateConfigTarget(server, kind, path))
throw new Error(
'Private bank configuration cannot be captured or changed by a file campaign.'
'Private bank configuration and moderation configuration cannot be captured or changed by a file campaign.'
);
}
export function isReservedConfigFilename(path: string): boolean {
return posix.basename(path.replaceAll('\\', '/')).toLowerCase() === BANK_CONFIG_FILE;
return PRIVATE_CONFIG_FILES.some(
(filename) => posix.basename(path.replaceAll('\\', '/')).toLowerCase() === filename
);
}
// Legacy campaign evidence omits the kind and stores the path relative to its destination.
export function isPrivateConfigEvidencePath(path: string): boolean {
return (
posix.normalize(path.replaceAll('\\', '/')) === BANK_CONFIG_FILE ||
isPrivateConfigPath(path)
PRIVATE_CONFIG_FILES.some(
(filename) => posix.normalize(path.replaceAll('\\', '/')) === filename
) || isPrivateConfigPath(path)
);
}
/** Credential injection uses bank.configPath, never a shared file's path field. */
/** Credential injection uses a private configPath, never a shared file's path field. */
export class PrivateFileOperationError extends Error {
constructor() {
super('Private bank configuration cannot be read or changed by file operations.');
super(
'Private bank configuration and moderation configuration cannot be read or changed by file operations.'
);
}
}
+1 -1
View File
@@ -253,7 +253,7 @@ export function createScript(input: CreateScriptInput): {
if (!targetRelPath) throw new ScriptError('target rel path is required', 'path-empty');
if (isReservedConfigFilename(targetRelPath))
throw new ScriptError(
'electric_cherry_bank.cfg is reserved for instance credentials.',
`${targetRelPath} is reserved for instance credentials.`,
'path-reserved'
);