import {z} from 'zod' export type PageSize = number; export type PageCursor = string; export type CIA = 'Confidentiality' | 'Integrity' | 'Availability'; export type UNCATEGORIZED = 'Uncategorized'; export type Treatment = 'Mitigate' | 'Transfer' | 'Avoid' | 'Accept'; export type NOTREATMENTTYPE = 'No treatment type'; export type ScoreGroup = 'Very low' | 'Low' | 'Med' | 'High' | 'Critical'; export type ReviewStatus = 'APPROVED' | 'DRAFT' | 'NOT_REVIEWED' | 'AWAITING_SUBMISSION' | 'PENDING_APPROVAL' | 'REQUESTED_CHANGES'; export type RiskScenarioType = 'Risk Scenario' | 'Enterprise Risk'; export type GetApiRiskScenariosArgs = {pageSize?: PageSize | undefined, pageCursor?: PageCursor | undefined, includeIgnored?: boolean | undefined, ownerMatchesAny?: Array | undefined, searchString?: string | undefined, categoryMatchesAny?: Array | undefined, ciaCategoryMatchesAny?: (Array) | undefined, treatmentTypeMatchesAny?: (Array) | undefined, inherentScoreGroupMatchesAny?: Array | undefined, residualScoreGroupMatchesAny?: Array | undefined, reviewStatusMatchesAny?: Array | undefined, type?: RiskScenarioType | undefined, orderBy?: ('description' | 'createdAt') | undefined}; export type GetApiRiskScenariosOptions = {baseUrl?: string | undefined, bearerAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const cIA = z.enum(["Confidentiality", "Integrity", "Availability"]); export const treatment = z.enum(["Mitigate", "Transfer", "Avoid", "Accept"]); export const customAttribute = z.object({label: z.string(), value: z.union([z.string(), z.array(z.string())])}); export const reviewStatus = z.enum(["APPROVED", "DRAFT", "NOT_REVIEWED", "AWAITING_SUBMISSION", "PENDING_APPROVAL", "REQUESTED_CHANGES"]); export const riskScenarioType = z.enum(["Risk Scenario", "Enterprise Risk"]); export const riskScenario = z.object({riskId: z.string(), description: z.string(), detailedDescription: z.string().nullable().optional(), isSensitive: z.boolean().nullable(), likelihood: z.number().int().nullable(), impact: z.number().int().nullable(), residualLikelihood: z.number().int().nullable(), residualImpact: z.number().int().nullable(), categories: z.array(z.string()), ciaCategories: z.array(cIA), treatment: treatment.nullable(), owner: z.string().nullable(), note: z.string().nullable(), riskRegister: z.string().nullable(), customFields: z.array(customAttribute), isArchived: z.boolean(), reviewStatus: reviewStatus, requiredApprovers: z.array(z.string()), type: riskScenarioType, identificationDate: z.string()}); export const pageInfo = z.object({endCursor: z.string().nullable(), hasNextPage: z.boolean(), hasPreviousPage: z.boolean(), startCursor: z.string().nullable()}); export const paginatedResponseRiskScenario = z.object({results: z.object({data: z.array(riskScenario), pageInfo: pageInfo})}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * List risk scenarios * * GET /risk-scenarios */ export const getApiRiskScenarios = async (args: GetApiRiskScenariosArgs, options?: GetApiRiskScenariosOptions) => { const {baseUrl = "https://api.vanta.com", fetch: fetchFn = fetch, bearerAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.pageSize != null) query.append("pageSize", String(args.pageSize)) if (args.pageCursor != null) query.append("pageCursor", String(args.pageCursor)) if (args.includeIgnored != null) query.append("includeIgnored", String(args.includeIgnored)) for (const item of args.ownerMatchesAny ?? []) query.append("ownerMatchesAny", String(item)) if (args.searchString != null) query.append("searchString", String(args.searchString)) for (const item of args.categoryMatchesAny ?? []) query.append("categoryMatchesAny", String(item)) for (const item of args.ciaCategoryMatchesAny ?? []) query.append("ciaCategoryMatchesAny", String(item)) for (const item of args.treatmentTypeMatchesAny ?? []) query.append("treatmentTypeMatchesAny", String(item)) for (const item of args.inherentScoreGroupMatchesAny ?? []) query.append("inherentScoreGroupMatchesAny", String(item)) for (const item of args.residualScoreGroupMatchesAny ?? []) query.append("residualScoreGroupMatchesAny", String(item)) for (const item of args.reviewStatusMatchesAny ?? []) query.append("reviewStatusMatchesAny", String(item)) if (args.type != null) query.append("type", String(args.type)) if (args.orderBy != null) query.append("orderBy", String(args.orderBy)) if (bearerAuth !== undefined) headers.set('authorization', `Bearer ${bearerAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/risk-scenarios${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(paginatedResponseRiskScenario, await res.json()) };