German is source of truth; EN/ES fully translated with no German residue. Auto-detects browser language (fallback German), persists choice, language switcher on all pages, localized formats/Clerk/legal. Scans store their language. Backend (T001-T003): language column on scans, openapi+codegen, ruleCatalogI18n, language threaded scans route -> analyzeSkill -> runStaticRule -> AI calls. Route/AI error messages localized via expanded i18n MESSAGES + reqLang(req) (?lang query -> Accept-Language header -> "de"). No German left in routes. Frontend (T004-T005): react-i18next framework, LanguageSwitcher, locale-aware format.ts, Clerk localizations. All page/component strings externalized to de/en/es locale area files across catalog, education, scan form/report/compare, history, dashboard, admin, legal pages. T006 verification + review-fix follow-up (this session): - Applied formatNumber to all visible metrics in scan-report (risk score, severity counts, security/privacy) and scan-compare (risk score, file count, diff counts); PDF/HTML export numbers formatted via Intl.NumberFormat(lng). - Fixed leftover `@workspace/n` import alias in i18n/index.ts -> real package `@workspace/api-client-react` (was failing workspace typecheck). - Verified: full `pnpm run typecheck` green; api-server tests 72/72 pass; curl confirms localized error responses (de/en/es) on scans route. Deviations: AI connection-test prompts left in German intentionally (sent to the model, not user-facing). proposeFollowUpTasks already created #52. Replit-Task-Id: 9f137230-db11-45dc-9276-4e5cbcceff03
636 lines
23 KiB
TypeScript
636 lines
23 KiB
TypeScript
/**
|
|
* Generated by orval v8.9.1 🍺
|
|
* Do not edit manually.
|
|
* Api
|
|
* API specification
|
|
* OpenAPI spec version: 0.1.0
|
|
*/
|
|
import * as zod from 'zod';
|
|
|
|
|
|
/**
|
|
* Returns server health status
|
|
* @summary Health check
|
|
*/
|
|
export const HealthCheckResponse = zod.object({
|
|
"status": zod.string()
|
|
})
|
|
|
|
|
|
/**
|
|
* Returns whether the caller is signed in and whether their email is on the admin allowlist. Always 200; never requires auth.
|
|
* @summary Current authentication and admin status
|
|
*/
|
|
export const GetMeResponse = zod.object({
|
|
"authenticated": zod.boolean(),
|
|
"isAdmin": zod.boolean(),
|
|
"email": zod.string().nullish().describe('The signed-in user\'s primary email, when available')
|
|
})
|
|
|
|
|
|
/**
|
|
* Aggregated statistics across all scans.
|
|
* @summary Dashboard summary
|
|
*/
|
|
export const GetDashboardResponse = zod.object({
|
|
"totalScans": zod.number(),
|
|
"avgRiskScore": zod.number(),
|
|
"verdictCounts": zod.object({
|
|
"pass": zod.number(),
|
|
"review": zod.number(),
|
|
"block": zod.number()
|
|
}),
|
|
"severityTotals": zod.object({
|
|
"critical": zod.number(),
|
|
"high": zod.number(),
|
|
"medium": zod.number(),
|
|
"low": zod.number(),
|
|
"info": zod.number()
|
|
}),
|
|
"axisTotals": zod.object({
|
|
"security": zod.number(),
|
|
"privacy": zod.number()
|
|
}),
|
|
"recentScans": zod.array(zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"description": zod.string().nullish().describe('AI-generated summary of the skill\'s purpose (null when no AI description is available)'),
|
|
"language": zod.enum(['de', 'en', 'es']).describe('Language the report content was generated in'),
|
|
"source": zod.enum(['zip', 'file', 'text']),
|
|
"status": zod.enum(['completed', 'failed']),
|
|
"verdict": zod.enum(['pass', 'review', 'block']),
|
|
"riskScore": zod.number(),
|
|
"fileCount": zod.number(),
|
|
"aiUsed": zod.boolean(),
|
|
"aiError": zod.string().nullish(),
|
|
"findingCounts": zod.object({
|
|
"critical": zod.number(),
|
|
"high": zod.number(),
|
|
"medium": zod.number(),
|
|
"low": zod.number(),
|
|
"info": zod.number(),
|
|
"security": zod.number(),
|
|
"privacy": zod.number(),
|
|
"total": zod.number()
|
|
}),
|
|
"fingerprint": zod.string().describe('Deterministic hash over all files (path + per-file hash)'),
|
|
"relation": zod.union([zod.literal('new'),zod.literal('identical'),zod.literal('modified'),zod.literal(null)]).nullable().describe('Relation to previously stored skills'),
|
|
"similarity": zod.number().nullable().describe('Content-aware similarity (0-100) to the compared skill (identical files count fully, changed text files use line-level similarity)'),
|
|
"comparedScanId": zod.number().nullable().describe('The scan this one was compared against, if any'),
|
|
"hidden": zod.boolean().describe('Whether an admin has hidden this scan from the public catalog'),
|
|
"createdAt": zod.string()
|
|
})),
|
|
"topRules": zod.array(zod.object({
|
|
"ruleId": zod.string(),
|
|
"title": zod.string(),
|
|
"axis": zod.enum(['security', 'privacy']),
|
|
"count": zod.number()
|
|
}))
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary List scan history
|
|
*/
|
|
export const ListScansResponseItem = zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"description": zod.string().nullish().describe('AI-generated summary of the skill\'s purpose (null when no AI description is available)'),
|
|
"language": zod.enum(['de', 'en', 'es']).describe('Language the report content was generated in'),
|
|
"source": zod.enum(['zip', 'file', 'text']),
|
|
"status": zod.enum(['completed', 'failed']),
|
|
"verdict": zod.enum(['pass', 'review', 'block']),
|
|
"riskScore": zod.number(),
|
|
"fileCount": zod.number(),
|
|
"aiUsed": zod.boolean(),
|
|
"aiError": zod.string().nullish(),
|
|
"findingCounts": zod.object({
|
|
"critical": zod.number(),
|
|
"high": zod.number(),
|
|
"medium": zod.number(),
|
|
"low": zod.number(),
|
|
"info": zod.number(),
|
|
"security": zod.number(),
|
|
"privacy": zod.number(),
|
|
"total": zod.number()
|
|
}),
|
|
"fingerprint": zod.string().describe('Deterministic hash over all files (path + per-file hash)'),
|
|
"relation": zod.union([zod.literal('new'),zod.literal('identical'),zod.literal('modified'),zod.literal(null)]).nullable().describe('Relation to previously stored skills'),
|
|
"similarity": zod.number().nullable().describe('Content-aware similarity (0-100) to the compared skill (identical files count fully, changed text files use line-level similarity)'),
|
|
"comparedScanId": zod.number().nullable().describe('The scan this one was compared against, if any'),
|
|
"hidden": zod.boolean().describe('Whether an admin has hidden this scan from the public catalog'),
|
|
"createdAt": zod.string()
|
|
})
|
|
export const ListScansResponse = zod.array(ListScansResponseItem)
|
|
|
|
|
|
/**
|
|
* Accepts a skill as a base64 ZIP archive, a single base64 file, or pasted text, runs the static rule engine and (optionally) the configured AI analysis, and returns the completed report.
|
|
* @summary Upload a skill and run an audit
|
|
*/
|
|
export const CreateScanBody = zod.object({
|
|
"name": zod.string().nullish().describe('Optional display name for the scan'),
|
|
"source": zod.enum(['zip', 'file', 'text']),
|
|
"useAi": zod.boolean().describe('Whether to also run the configured AI analysis'),
|
|
"language": zod.union([zod.literal('de'),zod.literal('en'),zod.literal('es'),zod.literal(null)]).nullish().describe('Language for the report content (AI output and static findings). Defaults to \"de\".'),
|
|
"contentBase64": zod.string().nullish().describe('Base64 content for source=zip or source=file'),
|
|
"filename": zod.string().nullish().describe('Original filename for source=file or source=zip'),
|
|
"text": zod.string().nullish().describe('Raw skill text for source=text')
|
|
})
|
|
|
|
|
|
/**
|
|
* Returns a file-level diff between the current scan (id) and a previously stored scan (otherId), including line-by-line diffs for modified text files.
|
|
* @summary Compare two scans on the file level
|
|
*/
|
|
export const CompareScansParams = zod.object({
|
|
"id": zod.coerce.number(),
|
|
"otherId": zod.coerce.number()
|
|
})
|
|
|
|
export const CompareScansResponse = zod.object({
|
|
"current": zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"verdict": zod.enum(['pass', 'review', 'block']),
|
|
"riskScore": zod.number(),
|
|
"fileCount": zod.number(),
|
|
"fingerprint": zod.string(),
|
|
"createdAt": zod.string()
|
|
}),
|
|
"previous": zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"verdict": zod.enum(['pass', 'review', 'block']),
|
|
"riskScore": zod.number(),
|
|
"fileCount": zod.number(),
|
|
"fingerprint": zod.string(),
|
|
"createdAt": zod.string()
|
|
}),
|
|
"files": zod.array(zod.object({
|
|
"path": zod.string(),
|
|
"status": zod.enum(['unchanged', 'modified', 'added', 'removed']),
|
|
"previousHash": zod.string().nullable(),
|
|
"currentHash": zod.string().nullable(),
|
|
"previousSize": zod.number().nullable(),
|
|
"currentSize": zod.number().nullable(),
|
|
"previousHasContent": zod.boolean().nullable(),
|
|
"currentHasContent": zod.boolean().nullable(),
|
|
"lineDiff": zod.union([zod.array(zod.object({
|
|
"type": zod.enum(['context', 'add', 'remove']),
|
|
"text": zod.string(),
|
|
"previousLine": zod.number().nullable(),
|
|
"currentLine": zod.number().nullable()
|
|
})),zod.null()])
|
|
}))
|
|
})
|
|
|
|
|
|
/**
|
|
* Returns every scan in the same fingerprint lineage as the given scan (linked by an identical fingerprint or by the comparedScanId chain), newest first, so the full version history of a skill can be shown on a timeline without re-scanning.
|
|
* @summary Get the version timeline for a skill family
|
|
*/
|
|
export const GetScanLineageParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
export const GetScanLineageResponseItem = zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"verdict": zod.enum(['pass', 'review', 'block']),
|
|
"riskScore": zod.number(),
|
|
"relation": zod.union([zod.literal('new'),zod.literal('identical'),zod.literal('modified'),zod.literal(null)]).nullable().describe('Relation of this version to the one it was compared against'),
|
|
"similarity": zod.number().nullable().describe('Content-aware similarity (0-100) to its compared version'),
|
|
"comparedScanId": zod.number().nullable().describe('The prior version this scan was compared against, if any'),
|
|
"fingerprint": zod.string(),
|
|
"createdAt": zod.string()
|
|
})
|
|
export const GetScanLineageResponse = zod.array(GetScanLineageResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary Get a scan report with findings
|
|
*/
|
|
export const GetScanParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
export const GetScanResponse = zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"description": zod.string().nullish().describe('AI-generated summary of the skill\'s purpose (null when no AI description is available)'),
|
|
"language": zod.enum(['de', 'en', 'es']).describe('Language the report content was generated in'),
|
|
"source": zod.enum(['zip', 'file', 'text']),
|
|
"status": zod.enum(['completed', 'failed']),
|
|
"verdict": zod.enum(['pass', 'review', 'block']),
|
|
"riskScore": zod.number(),
|
|
"fileCount": zod.number(),
|
|
"aiUsed": zod.boolean(),
|
|
"aiError": zod.string().nullish(),
|
|
"findingCounts": zod.object({
|
|
"critical": zod.number(),
|
|
"high": zod.number(),
|
|
"medium": zod.number(),
|
|
"low": zod.number(),
|
|
"info": zod.number(),
|
|
"security": zod.number(),
|
|
"privacy": zod.number(),
|
|
"total": zod.number()
|
|
}),
|
|
"fingerprint": zod.string().describe('Deterministic hash over all files (path + per-file hash)'),
|
|
"relation": zod.union([zod.literal('new'),zod.literal('identical'),zod.literal('modified'),zod.literal(null)]).nullable().describe('Relation to previously stored skills'),
|
|
"similarity": zod.number().nullable().describe('Content-aware similarity (0-100) to the compared skill (identical files count fully, changed text files use line-level similarity)'),
|
|
"comparedScanId": zod.number().nullable().describe('The scan this one was compared against, if any'),
|
|
"hidden": zod.boolean().describe('Whether an admin has hidden this scan from the public catalog'),
|
|
"createdAt": zod.string()
|
|
}).and(zod.object({
|
|
"files": zod.array(zod.object({
|
|
"path": zod.string(),
|
|
"kind": zod.enum(['instruction', 'script', 'resource']),
|
|
"language": zod.string().nullish(),
|
|
"size": zod.number(),
|
|
"hash": zod.string().describe('SHA-256 hash of the file content'),
|
|
"hasContent": zod.boolean().describe('Whether the text content was stored (false for binary files)'),
|
|
"content": zod.string().nullish().describe('The stored text content of the file, or null for binary files')
|
|
})),
|
|
"findings": zod.array(zod.object({
|
|
"id": zod.number(),
|
|
"ruleId": zod.string(),
|
|
"axis": zod.enum(['security', 'privacy']),
|
|
"severity": zod.enum(['critical', 'high', 'medium', 'low', 'info']),
|
|
"title": zod.string(),
|
|
"description": zod.string(),
|
|
"remediation": zod.string().nullish(),
|
|
"file": zod.string().nullish(),
|
|
"line": zod.number().nullish(),
|
|
"snippet": zod.string().nullish(),
|
|
"detectedBy": zod.enum(['static', 'ai'])
|
|
})),
|
|
"checkpoints": zod.array(zod.object({
|
|
"id": zod.string(),
|
|
"label": zod.string(),
|
|
"category": zod.string(),
|
|
"axis": zod.union([zod.literal('security'),zod.literal('privacy'),zod.literal(null)]).nullish(),
|
|
"severity": zod.union([zod.literal('critical'),zod.literal('high'),zod.literal('medium'),zod.literal('low'),zod.literal('info'),zod.literal(null)]).nullish(),
|
|
"status": zod.enum(['pass', 'flagged', 'skipped', 'error']),
|
|
"findingCount": zod.number(),
|
|
"scoreDelta": zod.number(),
|
|
"detectedBy": zod.union([zod.literal('static'),zod.literal('ai'),zod.literal(null)]).nullish()
|
|
}).describe('A single inspection step (Prüfschritt) with its partial assessment (Teilbewertung).')),
|
|
"checkCount": zod.number().describe('How often a skill with this exact fingerprint was scanned'),
|
|
"comparedScan": zod.union([zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"verdict": zod.enum(['pass', 'review', 'block']),
|
|
"riskScore": zod.number(),
|
|
"createdAt": zod.string()
|
|
}),zod.null()])
|
|
}))
|
|
|
|
|
|
/**
|
|
* Admin-only. Toggles whether a scan appears in the public catalog.
|
|
* @summary Moderate a scan (hide or unhide from the public catalog)
|
|
*/
|
|
export const ModerateScanParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
export const ModerateScanBody = zod.object({
|
|
"hidden": zod.boolean().describe('Whether to hide the scan from the public catalog')
|
|
})
|
|
|
|
export const ModerateScanResponse = zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"description": zod.string().nullish().describe('AI-generated summary of the skill\'s purpose (null when no AI description is available)'),
|
|
"language": zod.enum(['de', 'en', 'es']).describe('Language the report content was generated in'),
|
|
"source": zod.enum(['zip', 'file', 'text']),
|
|
"status": zod.enum(['completed', 'failed']),
|
|
"verdict": zod.enum(['pass', 'review', 'block']),
|
|
"riskScore": zod.number(),
|
|
"fileCount": zod.number(),
|
|
"aiUsed": zod.boolean(),
|
|
"aiError": zod.string().nullish(),
|
|
"findingCounts": zod.object({
|
|
"critical": zod.number(),
|
|
"high": zod.number(),
|
|
"medium": zod.number(),
|
|
"low": zod.number(),
|
|
"info": zod.number(),
|
|
"security": zod.number(),
|
|
"privacy": zod.number(),
|
|
"total": zod.number()
|
|
}),
|
|
"fingerprint": zod.string().describe('Deterministic hash over all files (path + per-file hash)'),
|
|
"relation": zod.union([zod.literal('new'),zod.literal('identical'),zod.literal('modified'),zod.literal(null)]).nullable().describe('Relation to previously stored skills'),
|
|
"similarity": zod.number().nullable().describe('Content-aware similarity (0-100) to the compared skill (identical files count fully, changed text files use line-level similarity)'),
|
|
"comparedScanId": zod.number().nullable().describe('The scan this one was compared against, if any'),
|
|
"hidden": zod.boolean().describe('Whether an admin has hidden this scan from the public catalog'),
|
|
"createdAt": zod.string()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Delete a scan report
|
|
*/
|
|
export const DeleteScanParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Generate the AI description for an existing scan
|
|
*/
|
|
export const GenerateScanDescriptionParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
export const GenerateScanDescriptionResponse = zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"description": zod.string().nullish().describe('AI-generated summary of the skill\'s purpose (null when no AI description is available)'),
|
|
"language": zod.enum(['de', 'en', 'es']).describe('Language the report content was generated in'),
|
|
"source": zod.enum(['zip', 'file', 'text']),
|
|
"status": zod.enum(['completed', 'failed']),
|
|
"verdict": zod.enum(['pass', 'review', 'block']),
|
|
"riskScore": zod.number(),
|
|
"fileCount": zod.number(),
|
|
"aiUsed": zod.boolean(),
|
|
"aiError": zod.string().nullish(),
|
|
"findingCounts": zod.object({
|
|
"critical": zod.number(),
|
|
"high": zod.number(),
|
|
"medium": zod.number(),
|
|
"low": zod.number(),
|
|
"info": zod.number(),
|
|
"security": zod.number(),
|
|
"privacy": zod.number(),
|
|
"total": zod.number()
|
|
}),
|
|
"fingerprint": zod.string().describe('Deterministic hash over all files (path + per-file hash)'),
|
|
"relation": zod.union([zod.literal('new'),zod.literal('identical'),zod.literal('modified'),zod.literal(null)]).nullable().describe('Relation to previously stored skills'),
|
|
"similarity": zod.number().nullable().describe('Content-aware similarity (0-100) to the compared skill (identical files count fully, changed text files use line-level similarity)'),
|
|
"comparedScanId": zod.number().nullable().describe('The scan this one was compared against, if any'),
|
|
"hidden": zod.boolean().describe('Whether an admin has hidden this scan from the public catalog'),
|
|
"createdAt": zod.string()
|
|
}).and(zod.object({
|
|
"files": zod.array(zod.object({
|
|
"path": zod.string(),
|
|
"kind": zod.enum(['instruction', 'script', 'resource']),
|
|
"language": zod.string().nullish(),
|
|
"size": zod.number(),
|
|
"hash": zod.string().describe('SHA-256 hash of the file content'),
|
|
"hasContent": zod.boolean().describe('Whether the text content was stored (false for binary files)'),
|
|
"content": zod.string().nullish().describe('The stored text content of the file, or null for binary files')
|
|
})),
|
|
"findings": zod.array(zod.object({
|
|
"id": zod.number(),
|
|
"ruleId": zod.string(),
|
|
"axis": zod.enum(['security', 'privacy']),
|
|
"severity": zod.enum(['critical', 'high', 'medium', 'low', 'info']),
|
|
"title": zod.string(),
|
|
"description": zod.string(),
|
|
"remediation": zod.string().nullish(),
|
|
"file": zod.string().nullish(),
|
|
"line": zod.number().nullish(),
|
|
"snippet": zod.string().nullish(),
|
|
"detectedBy": zod.enum(['static', 'ai'])
|
|
})),
|
|
"checkpoints": zod.array(zod.object({
|
|
"id": zod.string(),
|
|
"label": zod.string(),
|
|
"category": zod.string(),
|
|
"axis": zod.union([zod.literal('security'),zod.literal('privacy'),zod.literal(null)]).nullish(),
|
|
"severity": zod.union([zod.literal('critical'),zod.literal('high'),zod.literal('medium'),zod.literal('low'),zod.literal('info'),zod.literal(null)]).nullish(),
|
|
"status": zod.enum(['pass', 'flagged', 'skipped', 'error']),
|
|
"findingCount": zod.number(),
|
|
"scoreDelta": zod.number(),
|
|
"detectedBy": zod.union([zod.literal('static'),zod.literal('ai'),zod.literal(null)]).nullish()
|
|
}).describe('A single inspection step (Prüfschritt) with its partial assessment (Teilbewertung).')),
|
|
"checkCount": zod.number().describe('How often a skill with this exact fingerprint was scanned'),
|
|
"comparedScan": zod.union([zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"verdict": zod.enum(['pass', 'review', 'block']),
|
|
"riskScore": zod.number(),
|
|
"createdAt": zod.string()
|
|
}),zod.null()])
|
|
}))
|
|
|
|
|
|
/**
|
|
* @summary List configured AI providers
|
|
*/
|
|
export const ListProvidersResponseItem = zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"apiType": zod.enum(['openai', 'anthropic', 'custom']),
|
|
"baseUrl": zod.string(),
|
|
"model": zod.string(),
|
|
"enabled": zod.boolean(),
|
|
"hasToken": zod.boolean(),
|
|
"tokenPreview": zod.string().describe('Masked preview of the stored token (e.g. \"sk-...abcd\")'),
|
|
"createdAt": zod.string()
|
|
})
|
|
export const ListProvidersResponse = zod.array(ListProvidersResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary Create an AI provider
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
export const CreateProviderBody = zod.object({
|
|
"name": zod.string().min(1),
|
|
"apiType": zod.enum(['openai', 'anthropic', 'custom']),
|
|
"baseUrl": zod.string().min(1),
|
|
"model": zod.string().min(1),
|
|
"apiToken": zod.string().optional(),
|
|
"enabled": zod.boolean().optional()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Update an AI provider
|
|
*/
|
|
export const UpdateProviderParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const UpdateProviderBody = zod.object({
|
|
"name": zod.string().min(1).optional(),
|
|
"apiType": zod.enum(['openai', 'anthropic', 'custom']).optional(),
|
|
"baseUrl": zod.string().min(1).optional(),
|
|
"model": zod.string().min(1).optional(),
|
|
"apiToken": zod.string().optional().describe('Provide to replace the stored token; omit to keep existing'),
|
|
"enabled": zod.boolean().optional()
|
|
})
|
|
|
|
export const UpdateProviderResponse = zod.object({
|
|
"id": zod.number(),
|
|
"name": zod.string(),
|
|
"apiType": zod.enum(['openai', 'anthropic', 'custom']),
|
|
"baseUrl": zod.string(),
|
|
"model": zod.string(),
|
|
"enabled": zod.boolean(),
|
|
"hasToken": zod.boolean(),
|
|
"tokenPreview": zod.string().describe('Masked preview of the stored token (e.g. \"sk-...abcd\")'),
|
|
"createdAt": zod.string()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Delete an AI provider
|
|
*/
|
|
export const DeleteProviderParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Test the connection to an AI provider
|
|
*/
|
|
export const TestProviderParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
export const TestProviderResponse = zod.object({
|
|
"ok": zod.boolean(),
|
|
"message": zod.string().nullish()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary Test a provider connection with ad-hoc configuration
|
|
*/
|
|
|
|
|
|
|
|
export const TestProviderConnectionBody = zod.object({
|
|
"apiType": zod.enum(['openai', 'anthropic', 'custom']),
|
|
"baseUrl": zod.string().min(1),
|
|
"model": zod.string().optional().describe('Optional model to exercise with a full request; when omitted the test verifies credentials via the models endpoint instead'),
|
|
"apiToken": zod.string().optional().describe('Token to use for the test; omit or leave empty to fall back to the stored token of providerId'),
|
|
"providerId": zod.number().optional().describe('When apiToken is empty, fall back to this saved provider\'s stored token')
|
|
})
|
|
|
|
export const TestProviderConnectionResponse = zod.object({
|
|
"ok": zod.boolean(),
|
|
"message": zod.string().nullish()
|
|
})
|
|
|
|
|
|
/**
|
|
* Queries the provider's models endpoint with the supplied ad-hoc configuration (or the stored token of providerId when the token is omitted) and returns the discovered model IDs.
|
|
* @summary List the available models for a provider configuration
|
|
*/
|
|
|
|
|
|
|
|
export const ListProviderModelsBody = zod.object({
|
|
"apiType": zod.enum(['openai', 'anthropic', 'custom']),
|
|
"baseUrl": zod.string().min(1),
|
|
"apiToken": zod.string().optional().describe('Token to use for the request; omit or leave empty to fall back to the stored token of providerId'),
|
|
"providerId": zod.number().optional().describe('When apiToken is empty, fall back to this saved provider\'s stored token')
|
|
})
|
|
|
|
export const ListProviderModelsResponse = zod.object({
|
|
"ok": zod.boolean(),
|
|
"models": zod.array(zod.string()),
|
|
"message": zod.string().nullish()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary List configurable AI prompts
|
|
*/
|
|
export const ListPromptsResponseItem = zod.object({
|
|
"id": zod.number(),
|
|
"key": zod.string(),
|
|
"name": zod.string(),
|
|
"content": zod.string(),
|
|
"updatedAt": zod.string()
|
|
})
|
|
export const ListPromptsResponse = zod.array(ListPromptsResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary Update an AI prompt
|
|
*/
|
|
export const UpdatePromptParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
export const UpdatePromptBody = zod.object({
|
|
"name": zod.string().min(1).optional(),
|
|
"content": zod.string().min(1).optional()
|
|
})
|
|
|
|
export const UpdatePromptResponse = zod.object({
|
|
"id": zod.number(),
|
|
"key": zod.string(),
|
|
"name": zod.string(),
|
|
"content": zod.string(),
|
|
"updatedAt": zod.string()
|
|
})
|
|
|
|
|
|
/**
|
|
* @summary List the static rule catalog
|
|
*/
|
|
export const ListRulesQueryParams = zod.object({
|
|
"lang": zod.enum(['de', 'en', 'es']).optional().describe('Language for the rule catalog text (title\/description\/category). Defaults to \"de\".')
|
|
})
|
|
|
|
export const ListRulesResponseItem = zod.object({
|
|
"id": zod.number(),
|
|
"ruleId": zod.string(),
|
|
"axis": zod.enum(['security', 'privacy']),
|
|
"category": zod.string(),
|
|
"title": zod.string(),
|
|
"description": zod.string(),
|
|
"severity": zod.enum(['critical', 'high', 'medium', 'low', 'info']),
|
|
"detectionType": zod.enum(['regex', 'heuristic', 'ai']),
|
|
"enabled": zod.boolean()
|
|
})
|
|
export const ListRulesResponse = zod.array(ListRulesResponseItem)
|
|
|
|
|
|
/**
|
|
* @summary Update a rule's severity or enabled state
|
|
*/
|
|
export const UpdateRuleParams = zod.object({
|
|
"id": zod.coerce.number()
|
|
})
|
|
|
|
export const UpdateRuleBody = zod.object({
|
|
"severity": zod.enum(['critical', 'high', 'medium', 'low', 'info']).optional(),
|
|
"enabled": zod.boolean().optional()
|
|
})
|
|
|
|
export const UpdateRuleResponse = zod.object({
|
|
"id": zod.number(),
|
|
"ruleId": zod.string(),
|
|
"axis": zod.enum(['security', 'privacy']),
|
|
"category": zod.string(),
|
|
"title": zod.string(),
|
|
"description": zod.string(),
|
|
"severity": zod.enum(['critical', 'high', 'medium', 'low', 'info']),
|
|
"detectionType": zod.enum(['regex', 'heuristic', 'ai']),
|
|
"enabled": zod.boolean()
|
|
})
|
|
|
|
|