import {z} from 'zod' export type GetApiV2DadosOrgaoArgs = {orgao: string}; export type GetApiV2DadosOrgaoOptions = {baseUrl: string, fetch?: typeof fetch | undefined}; export const papiCollecting = z.object({descricao: z.array(z.string()).optional(), timestamp: z.number().int().optional()}); export const papiCollect = z.object({duracao_segundos: z.number().optional(), repositorio_coletor: z.string().optional(), repositorio_parser: z.string().optional(), versao_coletor: z.string().optional(), versao_parser: z.string().optional()}); export const papiMiError = z.object({cmd: z.string().optional(), err_msg: z.string().optional(), status: z.number().int().optional()}); export const papiScore = z.object({indice_completude: z.number().optional(), indice_facilidade: z.number().optional(), indice_transparencia: z.number().optional()}); export const papiMetadata = z.object({acesso: z.string().optional(), dados_estritamente_tabulares: z.boolean().optional(), despesas: z.string().optional(), extensao: z.string().optional(), formato_aberto: z.boolean().optional(), manteve_consistencia_no_formato: z.boolean().optional(), outras_receitas: z.string().optional(), remuneracao_basica: z.string().optional(), tem_cargo: z.boolean().optional(), tem_lotacao: z.boolean().optional(), tem_matricula: z.boolean().optional()}); export const papiBackup = z.object({hash: z.string().optional(), size: z.number().int().optional(), url: z.string().optional()}); export const papiDataSummary = z.object({max: z.number().optional(), media: z.number().optional(), min: z.number().optional(), total: z.number().optional()}); export const papiItemSummary = z.record(z.string(), z.number()); export const papiSummary = z.object({descontos: papiDataSummary.optional(), outras_remuneracoes: papiDataSummary.optional(), quantidade: z.number().int().optional(), remuneracao_base: papiDataSummary.optional(), remuneracoes: papiDataSummary.optional(), resumo_rubricas: papiItemSummary.optional()}); export const papiSummaries = z.object({membros_ativos: papiSummary.optional()}); export const papiSummaryzedMI = z.object({ano: z.number().int().optional(), coleta_manual: z.boolean().optional(), dados_coleta: papiCollect.optional(), error: papiMiError.optional(), id_orgao: z.string().optional(), inconsistente: z.boolean().optional(), indice_transparencia: papiScore.optional(), mes: z.number().int().optional(), metadados: papiMetadata.optional(), pacote_de_dados: papiBackup.optional(), sumarios: papiSummaries.optional()}); export const papiAllAgencyInformation = z.object({coletando: z.array(papiCollecting).optional(), coletas: z.array(papiSummaryzedMI).optional(), entidade: z.string().optional(), id_orgao: z.string().optional(), indice_transparencia: papiScore.optional(), jurisdicao: z.string().optional(), meses_com_dados: z.number().int().optional(), nome: z.string().optional(), ouvidoria: z.string().optional(), total_coletas_realizadas: z.number().int().optional(), twitter_handle: z.string().optional(), uf: z.string().optional(), url: z.string().optional()}); 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 }; /** * Busca todos os dados de um órgão específico trazendo informações de cada mês disponível para cada ano disponível a partir de 2018, retornando status de coleta, dados de coleta (duração da coleta e dados do coletor), dados sumarizados de remuneração (dos membros ativos, remuneração base/salário, outras remunerações/benefícios, descontos, remunerações líquidas, quantidade de membros, e gasto em rubricas identificadas/penduricalhos), metadados de completude e facilidade de acesso e pontuações referentes ao índice de transparência nas dimensões de completude, facilidade de acesso e transparência (https://dadosjusbr.org/indice). * * GET /v2/dados/{orgao} */ export const getApiV2DadosOrgao = async (args: GetApiV2DadosOrgaoArgs, options: GetApiV2DadosOrgaoOptions) => { const {baseUrl, fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") const url = `${baseUrl.replace(/\/+$/, '')}/v2/dados/${encodeURIComponent(String(args.orgao))}${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(papiAllAgencyInformation, await res.json()) };