feat(frontend): add Zod schemas for threat detection API
Type-safe schemas matching backend Pydantic models for threats, stats, models status, and WebSocket alerts.
This commit is contained in:
parent
012d849366
commit
cdeb1451ef
|
|
@ -2,3 +2,8 @@
|
|||
// © AngelaMos | 2026
|
||||
// index.ts
|
||||
// ===================
|
||||
|
||||
export * from './threats.types'
|
||||
export * from './stats.types'
|
||||
export * from './models.types'
|
||||
export * from './websocket.types'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
// ===================
|
||||
// © AngelaMos | 2026
|
||||
// models.types.ts
|
||||
// ===================
|
||||
|
||||
import { z } from 'zod'
|
||||
|
||||
export const ActiveModelSchema = z.object({
|
||||
model_type: z.string(),
|
||||
version: z.string(),
|
||||
training_samples: z.number().int(),
|
||||
metrics: z.record(z.string(), z.number()),
|
||||
threshold: z.number().nullable(),
|
||||
})
|
||||
|
||||
export const ModelStatusSchema = z.object({
|
||||
models_loaded: z.boolean(),
|
||||
detection_mode: z.string(),
|
||||
active_models: z.array(ActiveModelSchema),
|
||||
})
|
||||
|
||||
export const RetrainResponseSchema = z.object({
|
||||
status: z.string(),
|
||||
job_id: z.string(),
|
||||
})
|
||||
|
||||
export type ActiveModel = z.infer<typeof ActiveModelSchema>
|
||||
export type ModelStatus = z.infer<typeof ModelStatusSchema>
|
||||
export type RetrainResponse = z.infer<typeof RetrainResponseSchema>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// ===================
|
||||
// © AngelaMos | 2026
|
||||
// stats.types.ts
|
||||
// ===================
|
||||
|
||||
import { z } from 'zod'
|
||||
|
||||
export const SeverityBreakdownSchema = z.object({
|
||||
high: z.number().int(),
|
||||
medium: z.number().int(),
|
||||
low: z.number().int(),
|
||||
})
|
||||
|
||||
export const IPStatEntrySchema = z.object({
|
||||
source_ip: z.string(),
|
||||
count: z.number().int(),
|
||||
})
|
||||
|
||||
export const PathStatEntrySchema = z.object({
|
||||
path: z.string(),
|
||||
count: z.number().int(),
|
||||
})
|
||||
|
||||
export const StatsResponseSchema = z.object({
|
||||
time_range: z.string(),
|
||||
threats_stored: z.number().int(),
|
||||
threats_detected: z.number().int(),
|
||||
severity_breakdown: SeverityBreakdownSchema,
|
||||
top_source_ips: z.array(IPStatEntrySchema),
|
||||
top_attacked_paths: z.array(PathStatEntrySchema),
|
||||
})
|
||||
|
||||
export type SeverityBreakdown = z.infer<typeof SeverityBreakdownSchema>
|
||||
export type IPStatEntry = z.infer<typeof IPStatEntrySchema>
|
||||
export type PathStatEntry = z.infer<typeof PathStatEntrySchema>
|
||||
export type StatsResponse = z.infer<typeof StatsResponseSchema>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// ===================
|
||||
// © AngelaMos | 2026
|
||||
// threats.types.ts
|
||||
// ===================
|
||||
|
||||
import { z } from 'zod'
|
||||
|
||||
export const GeoInfoSchema = z.object({
|
||||
country: z.string().nullable(),
|
||||
city: z.string().nullable(),
|
||||
lat: z.number().nullable(),
|
||||
lon: z.number().nullable(),
|
||||
})
|
||||
|
||||
export const ThreatEventSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
created_at: z.string(),
|
||||
source_ip: z.string(),
|
||||
request_method: z.string(),
|
||||
request_path: z.string(),
|
||||
status_code: z.number().int(),
|
||||
response_size: z.number().int(),
|
||||
user_agent: z.string(),
|
||||
threat_score: z.number(),
|
||||
severity: z.literal(['HIGH', 'MEDIUM', 'LOW']),
|
||||
component_scores: z.record(z.string(), z.number()),
|
||||
geo: GeoInfoSchema,
|
||||
matched_rules: z.array(z.string()).nullable(),
|
||||
model_version: z.string().nullable(),
|
||||
reviewed: z.boolean(),
|
||||
review_label: z.string().nullable(),
|
||||
})
|
||||
|
||||
export const ThreatListSchema = z.object({
|
||||
total: z.number().int(),
|
||||
limit: z.number().int(),
|
||||
offset: z.number().int(),
|
||||
items: z.array(ThreatEventSchema),
|
||||
})
|
||||
|
||||
export type GeoInfo = z.infer<typeof GeoInfoSchema>
|
||||
export type ThreatEvent = z.infer<typeof ThreatEventSchema>
|
||||
export type ThreatList = z.infer<typeof ThreatListSchema>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// ===================
|
||||
// © AngelaMos | 2026
|
||||
// websocket.types.ts
|
||||
// ===================
|
||||
|
||||
import { z } from 'zod'
|
||||
|
||||
export const WebSocketAlertSchema = z.object({
|
||||
event: z.literal('threat'),
|
||||
timestamp: z.string(),
|
||||
source_ip: z.string(),
|
||||
request_path: z.string(),
|
||||
threat_score: z.number(),
|
||||
severity: z.string(),
|
||||
component_scores: z.record(z.string(), z.number()),
|
||||
})
|
||||
|
||||
export type WebSocketAlert = z.infer<typeof WebSocketAlertSchema>
|
||||
Loading…
Reference in New Issue