skillguard/lib/api-zod/src/generated/api.ts
amertensreplit 2236ad179d Add DE/EN/ES multilingual support to SkillGuard (Task #49)
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
2026-06-13 09:05:57 +00:00

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()
})