import { z } from "zod"; import { ASSET_CLASSES, EVENT_TYPES, FIELDS, OBSERVATION_TYPES, REALTIME_STATUSES, RIGHTS_STATUSES, SEVERITIES, SOURCE_TYPES, TIMESTAMP_TRUSTS, } from "./enums.js"; export const InstrumentHintSchema = z.object({ assetClass: z.enum(ASSET_CLASSES), name: z.string().optional(), exchangeId: z.string().nullable().optional(), mic: z.string().nullable().optional(), currency: z.string().nullable().optional(), country: z.string().nullable().optional(), base: z.string().nullable().optional(), quote: z.string().nullable().optional(), securityType: z.string().nullable().optional(), companyName: z.string().nullable().optional(), cik: z.string().nullable().optional(), metadata: z.record(z.unknown()).optional(), }); export const NormalizedObservationSchema = z.object({ symbol: z.string().min(1).max(64), instrumentId: z.string().optional(), instrumentHint: InstrumentHintSchema.optional(), field: z.enum(FIELDS), value: z.number().finite(), currency: z.string().nullable().optional(), observationType: z.enum(OBSERVATION_TYPES).optional(), sourceTimestamp: z.number().int().nullable(), timestampTrust: z.enum(TIMESTAMP_TRUSTS), sequence: z.union([z.number(), z.string()]).nullable().optional(), rightsStatus: z.enum(RIGHTS_STATUSES), realtimeStatus: z.enum(REALTIME_STATUSES), confidence: z.number().min(0).max(1).optional(), meta: z.record(z.unknown()).optional(), }); export const MarketEventSchema = z.object({ version: z.literal(1), id: z.string(), type: z.enum(EVENT_TYPES), instrumentIds: z.array(z.string()), entityIds: z.array(z.string()), timestamp: z.number().int(), severity: z.enum(SEVERITIES), confidence: z.number().min(0).max(1), sourceCount: z.number().int().nonnegative(), sources: z.array(z.string()), title: z.string(), summary: z.string().nullable(), data: z.record(z.unknown()), fingerprint: z.string(), supportingObservations: z.array(z.string()), }); export const ConnectorMetadataSchema = z.object({ id: z.string().regex(/^[a-z0-9][a-z0-9-]{1,60}$/), name: z.string(), version: z.string(), sourceId: z.string(), organization: z.string().nullable(), sourceType: z.enum(SOURCE_TYPES), jurisdiction: z.string().nullable(), rightsStatus: z.enum(RIGHTS_STATUSES), realtimeStatus: z.enum(REALTIME_STATUSES), expectedLatencyMs: z.number().nullable(), supportsStreaming: z.boolean(), supportsHistorical: z.boolean(), assetClasses: z.array(z.enum(ASSET_CLASSES)), exchanges: z.array(z.string()), homepage: z.string().url().nullable(), description: z.string(), rightsNotes: z.string().nullable(), termsUrl: z.string().url().nullable(), sourceFamily: z.string().nullable(), enabled: z.boolean(), }); /** WebSocket client → gateway messages. */ export const StreamClientMessageSchema = z.discriminatedUnion("action", [ z.object({ action: z.literal("subscribe"), channels: z.array(z.string().max(120)).max(500) }), z.object({ action: z.literal("unsubscribe"), channels: z.array(z.string().max(120)).max(500) }), z.object({ action: z.literal("ping"), id: z.union([z.string(), z.number()]).optional() }), ]); export type StreamClientMessage = z.infer;