diff --git a/packages/uta-protocol/src/schemas/index.ts b/packages/uta-protocol/src/schemas/index.ts index 9e3cd60e3..38cdec863 100644 --- a/packages/uta-protocol/src/schemas/index.ts +++ b/packages/uta-protocol/src/schemas/index.ts @@ -7,5 +7,25 @@ * lifts each route. */ -export {} +import { z } from 'zod' + +const guardConfigSchema = z.object({ + type: z.string(), + options: z.record(z.string(), z.unknown()).default({}), +}) + +export const utaConfigSchema = z.object({ + id: z.string(), + label: z.string().optional(), + presetId: z.string(), + enabled: z.boolean().default(true), + guards: z.array(guardConfigSchema).default([]), + presetConfig: z.record(z.string(), z.unknown()).default({}), + ephemeral: z.boolean().optional(), +}).refine((u) => u.ephemeral !== true || u.presetId === 'mock-simulator', { + message: 'ephemeral: true is only allowed on mock-simulator UTAs (would destroy real broker history at next boot)', + path: ['ephemeral'], +}) + +export type UTAConfig = z.infer diff --git a/src/core/config.ts b/src/core/config.ts index 32d71ec4c..b1a70e626 100644 --- a/src/core/config.ts +++ b/src/core/config.ts @@ -315,45 +315,11 @@ export type WebChannel = z.infer // ==================== UTA Config ==================== -const guardConfigSchema = z.object({ - type: z.string(), - options: z.record(z.string(), z.unknown()).default({}), -}) - -/** - * One Unified Trading Account. The user-facing concept — one preset - * (OKX, Bybit, IBKR, …) plus credentials, guards, and an enabled flag. - * - * Distinct from `AccountInfo` (which is broker-side: cash, equity, - * margin returned by `IBroker.getAccount()`). Two different "account"s. - */ -export const utaConfigSchema = z.object({ - id: z.string(), - label: z.string().optional(), - /** Broker preset id — resolves to engine + form schema via BROKER_PRESET_CATALOG. */ - presetId: z.string(), - enabled: z.boolean().default(true), - guards: z.array(guardConfigSchema).default([]), - /** User-filled form values, validated against the preset's own zodSchema. */ - presetConfig: z.record(z.string(), z.unknown()).default({}), - /** - * Test/throwaway UTA — purged at every server startup (config entry - * removed + `data/trading//` wiped) and dropped immediately when - * deleted via the UTA-config DELETE endpoint. For fixture-based testing: - * each session starts from a clean slate, no cross-session cost-basis - * pollution. Only allowed on `mock-simulator` preset; setting it on a - * real broker would silently destroy account history on next boot. - */ - ephemeral: z.boolean().optional(), -}).refine((u) => u.ephemeral !== true || u.presetId === 'mock-simulator', { - message: 'ephemeral: true is only allowed on mock-simulator UTAs (would destroy real broker history at next boot)', - path: ['ephemeral'], -}) +import { utaConfigSchema, type UTAConfig } from '@traderalice/uta-protocol' +export { utaConfigSchema, UTAConfig } export const utasFileSchema = z.array(utaConfigSchema) -export type UTAConfig = z.infer - // ==================== Unified Config Type ==================== export type Config = {