import { codexRecord } from './classes.codexprojection.js'; import { isCodexCreationToken } from './functions.codexidentity.js'; import { isCodexRemoteDirectory, validateCodexServerUrl } from './classes.codexconnectionmodels.js'; import type * as interfaces from '../ts_interfaces/codex.js'; const shape = (valueArg: unknown, requiredArg: string[], optionalArg: string[] = []): Record => { const value = codexRecord(valueArg); if (!requiredArg.every(key => Object.hasOwn(value, key)) || Object.keys(value).some(key => !requiredArg.includes(key) && !optionalArg.includes(key))) throw new Error('Invalid Codex connection request.'); return value; }; const name = (valueArg: unknown): string => { if (typeof valueArg !== 'string' || valueArg.trim() !== valueArg || valueArg.length < 1 || valueArg.length > 128 || /[\u0000-\u001f\u007f]/.test(valueArg)) throw new Error('Use a connection name of 1–128 characters.'); return valueArg; }; const token = (valueArg: unknown): string => { if (typeof valueArg !== 'string' || !/^[\x21-\x7e]{1,8192}$/.test(valueArg)) throw new Error('Use a token of 1–8192 printable ASCII characters without spaces.'); return valueArg; }; const profileId = (valueArg: unknown): string => { if (!isCodexCreationToken(valueArg, 32)) throw new Error('Invalid Codex profile identity.'); return valueArg; }; export const assertCodexProfileSelection = (valueArg: unknown, requiredArg = false): { profileId?: string } => { const value = shape(valueArg, requiredArg ? ['profileId'] : [], requiredArg ? [] : ['profileId']); return Object.hasOwn(value, 'profileId') ? { profileId: profileId(value.profileId) } : {}; }; export const assertCodexProfilesList = (valueArg: unknown): { projectId?: string } => { const value = shape(valueArg, [], ['projectId']); if (Object.hasOwn(value, 'projectId') && !isCodexCreationToken(value.projectId, 16)) throw new Error('Invalid Codex project identity.'); return value.projectId === undefined ? {} : { projectId: value.projectId as string }; }; export const assertCodexProfileCreate = (valueArg: unknown): interfaces.IReq_ControllerCodexProfileCreate['request'] => { const value = shape(valueArg, ['name', 'serverUrl'], ['token']); return { name: name(value.name), serverUrl: validateCodexServerUrl(value.serverUrl), ...(Object.hasOwn(value, 'token') ? { token: token(value.token) } : {}) }; }; export const assertCodexProfileUpdate = (valueArg: unknown): interfaces.IReq_ControllerCodexProfileUpdate['request'] => { const value = shape(valueArg, ['profileId', 'expectedCredentialRevision'], ['name', 'token', 'retire']); if (!Number.isSafeInteger(value.expectedCredentialRevision) || Number(value.expectedCredentialRevision) < 0 || (!Object.hasOwn(value, 'name') && !Object.hasOwn(value, 'token') && !Object.hasOwn(value, 'retire')) || (Object.hasOwn(value, 'retire') && value.retire !== true)) throw new Error('Invalid Codex profile change.'); return { profileId: profileId(value.profileId), expectedCredentialRevision: value.expectedCredentialRevision as number, ...(Object.hasOwn(value, 'name') ? { name: name(value.name) } : {}), ...(Object.hasOwn(value, 'token') ? { token: value.token === null ? null : token(value.token) } : {}), ...(value.retire === true ? { retire: true } : {}) }; }; export const assertCodexMappingUpdate = (valueArg: unknown): interfaces.IControllerCodexProjectMapping => { const value = shape(valueArg, ['projectId', 'profileId', 'remoteDirectory']); if (!isCodexCreationToken(value.projectId, 16) || !isCodexRemoteDirectory(value.remoteDirectory)) throw new Error('Select a project and an absolute directory on the Codex server.'); return { projectId: value.projectId, profileId: profileId(value.profileId), remoteDirectory: value.remoteDirectory }; };