@precisa-saude/fhir-rnds-sandbox 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +477 -0
- package/dist/cli.cjs +1588 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +18 -0
- package/dist/cli.d.ts +18 -0
- package/dist/cli.js +1556 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +1425 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +338 -0
- package/dist/index.d.ts +338 -0
- package/dist/index.js +1375 -0
- package/dist/index.js.map +1 -0
- package/dist/types-C61Coait.d.cts +133 -0
- package/dist/types-C61Coait.d.ts +133 -0
- package/package.json +69 -0
package/dist/cli.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/scenarios/internacao.ts","../src/scenarios/paciente-com-exames.ts","../src/scenarios/vacina.ts","../src/scenarios/index.ts","../src/server.ts","../src/keys.ts","../src/auth.ts","../src/jwks.ts","../src/validation/helpers.ts","../src/validation/profiles.ts","../src/validation/index.ts","../src/router.ts","../src/store.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CLI: rnds-sandbox start [opções]\n *\n * Sobe um mock local da RNDS para desenvolvimento.\n */\n\nimport fs from 'node:fs';\nimport { fileURLToPath } from 'node:url';\n\nimport { SCENARIOS } from './scenarios';\nimport { createSandboxServer } from './server';\nimport type { SandboxOptions, ScenarioName } from './types';\n\nexport interface ParsedArgs {\n command?: 'start' | 'help' | 'scenarios';\n errors: string[];\n options: SandboxOptions;\n}\n\nconst HELP = `rnds-sandbox — mock local da RNDS\n\nUso:\n rnds-sandbox start [opções]\n rnds-sandbox scenarios\n rnds-sandbox --help\n\nOpções de start:\n --port <n> Porta (padrão: 8080, ou 8443 se --mtls)\n --host <h> Host (padrão: 127.0.0.1)\n --scenario <nome> paciente-com-exames | internacao | vacina | vazio\n\nModos de fidelidade RNDS:\n --strict Exige bearer token + header Authorization: <CNS> em /api/fhir/r4/*\n (implícito quando --mtls está ativo)\n --mtls HTTPS + handshake mTLS (cliente apresenta cert).\n /api/token exige cert; FHIR API exige bearer.\n --no-validate Desabilita validação contra perfis BR* do IG em POST /Bundle\n (default: validação ON, retorna 422 OperationOutcome em falha)\n\nCert do servidor (use uma forma OU outra):\n --pfx <caminho> PFX do servidor\n --pfx-password <s> Senha do PFX\n --server-key <caminho> PEM da chave privada do servidor\n --server-cert <caminho> PEM do certificado do servidor\n\nChaves de assinatura JWT (RS256):\n --jwt-private-key <p> PEM da chave privada (padrão: gera uma RSA-2048 efêmera)\n --jwt-public-key <p> PEM da chave pública (opcional — derivada da privada)\n --jwt-key-id <s> kid no JWT/JWKS (padrão: rnds-sandbox-1)\n\nExemplos:\n rnds-sandbox start\n rnds-sandbox start --strict --jwt-private-key ./jwt.pem\n rnds-sandbox start --port 9000 --scenario internacao\n rnds-sandbox start --mtls --pfx ./cert.pfx --pfx-password senha\n rnds-sandbox start --mtls --server-key ./srv.key --server-cert ./srv.crt\n`;\n\nconst STRING_ARGS: Record<string, (options: SandboxOptions, value: string) => void> = {\n '--host': (o, v) => {\n o.host = v;\n },\n '--jwt-key-id': (o, v) => {\n o.jwtKeyId = v;\n },\n '--jwt-private-key': (o, v) => {\n o.jwtPrivateKey = v;\n },\n '--jwt-public-key': (o, v) => {\n o.jwtPublicKey = v;\n },\n '--pfx': (o, v) => {\n o.serverPfx = v;\n },\n '--pfx-password': (o, v) => {\n o.serverPfxPassword = v;\n },\n '--server-cert': (o, v) => {\n o.serverCert = v;\n },\n '--server-key': (o, v) => {\n o.serverKey = v;\n },\n};\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const errors: string[] = [];\n const options: SandboxOptions = {};\n let command: ParsedArgs['command'];\n\n const args = [...argv];\n while (args.length > 0) {\n const token = args.shift()!;\n if (token === '--help' || token === '-h') {\n command = 'help';\n continue;\n }\n if (!command && (token === 'start' || token === 'scenarios' || token === 'help')) {\n command = token;\n continue;\n }\n if (token === '--port') {\n const value = args.shift();\n const port = Number(value);\n if (!value || Number.isNaN(port)) {\n errors.push(`--port requer valor numérico, recebido: ${String(value)}`);\n } else {\n options.port = port;\n }\n continue;\n }\n if (token === '--scenario') {\n const value = args.shift();\n if (!value || !(value in SCENARIOS)) {\n errors.push(\n `--scenario inválido. Disponíveis: ${Object.keys(SCENARIOS).join(', ')}. Recebido: ${String(value)}`,\n );\n } else {\n options.scenario = value as ScenarioName;\n }\n continue;\n }\n if (token === '--mtls') {\n options.mtls = true;\n continue;\n }\n if (token === '--strict') {\n options.strict = true;\n continue;\n }\n if (token === '--no-validate') {\n options.validateSubmissions = false;\n continue;\n }\n const stringSetter = STRING_ARGS[token];\n if (stringSetter) {\n const value = args.shift();\n if (!value) {\n errors.push(`${token} requer valor`);\n } else {\n stringSetter(options, value);\n }\n continue;\n }\n errors.push(`argumento desconhecido: ${token}`);\n }\n\n return { command, errors, options };\n}\n\nexport async function main(argv: string[] = process.argv.slice(2)): Promise<number> {\n const parsed = parseArgs(argv);\n\n if (parsed.errors.length > 0) {\n for (const err of parsed.errors) {\n process.stderr.write(`erro: ${err}\\n`);\n }\n process.stderr.write(`\\n${HELP}`);\n return 1;\n }\n\n if (!parsed.command || parsed.command === 'help') {\n process.stdout.write(HELP);\n return 0;\n }\n\n if (parsed.command === 'scenarios') {\n process.stdout.write('Cenários disponíveis:\\n\\n');\n for (const scenario of Object.values(SCENARIOS)) {\n process.stdout.write(` ${scenario.name}\\n ${scenario.description}\\n\\n`);\n }\n return 0;\n }\n\n if (parsed.options.mtls) {\n const hasPfx = parsed.options.serverPfx;\n const hasKeyAndCert = parsed.options.serverKey && parsed.options.serverCert;\n if (!hasPfx && !hasKeyAndCert) {\n process.stderr.write(\n 'erro: --mtls requer --pfx + --pfx-password OU --server-key + --server-cert\\n',\n );\n return 1;\n }\n }\n\n const sandbox = createSandboxServer(parsed.options);\n await sandbox.start();\n\n const shutdown = async (signal: string) => {\n process.stdout.write(`\\n[rnds-sandbox] recebido ${signal}, encerrando...\\n`);\n await sandbox.stop();\n process.exit(0);\n };\n process.on('SIGINT', () => void shutdown('SIGINT'));\n process.on('SIGTERM', () => void shutdown('SIGTERM'));\n\n return 0;\n}\n\n// Só executa quando este arquivo é o entry-point. Comparamos via realpath\n// (ambos os lados) porque `process.argv[1]` pode ser um symlink criado pelo\n// npm em `node_modules/.bin/` enquanto `import.meta.url` resolve para o\n// arquivo bundled real. Sem realpath, importar este módulo em teste acaba\n// disparando `main()` em alguns ambientes / o oposto: o bin não roda quando\n// invocado via npx.\nfunction isCliEntryPoint(): boolean {\n const argv1 = process.argv[1];\n if (typeof argv1 !== 'string' || argv1.length === 0) return false;\n try {\n const here = fs.realpathSync(fileURLToPath(import.meta.url));\n const invoked = fs.realpathSync(argv1);\n return here === invoked;\n } catch {\n return false;\n }\n}\n\nif (isCliEntryPoint()) {\n main().catch((err: unknown) => {\n process.stderr.write(`erro fatal: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n });\n}\n","/**\n * Cenário: paciente com episódio de internação recente.\n *\n * Carlos Henrique Souza, 67 anos, internado por descompensação de\n * insuficiência cardíaca. Bundle pré-submetido contém Encounter\n * (admissão) + Observations (BNP, troponina) + Condition (CID I50.0).\n */\n\nimport type { Scenario } from '../types';\n\nconst CPF = '98765432100';\nconst CNS = '700000000000020';\nconst CNES_HOSPITAL = '3456789';\nconst CNS_PROFISSIONAL = '700000000000030';\n\nexport const internacao: Scenario = {\n data: {\n organizations: [\n {\n active: true,\n id: CNES_HOSPITAL,\n identifier: [\n { system: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cnes', value: CNES_HOSPITAL },\n ],\n name: 'Hospital Sintético do Coração (sandbox)',\n resourceType: 'Organization',\n },\n ],\n patients: [\n {\n birthDate: '1958-02-28',\n gender: 'male',\n id: CNS,\n identifier: [\n { system: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cpf', value: CPF },\n { system: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cns', value: CNS },\n ],\n name: [{ family: 'Souza', given: ['Carlos', 'Henrique'] }],\n resourceType: 'Patient',\n },\n ],\n practitioners: [\n {\n active: true,\n id: CNS_PROFISSIONAL,\n identifier: [\n {\n system: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cns',\n value: CNS_PROFISSIONAL,\n },\n ],\n name: [{ family: 'Mendes', given: ['Roberto'] }],\n resourceType: 'Practitioner',\n },\n ],\n submittedBundles: [\n {\n entry: [\n {\n request: { method: 'POST', url: 'Encounter' },\n resource: {\n class: { code: 'IMP', display: 'inpatient encounter' },\n period: { start: '2026-04-15T10:30:00-03:00' },\n resourceType: 'Encounter',\n serviceProvider: { reference: `Organization/${CNES_HOSPITAL}` },\n status: 'in-progress',\n subject: { reference: `Patient/${CNS}` },\n },\n },\n {\n request: { method: 'POST', url: 'Condition' },\n resource: {\n code: {\n coding: [\n {\n code: 'I50.0',\n display: 'Insuficiência cardíaca congestiva',\n system: 'http://hl7.org/fhir/sid/icd-10',\n },\n ],\n },\n recordedDate: '2026-04-15',\n resourceType: 'Condition',\n subject: { reference: `Patient/${CNS}` },\n },\n },\n {\n request: { method: 'POST', url: 'Observation' },\n resource: {\n code: {\n coding: [{ code: '33762-6', display: 'NT-proBNP', system: 'http://loinc.org' }],\n },\n effectiveDateTime: '2026-04-15T11:15:00-03:00',\n resourceType: 'Observation',\n status: 'final',\n subject: { reference: `Patient/${CNS}` },\n valueQuantity: {\n code: 'pg/mL',\n system: 'http://unitsofmeasure.org',\n unit: 'pg/mL',\n value: 4820,\n },\n },\n },\n {\n request: { method: 'POST', url: 'Observation' },\n resource: {\n code: {\n coding: [{ code: '49563-0', display: 'Troponina I', system: 'http://loinc.org' }],\n },\n effectiveDateTime: '2026-04-15T11:15:00-03:00',\n resourceType: 'Observation',\n status: 'final',\n subject: { reference: `Patient/${CNS}` },\n valueQuantity: {\n code: 'ng/mL',\n system: 'http://unitsofmeasure.org',\n unit: 'ng/mL',\n value: 0.08,\n },\n },\n },\n ],\n resourceType: 'Bundle',\n type: 'transaction',\n },\n ],\n },\n description:\n 'Carlos Henrique Souza (CPF 987.654.321-00, CNS 700 0000 0000 0020), 67 anos, internado por insuficiência cardíaca descompensada (CID I50.0). Hospital CNES 3456789.',\n name: 'internacao',\n};\n","/**\n * Cenário: paciente com histórico de exames laboratoriais.\n *\n * Joana Maria da Silva, 42 anos, com Bundle pré-submetido de\n * lipidograma, glicemia e hemograma. Útil para demonstrar\n * o fluxo \"buscar paciente → consultar exames anteriores → submeter novos\".\n *\n * IDs sintéticos — não correspondem a CPF/CNS reais.\n */\n\nimport type { Scenario } from '../types';\n\nconst CPF = '12345678901';\nconst CNS = '700000000000001';\nconst CNES_LAB = '2345678';\nconst CNS_PROFISSIONAL = '700000000000010';\n\nexport const pacienteComExames: Scenario = {\n data: {\n organizations: [\n {\n active: true,\n id: CNES_LAB,\n identifier: [\n {\n system: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cnes',\n value: CNES_LAB,\n },\n ],\n name: 'Laboratório Sintético São Paulo (sandbox)',\n resourceType: 'Organization',\n },\n ],\n patients: [\n {\n birthDate: '1983-08-12',\n gender: 'female',\n id: CNS,\n identifier: [\n { system: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cpf', value: CPF },\n { system: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cns', value: CNS },\n ],\n name: [{ family: 'Silva', given: ['Joana', 'Maria', 'da'] }],\n resourceType: 'Patient',\n },\n ],\n practitioners: [\n {\n active: true,\n id: CNS_PROFISSIONAL,\n identifier: [\n {\n system: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cns',\n value: CNS_PROFISSIONAL,\n },\n ],\n name: [{ family: 'Pereira', given: ['Ana', 'Carolina'] }],\n resourceType: 'Practitioner',\n },\n ],\n submittedBundles: [\n {\n entry: [\n {\n request: { method: 'POST', url: 'Observation' },\n resource: {\n code: {\n coding: [\n {\n code: '2093-3',\n display: 'Colesterol total',\n system: 'http://loinc.org',\n },\n ],\n },\n effectiveDateTime: '2025-09-10',\n resourceType: 'Observation',\n status: 'final',\n subject: { reference: `Patient/${CNS}` },\n valueQuantity: {\n code: 'mg/dL',\n system: 'http://unitsofmeasure.org',\n unit: 'mg/dL',\n value: 198,\n },\n },\n },\n {\n request: { method: 'POST', url: 'Observation' },\n resource: {\n code: {\n coding: [{ code: '2089-1', display: 'LDL-Colesterol', system: 'http://loinc.org' }],\n },\n effectiveDateTime: '2025-09-10',\n resourceType: 'Observation',\n status: 'final',\n subject: { reference: `Patient/${CNS}` },\n valueQuantity: {\n code: 'mg/dL',\n system: 'http://unitsofmeasure.org',\n unit: 'mg/dL',\n value: 124,\n },\n },\n },\n {\n request: { method: 'POST', url: 'Observation' },\n resource: {\n code: {\n coding: [{ code: '2085-9', display: 'HDL-Colesterol', system: 'http://loinc.org' }],\n },\n effectiveDateTime: '2025-09-10',\n resourceType: 'Observation',\n status: 'final',\n subject: { reference: `Patient/${CNS}` },\n valueQuantity: {\n code: 'mg/dL',\n system: 'http://unitsofmeasure.org',\n unit: 'mg/dL',\n value: 56,\n },\n },\n },\n {\n request: { method: 'POST', url: 'Observation' },\n resource: {\n code: {\n coding: [{ code: '2345-7', display: 'Glicose', system: 'http://loinc.org' }],\n },\n effectiveDateTime: '2025-09-10',\n resourceType: 'Observation',\n status: 'final',\n subject: { reference: `Patient/${CNS}` },\n valueQuantity: {\n code: 'mg/dL',\n system: 'http://unitsofmeasure.org',\n unit: 'mg/dL',\n value: 96,\n },\n },\n },\n ],\n resourceType: 'Bundle',\n type: 'transaction',\n },\n ],\n },\n description:\n 'Joana Maria da Silva (CPF 123.456.789-01, CNS 700 0000 0000 0001), 42 anos, com histórico de lipidograma e glicemia. Laboratório CNES 2345678. Profissional Dr(a). Pereira (CNS 700 0000 0000 0010).',\n name: 'paciente-com-exames',\n};\n","/**\n * Cenário: paciente com calendário vacinal aplicado.\n *\n * Pedro Lima Almeida, 8 anos, com Bundle pré-submetido contendo\n * Immunization (BCG, hepatite B, pentavalente, tríplice viral).\n */\n\nimport type { Scenario } from '../types';\n\nconst CNS = '700000000000040';\nconst CNES_UBS = '4567890';\nconst CNS_PROFISSIONAL = '700000000000050';\n\nexport const vacina: Scenario = {\n data: {\n organizations: [\n {\n active: true,\n id: CNES_UBS,\n identifier: [\n { system: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cnes', value: CNES_UBS },\n ],\n name: 'UBS Sintética Vila Saúde (sandbox)',\n resourceType: 'Organization',\n },\n ],\n patients: [\n {\n birthDate: '2017-11-04',\n gender: 'male',\n id: CNS,\n identifier: [{ system: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cns', value: CNS }],\n name: [{ family: 'Almeida', given: ['Pedro', 'Lima'] }],\n resourceType: 'Patient',\n },\n ],\n practitioners: [\n {\n active: true,\n id: CNS_PROFISSIONAL,\n identifier: [\n {\n system: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cns',\n value: CNS_PROFISSIONAL,\n },\n ],\n name: [{ family: 'Costa', given: ['Fernanda'] }],\n resourceType: 'Practitioner',\n },\n ],\n submittedBundles: [\n {\n entry: [\n {\n request: { method: 'POST', url: 'Immunization' },\n resource: {\n occurrenceDateTime: '2017-11-05',\n patient: { reference: `Patient/${CNS}` },\n resourceType: 'Immunization',\n status: 'completed',\n vaccineCode: {\n coding: [{ code: 'BCG', display: 'BCG', system: 'urn:oid:2.16.840.1.113883.6.59' }],\n },\n },\n },\n {\n request: { method: 'POST', url: 'Immunization' },\n resource: {\n occurrenceDateTime: '2017-11-05',\n patient: { reference: `Patient/${CNS}` },\n resourceType: 'Immunization',\n status: 'completed',\n vaccineCode: {\n coding: [\n {\n code: 'HBV',\n display: 'Hepatite B (RN)',\n system: 'urn:oid:2.16.840.1.113883.6.59',\n },\n ],\n },\n },\n },\n {\n request: { method: 'POST', url: 'Immunization' },\n resource: {\n occurrenceDateTime: '2018-12-12',\n patient: { reference: `Patient/${CNS}` },\n resourceType: 'Immunization',\n status: 'completed',\n vaccineCode: {\n coding: [\n {\n code: 'MMR',\n display: 'Tríplice viral (SCR)',\n system: 'urn:oid:2.16.840.1.113883.6.59',\n },\n ],\n },\n },\n },\n ],\n resourceType: 'Bundle',\n type: 'transaction',\n },\n ],\n },\n description:\n 'Pedro Lima Almeida (CNS 700 0000 0000 0040), 8 anos, com calendário vacinal aplicado em UBS CNES 4567890.',\n name: 'vacina',\n};\n","/**\n * Registro de cenários disponíveis no sandbox.\n */\n\nimport type { Scenario, ScenarioName } from '../types';\nimport { internacao } from './internacao';\nimport { pacienteComExames } from './paciente-com-exames';\nimport { vacina } from './vacina';\n\nexport const SCENARIOS: Record<ScenarioName, Scenario> = {\n internacao,\n 'paciente-com-exames': pacienteComExames,\n vacina,\n vazio: {\n data: { organizations: [], patients: [], practitioners: [] },\n description: 'Estado limpo. Útil para testar fluxos do zero.',\n name: 'vazio',\n },\n};\n\nexport function resolveScenario(name: ScenarioName | undefined): Scenario {\n return SCENARIOS[name ?? 'paciente-com-exames'];\n}\n\nexport { internacao, pacienteComExames, vacina };\n","/**\n * Servidor HTTP(S) do sandbox.\n *\n * Cria um http.Server (sem mTLS) ou https.Server (com mTLS opcional)\n * que despacha requisições para o roteador. Em modo mTLS, o cert do\n * cliente apresentado no handshake é repassado ao roteador para que\n * /api/token possa exigir + extrair identidade dele.\n */\n\nimport fs from 'node:fs';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport http from 'node:http';\nimport https from 'node:https';\nimport type { TLSSocket } from 'node:tls';\n\nimport { resolveSigningKeys, type SigningKeys } from './keys';\nimport { dispatch, type PeerCertInfo, type RouteContext } from './router';\nimport { resolveScenario } from './scenarios';\nimport { SandboxStore } from './store';\nimport type { SandboxOptions } from './types';\n\nexport interface SandboxServer {\n /** Servidor HTTP(S) subjacente. */\n server: http.Server | https.Server;\n /** Chaves RSA usadas para assinar/validar tokens. */\n signingKeys: SigningKeys;\n /** Inicia o servidor. Retorna quando estiver escutando. */\n start: () => Promise<{ host: string; port: number }>;\n /** Encerra o servidor. */\n stop: () => Promise<void>;\n /** Store em memória — útil para inspeção em testes. */\n store: SandboxStore;\n}\n\nexport function createSandboxServer(options: SandboxOptions = {}): SandboxServer {\n // eslint-disable-next-line no-console\n const log = options.log ?? ((msg: string) => console.log(`[rnds-sandbox] ${msg}`));\n const useMtls = options.mtls === true;\n const strict = options.strict ?? useMtls;\n const validateProfiles = options.validateSubmissions ?? true;\n const port = options.port ?? (useMtls ? 8443 : 8080);\n const host = options.host ?? '127.0.0.1';\n\n const store = new SandboxStore();\n store.load(resolveScenario(options.scenario));\n\n const signingKeys = resolveSigningKeys({\n keyId: options.jwtKeyId,\n privateKey: options.jwtPrivateKey,\n publicKey: options.jwtPublicKey,\n });\n\n const handler = (req: IncomingMessage, res: ServerResponse) => {\n handleRequest(req, res, {\n keys: signingKeys,\n log,\n store,\n strict,\n useMtls,\n validateProfiles,\n }).catch((err: unknown) => {\n log(`erro inesperado: ${err instanceof Error ? err.message : String(err)}`);\n if (res.headersSent) {\n // Headers já foram para o socket — só garante que o response feche\n // para o cliente não pendurar. Sem body novo.\n if (!res.writableEnded) res.end();\n return;\n }\n res.writeHead(500, { 'Content-Type': 'application/fhir+json; charset=utf-8' });\n res.end(\n JSON.stringify({\n issue: [{ code: 'exception', diagnostics: String(err), severity: 'fatal' }],\n resourceType: 'OperationOutcome',\n }),\n );\n });\n };\n\n const server: http.Server | https.Server = useMtls\n ? https.createServer(buildTlsOptions(options), handler)\n : http.createServer(handler);\n\n return {\n server,\n signingKeys,\n start: () =>\n new Promise<{ host: string; port: number }>((resolve, reject) => {\n const onError = (err: Error) => {\n server.off('error', onError);\n reject(err);\n };\n server.once('error', onError);\n server.listen(port, host, () => {\n server.off('error', onError);\n const address = server.address();\n const actualPort = typeof address === 'object' && address ? address.port : port;\n log(\n `${useMtls ? 'HTTPS+mTLS' : 'HTTP'} ouvindo em ${host}:${actualPort} ` +\n `(cenário: ${options.scenario ?? 'paciente-com-exames'}, ` +\n `strict=${strict}, validate=${validateProfiles}, kid=${signingKeys.keyId})`,\n );\n resolve({ host, port: actualPort });\n });\n }),\n stop: () =>\n new Promise<void>((resolve, reject) => {\n // server.close() para de aceitar novas conexões mas não derruba\n // keep-alive existentes — em testes isso pode prender o vitest.\n server.closeAllConnections?.();\n server.close((err) => (err ? reject(err) : resolve()));\n }),\n store,\n };\n}\n\ninterface HandlerContext {\n keys: SigningKeys;\n log: (msg: string) => void;\n store: SandboxStore;\n strict: boolean;\n useMtls: boolean;\n validateProfiles: boolean;\n}\n\nasync function handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n ctx: HandlerContext,\n): Promise<void> {\n const url = new URL(req.url ?? '/', 'http://sandbox.local');\n const body = await readBody(req);\n const peerCert = ctx.useMtls ? extractPeerCert(req) : undefined;\n const headers = lowercaseHeaders(req.headers);\n\n const routeCtx: RouteContext = {\n body,\n headers,\n keys: ctx.keys,\n method: req.method ?? 'GET',\n path: url.pathname,\n peerCert,\n query: url.searchParams,\n store: ctx.store,\n strict: ctx.strict,\n validateProfiles: ctx.validateProfiles,\n };\n\n const response = dispatch(routeCtx);\n ctx.log(`${routeCtx.method} ${routeCtx.path} → ${response.status}`);\n\n res.writeHead(response.status, {\n 'Content-Type': 'application/fhir+json; charset=utf-8',\n });\n res.end(JSON.stringify(response.body));\n}\n\n/** Sentinela retornada quando o corpo da requisição não é JSON válido. */\nconst INVALID_BODY = Symbol.for('rnds-sandbox.invalidBody');\n\nasync function readBody(req: IncomingMessage): Promise<unknown> {\n if (req.method !== 'POST' && req.method !== 'PUT') {\n return undefined;\n }\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n if (chunks.length === 0) {\n return undefined;\n }\n const text = Buffer.concat(chunks).toString('utf-8');\n if (!text) {\n return undefined;\n }\n try {\n return JSON.parse(text);\n } catch {\n // JSON malformado — retorna sentinela. Handler de POST detecta e\n // devolve OperationOutcome com `code: 'structure'` em vez de tentar\n // tratar a string como Bundle.\n return INVALID_BODY;\n }\n}\n\n/** True quando o body é a sentinela INVALID_BODY (JSON malformado). */\nexport function isInvalidBody(body: unknown): boolean {\n return body === INVALID_BODY;\n}\n\nfunction extractPeerCert(req: IncomingMessage): PeerCertInfo {\n const socket = req.socket as TLSSocket;\n if (typeof socket.getPeerCertificate !== 'function') {\n return { presented: false };\n }\n const cert = socket.getPeerCertificate();\n if (!cert || Object.keys(cert).length === 0) {\n return { presented: false };\n }\n const cn = readCommonName(cert.subject);\n return {\n cn,\n cnes: cn ? extractCnesFromCn(cn) : undefined,\n presented: true,\n };\n}\n\nfunction readCommonName(subject: unknown): string | undefined {\n if (!subject || typeof subject !== 'object') {\n return undefined;\n }\n const cnValue = (subject as Record<string, unknown>).CN;\n if (typeof cnValue === 'string') {\n return cnValue;\n }\n return undefined;\n}\n\nfunction extractCnesFromCn(cn: string): string | undefined {\n // Heurística: CN de cert ICP-Brasil PJ frequentemente embute CNES como\n // sequência de 7 dígitos; se não for o caso, simplesmente não retorna nada.\n const match = /\\b(\\d{7})\\b/.exec(cn);\n return match ? match[1] : undefined;\n}\n\nfunction lowercaseHeaders(headers: http.IncomingHttpHeaders): Record<string, string | undefined> {\n const out: Record<string, string | undefined> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (Array.isArray(value)) {\n out[key.toLowerCase()] = value.join(', ');\n } else {\n out[key.toLowerCase()] = value;\n }\n }\n return out;\n}\n\nfunction buildTlsOptions(options: SandboxOptions): https.ServerOptions {\n const tlsOptions: https.ServerOptions = {\n rejectUnauthorized: false,\n requestCert: true,\n };\n if (options.serverPfx) {\n tlsOptions.pfx = resolveBuffer(options.serverPfx);\n if (options.serverPfxPassword) {\n tlsOptions.passphrase = options.serverPfxPassword;\n }\n } else if (options.serverKey && options.serverCert) {\n tlsOptions.key = resolveBuffer(options.serverKey);\n tlsOptions.cert = resolveBuffer(options.serverCert);\n } else {\n throw new Error('mTLS requer --pfx + --pfx-password OU --server-key + --server-cert (PEM)');\n }\n return tlsOptions;\n}\n\nfunction resolveBuffer(value: Buffer | string): Buffer {\n if (typeof value !== 'string') {\n return value;\n }\n if (value.includes('-----BEGIN')) {\n return Buffer.from(value);\n }\n return fs.readFileSync(value);\n}\n","/**\n * Geração e carregamento de chaves RSA para assinatura RS256 do JWT.\n *\n * Em produção a RNDS usa chaves estáveis (com `kid` publicado em JWKS).\n * No sandbox, geramos um par RSA-2048 efêmero no boot por padrão; quem\n * precisa de tokens estáveis entre reinícios passa `--jwt-private-key`\n * (PEM) — útil em CI ou em demos onde o token é capturado e reutilizado.\n */\n\nimport {\n createPrivateKey,\n createPublicKey,\n generateKeyPairSync,\n type KeyObject,\n} from 'node:crypto';\nimport fs from 'node:fs';\n\nexport interface SigningKeys {\n /** Identificador da chave (claim `kid` no JWT, `kid` no JWKS) */\n keyId: string;\n /** Chave privada — usada para assinar */\n privateKey: KeyObject;\n /** Chave pública — exposta via JWKS */\n publicKey: KeyObject;\n}\n\nexport interface KeyOptions {\n /** Identificador da chave. Padrão: 'rnds-sandbox-1' */\n keyId?: string;\n /** PEM da chave privada (Buffer ou caminho). Se omitido, gera-se um par novo. */\n privateKey?: Buffer | string;\n /** PEM da chave pública (Buffer ou caminho). Opcional — derivada da privada quando omitida. */\n publicKey?: Buffer | string;\n}\n\nconst DEFAULT_KEY_ID = 'rnds-sandbox-1';\n\n// Singleton lazy do par RSA gerado — caro (~50ms) e não-determinístico.\n// Cacheamos pra que múltiplos `resolveSigningKeys()` sem opções (caso\n// típico de testes que rodam à parte) compartilhem o mesmo par e o\n// `kid`. Quem precisar de chaves distintas passa `keyId` ou `privateKey`\n// diferentes.\nlet cachedDefaultKeys: SigningKeys | undefined;\n\nexport function resolveSigningKeys(options: KeyOptions = {}): SigningKeys {\n const keyId = options.keyId ?? DEFAULT_KEY_ID;\n\n if (options.privateKey) {\n const privatePem = readPem(options.privateKey);\n const privateKey = createPrivateKey(privatePem);\n const publicKey = options.publicKey\n ? createPublicKey(readPem(options.publicKey))\n : createPublicKey(privateKey);\n return { keyId, privateKey, publicKey };\n }\n\n // Cache atinge somente o caminho default (sem PEM, com keyId padrão).\n // Qualquer override de keyId exige par novo (testes podem querer kids distintos).\n if (keyId === DEFAULT_KEY_ID && cachedDefaultKeys) {\n return cachedDefaultKeys;\n }\n\n const generated = generateKeyPairSync('rsa', { modulusLength: 2048 });\n const result: SigningKeys = {\n keyId,\n privateKey: generated.privateKey,\n publicKey: generated.publicKey,\n };\n if (keyId === DEFAULT_KEY_ID) {\n cachedDefaultKeys = result;\n }\n return result;\n}\n\n/** Limpa o cache do par default — útil em testes que precisam reset. */\nexport function resetSigningKeysCache(): void {\n cachedDefaultKeys = undefined;\n}\n\nfunction readPem(value: Buffer | string): Buffer | string {\n if (typeof value !== 'string') {\n return value;\n }\n if (value.includes('-----BEGIN')) {\n return value;\n }\n return fs.readFileSync(value);\n}\n","/**\n * Emissor e verificador de tokens JWT (RS256) para o sandbox.\n *\n * A RNDS real assina seus tokens com RS256 e expõe a chave pública\n * para validação. O sandbox faz o mesmo: gera (ou carrega) um par\n * RSA-2048, assina com a privada e expõe a pública via JWKS em\n * `/.well-known/jwks.json`.\n *\n * Claims seguem o formato observado em respostas da RNDS:\n * `iss`, `sub`, `aud`, `iat`, `exp`, e — quando o cliente apresenta\n * certificado mTLS — `cn`/`cnes` extraídos do certificado.\n */\n\nimport { createSign, createVerify } from 'node:crypto';\n\nimport type { SigningKeys } from './keys';\n\nconst TOKEN_TTL_MS = 30 * 60 * 1000;\n\nexport interface TokenPayload {\n access_token: string;\n expires_in: number;\n scope: string;\n token_type: string;\n}\n\nexport interface JwtClaims {\n /** Audience — identifica quem deve consumir o token */\n aud: string;\n /** Common Name do certificado mTLS, se houver */\n cn?: string;\n /** CNES extraído do certificado mTLS apresentado, se houver */\n cnes?: string;\n /** Expiração (epoch seconds) */\n exp: number;\n /** Issued at (epoch seconds) */\n iat: number;\n /** Issuer */\n iss: string;\n /** Subject — identidade do cliente (CN ou 'sandbox') */\n sub: string;\n}\n\nexport interface IssueTokenOptions {\n /** Audience — padrão 'rnds-sandbox' */\n audience?: string;\n /** Identidade extraída do certificado mTLS, se aplicável */\n identity?: { cn?: string; cnes?: string };\n /** Issuer — padrão 'https://rnds-sandbox.local' */\n issuer?: string;\n /** Override de tempo (testes) */\n now?: number;\n}\n\nexport function issueToken(keys: SigningKeys, options: IssueTokenOptions = {}): TokenPayload {\n const now = options.now ?? Date.now();\n const audience = options.audience ?? 'rnds-sandbox';\n const issuer = options.issuer ?? 'https://rnds-sandbox.local';\n\n const claims: JwtClaims = {\n aud: audience,\n exp: Math.floor((now + TOKEN_TTL_MS) / 1000),\n iat: Math.floor(now / 1000),\n iss: issuer,\n sub: options.identity?.cn ?? 'sandbox',\n ...(options.identity?.cn ? { cn: options.identity.cn } : {}),\n ...(options.identity?.cnes ? { cnes: options.identity.cnes } : {}),\n };\n\n const accessToken = signJwt(claims, keys);\n\n return {\n access_token: accessToken,\n expires_in: Math.floor(TOKEN_TTL_MS / 1000),\n scope: 'rnds:read rnds:write',\n token_type: 'Bearer',\n };\n}\n\nexport type VerifyResult =\n | { valid: true; claims: JwtClaims }\n | {\n valid: false;\n reason: 'malformed' | 'bad-signature' | 'expired' | 'wrong-key' | 'wrong-audience';\n };\n\nexport interface VerifyOptions {\n /** Audience esperada — falha quando claim `aud` não casa. Padrão: 'rnds-sandbox' */\n audience?: string;\n /** Override de tempo para testes */\n now?: number;\n}\n\nexport function verifyToken(\n token: string,\n keys: SigningKeys,\n options: VerifyOptions = {},\n): VerifyResult {\n const now = options.now ?? Date.now();\n const expectedAudience = options.audience ?? 'rnds-sandbox';\n const parts = token.split('.');\n if (parts.length !== 3) {\n return { reason: 'malformed', valid: false };\n }\n const [headerB64, payloadB64, signatureB64] = parts as [string, string, string];\n\n let header: { alg?: string; kid?: string; typ?: string };\n let payload: JwtClaims;\n try {\n header = JSON.parse(Buffer.from(headerB64, 'base64url').toString('utf-8')) as typeof header;\n payload = JSON.parse(Buffer.from(payloadB64, 'base64url').toString('utf-8')) as JwtClaims;\n } catch {\n return { reason: 'malformed', valid: false };\n }\n\n if (header.alg !== 'RS256') {\n return { reason: 'malformed', valid: false };\n }\n if (header.kid && header.kid !== keys.keyId) {\n return { reason: 'wrong-key', valid: false };\n }\n\n const signingInput = `${headerB64}.${payloadB64}`;\n const verifier = createVerify('RSA-SHA256').update(signingInput);\n const signatureValid = verifier.verify(keys.publicKey, Buffer.from(signatureB64, 'base64url'));\n if (!signatureValid) {\n return { reason: 'bad-signature', valid: false };\n }\n\n if (payload.exp * 1000 < now) {\n return { reason: 'expired', valid: false };\n }\n\n if (payload.aud !== expectedAudience) {\n return { reason: 'wrong-audience', valid: false };\n }\n\n return { claims: payload, valid: true };\n}\n\nfunction signJwt(claims: JwtClaims, keys: SigningKeys): string {\n const header = { alg: 'RS256', kid: keys.keyId, typ: 'JWT' };\n const headerB64 = base64UrlJson(header);\n const payloadB64 = base64UrlJson(claims);\n const signingInput = `${headerB64}.${payloadB64}`;\n const signer = createSign('RSA-SHA256').update(signingInput);\n const signature = signer.sign(keys.privateKey).toString('base64url');\n return `${signingInput}.${signature}`;\n}\n\nfunction base64UrlJson(value: unknown): string {\n return Buffer.from(JSON.stringify(value)).toString('base64url');\n}\n","/**\n * Geração do documento JWKS (`/.well-known/jwks.json`).\n *\n * Permite que clientes (incluindo jwt.io) busquem a chave pública do\n * sandbox e validem a assinatura do token sem nenhuma configuração\n * fora-de-banda.\n */\n\nimport type { SigningKeys } from './keys';\n\nexport interface Jwk {\n alg: 'RS256';\n e: string;\n kid: string;\n kty: 'RSA';\n n: string;\n use: 'sig';\n}\n\nexport interface JwksDocument {\n keys: Jwk[];\n}\n\nexport function buildJwks(keys: SigningKeys): JwksDocument {\n const exported = keys.publicKey.export({ format: 'jwk' });\n if (typeof exported !== 'object' || exported === null || exported.kty !== 'RSA') {\n throw new Error('Chave pública não é RSA — JWKS só suporta RS256 no sandbox');\n }\n if (typeof exported.n !== 'string' || typeof exported.e !== 'string') {\n throw new Error('Chave pública RSA exportada está incompleta (n/e ausentes)');\n }\n return {\n keys: [\n {\n alg: 'RS256',\n e: exported.e,\n kid: keys.keyId,\n kty: 'RSA',\n n: exported.n,\n use: 'sig',\n },\n ],\n };\n}\n","/**\n * Helpers compartilhados pelos validadores de perfil.\n *\n * Cada helper retorna `ValidationIssue[]` (vazio quando passa) para que\n * os validadores de perfil possam compor checagens com `[].concat(...)`.\n */\n\nimport type { IssueSeverity, ValidationIssue } from './types';\n\nexport function issue(\n severity: IssueSeverity,\n code: string,\n diagnostics: string,\n path: string,\n): ValidationIssue {\n // Apenas `expression` (FHIRPath) — `location` foi marcado deprecated\n // no R4 em favor de `expression`. Conteúdo idêntico em ambos só\n // poluiria a saída.\n return { code, diagnostics, expression: [path], severity };\n}\n\n/** Retorna issue `error/required` se `value` for null/undefined. */\nexport function requireField(value: unknown, label: string, path: string): ValidationIssue[] {\n if (value === undefined || value === null) {\n return [issue('error', 'required', `${label} é obrigatório`, path)];\n }\n return [];\n}\n\n/** Retorna issue se `value` não for um array com pelo menos `min` elementos. */\nexport function requireMinCardinality(\n value: unknown,\n min: number,\n label: string,\n path: string,\n): ValidationIssue[] {\n if (!Array.isArray(value) || value.length < min) {\n return [\n issue(\n 'error',\n 'required',\n `${label} requer pelo menos ${min} elemento(s); recebido ${\n Array.isArray(value) ? value.length : 0\n }`,\n path,\n ),\n ];\n }\n return [];\n}\n\n/** Retorna issue se `actual` não estiver no conjunto `allowed`. */\nexport function requireOneOf(\n actual: unknown,\n allowed: readonly string[],\n label: string,\n path: string,\n): ValidationIssue[] {\n if (typeof actual !== 'string' || !allowed.includes(actual)) {\n return [\n issue(\n 'error',\n 'invalid',\n `${label} deve ser um de [${allowed.join(', ')}]; recebido \"${String(actual)}\"`,\n path,\n ),\n ];\n }\n return [];\n}\n\n/** Retorna issue se a string não casar com o regex. */\nexport function requirePattern(\n value: unknown,\n pattern: RegExp,\n label: string,\n path: string,\n): ValidationIssue[] {\n if (typeof value !== 'string' || !pattern.test(value)) {\n return [\n issue(\n 'error',\n 'invalid',\n `${label} não obedece ao formato esperado (${pattern.source})`,\n path,\n ),\n ];\n }\n return [];\n}\n\n/**\n * Retorna o valor de `obj[key]` quando obj é um objeto não-null, ou\n * undefined caso contrário (sem lançar).\n */\nexport function get<T = unknown>(obj: unknown, key: string): T | undefined {\n if (obj && typeof obj === 'object') {\n return (obj as Record<string, unknown>)[key] as T | undefined;\n }\n return undefined;\n}\n","/**\n * Validadores de perfil para os recursos cobertos pelo IG do fhir-brasil\n * (BRPatient, BRLabObservation, BRDiagnosticReport).\n *\n * As regras espelham as restrições do FSH em `ig/input/fsh/profiles/`.\n * Não pretendem ser uma implementação completa de FHIR validation —\n * cobrem o que a RNDS real rejeita na prática para esses três perfis.\n */\n\nimport { get, issue, requireField, requireMinCardinality, requireOneOf } from './helpers';\nimport type { ValidationIssue } from './types';\n\n// ============================================================================\n// Constantes do IG (alinhadas com aliases.fsh / sushi-config.yaml)\n// ============================================================================\n\nconst NS_CPF = 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cpf';\nconst NS_CNS = 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cns';\nconst SYS_LOINC = 'http://loinc.org';\nconst SYS_UCUM = 'http://unitsofmeasure.org';\nconst SYS_OBS_CATEGORY = 'http://terminology.hl7.org/CodeSystem/observation-category';\nconst SYS_V2_0074 = 'http://terminology.hl7.org/CodeSystem/v2-0074';\n\nconst PATIENT_GENDERS = ['male', 'female', 'other', 'unknown'] as const;\nconst LAB_OBS_STATUS = ['final', 'amended', 'corrected'] as const;\nconst DIAG_REPORT_STATUS = ['final', 'amended', 'corrected'] as const;\n\n// ============================================================================\n// BRPatient\n// ============================================================================\n\nexport function validateBRPatient(resource: unknown, path: string): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n const identifiers = get<unknown[]>(resource, 'identifier');\n issues.push(...requireMinCardinality(identifiers, 1, 'Patient.identifier', `${path}.identifier`));\n\n if (Array.isArray(identifiers)) {\n const hasBrazilianId = identifiers.some((id) => {\n const sys = get<string>(id, 'system');\n return sys === NS_CPF || sys === NS_CNS;\n });\n if (!hasBrazilianId) {\n issues.push(\n issue(\n 'error',\n 'invariant',\n 'Patient deve ter pelo menos um identificador CPF ou CNS (br-patient-identifier)',\n `${path}.identifier`,\n ),\n );\n }\n }\n\n const names = get<unknown[]>(resource, 'name');\n issues.push(...requireMinCardinality(names, 1, 'Patient.name', `${path}.name`));\n\n issues.push(\n ...requireField(get(resource, 'birthDate'), 'Patient.birthDate', `${path}.birthDate`),\n );\n const gender = get(resource, 'gender');\n issues.push(...requireField(gender, 'Patient.gender', `${path}.gender`));\n if (gender !== undefined) {\n issues.push(...requireOneOf(gender, PATIENT_GENDERS, 'Patient.gender', `${path}.gender`));\n }\n\n return issues;\n}\n\n// ============================================================================\n// BRLabObservation\n// ============================================================================\n\nexport function validateBRLabObservation(resource: unknown, path: string): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n const status = get(resource, 'status');\n issues.push(...requireField(status, 'Observation.status', `${path}.status`));\n if (status !== undefined) {\n issues.push(...requireOneOf(status, LAB_OBS_STATUS, 'Observation.status', `${path}.status`));\n }\n\n const categories = get<unknown[]>(resource, 'category');\n issues.push(...requireMinCardinality(categories, 1, 'Observation.category', `${path}.category`));\n if (Array.isArray(categories)) {\n const hasLab = categories.some((cat) => {\n const codings = get<unknown[]>(cat, 'coding');\n return (\n Array.isArray(codings) &&\n codings.some(\n (c) =>\n get<string>(c, 'system') === SYS_OBS_CATEGORY &&\n get<string>(c, 'code') === 'laboratory',\n )\n );\n });\n if (!hasLab) {\n issues.push(\n issue(\n 'error',\n 'invalid',\n 'Observation.category deve incluir { system: observation-category, code: laboratory }',\n `${path}.category`,\n ),\n );\n }\n }\n\n const code = get(resource, 'code');\n issues.push(...requireField(code, 'Observation.code', `${path}.code`));\n if (code) {\n const codings = get<unknown[]>(code, 'coding');\n const hasLoinc =\n Array.isArray(codings) && codings.some((c) => get<string>(c, 'system') === SYS_LOINC);\n if (!hasLoinc) {\n issues.push(\n issue(\n 'error',\n 'required',\n 'Observation.code.coding deve incluir um coding com system http://loinc.org',\n `${path}.code.coding`,\n ),\n );\n }\n }\n\n const value = get(resource, 'valueQuantity');\n issues.push(...requireField(value, 'Observation.valueQuantity', `${path}.valueQuantity`));\n if (value) {\n issues.push(\n ...requireField(get(value, 'value'), 'valueQuantity.value', `${path}.valueQuantity.value`),\n );\n issues.push(\n ...requireField(get(value, 'unit'), 'valueQuantity.unit', `${path}.valueQuantity.unit`),\n );\n issues.push(\n ...requireField(get(value, 'code'), 'valueQuantity.code', `${path}.valueQuantity.code`),\n );\n // `system` é simultaneamente obrigatório (1..1) e fixo em UCUM. Tratamos\n // os dois casos explicitamente em vez de empilhar checagens — fica\n // claro que ausente vira `required` e errado vira `invalid`.\n const sys = get(value, 'system');\n if (sys === undefined) {\n issues.push(\n issue(\n 'error',\n 'required',\n 'valueQuantity.system é obrigatório',\n `${path}.valueQuantity.system`,\n ),\n );\n } else if (sys !== SYS_UCUM) {\n issues.push(\n issue(\n 'error',\n 'invalid',\n `valueQuantity.system deve ser ${SYS_UCUM}; recebido \"${String(sys)}\"`,\n `${path}.valueQuantity.system`,\n ),\n );\n }\n }\n\n issues.push(...requireField(get(resource, 'subject'), 'Observation.subject', `${path}.subject`));\n issues.push(\n ...requireField(\n get(resource, 'effectiveDateTime'),\n 'Observation.effectiveDateTime',\n `${path}.effectiveDateTime`,\n ),\n );\n\n return issues;\n}\n\n// ============================================================================\n// BRDiagnosticReport\n// ============================================================================\n\nexport function validateBRDiagnosticReport(resource: unknown, path: string): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n const status = get(resource, 'status');\n issues.push(...requireField(status, 'DiagnosticReport.status', `${path}.status`));\n if (status !== undefined) {\n issues.push(\n ...requireOneOf(status, DIAG_REPORT_STATUS, 'DiagnosticReport.status', `${path}.status`),\n );\n }\n\n const categories = get<unknown[]>(resource, 'category');\n issues.push(\n ...requireMinCardinality(categories, 1, 'DiagnosticReport.category', `${path}.category`),\n );\n if (Array.isArray(categories)) {\n const hasLab = categories.some((cat) => {\n const codings = get<unknown[]>(cat, 'coding');\n return (\n Array.isArray(codings) &&\n codings.some(\n (c) => get<string>(c, 'system') === SYS_V2_0074 && get<string>(c, 'code') === 'LAB',\n )\n );\n });\n if (!hasLab) {\n issues.push(\n issue(\n 'error',\n 'invalid',\n 'DiagnosticReport.category deve incluir { system: v2-0074, code: LAB }',\n `${path}.category`,\n ),\n );\n }\n }\n\n issues.push(...requireField(get(resource, 'code'), 'DiagnosticReport.code', `${path}.code`));\n issues.push(\n ...requireField(get(resource, 'subject'), 'DiagnosticReport.subject', `${path}.subject`),\n );\n issues.push(\n ...requireField(\n get(resource, 'effectiveDateTime'),\n 'DiagnosticReport.effectiveDateTime',\n `${path}.effectiveDateTime`,\n ),\n );\n const results = get<unknown[]>(resource, 'result');\n issues.push(...requireMinCardinality(results, 1, 'DiagnosticReport.result', `${path}.result`));\n const performers = get<unknown[]>(resource, 'performer');\n issues.push(\n ...requireMinCardinality(performers, 1, 'DiagnosticReport.performer', `${path}.performer`),\n );\n\n return issues;\n}\n","/**\n * Validação de Bundles FHIR contra os perfis do IG fhir-brasil.\n *\n * O sandbox roteia cada `Bundle.entry[i].resource` para o validador do\n * perfil correspondente baseado no `meta.profile` declarado OU no\n * `resourceType` quando ausente. Resultado é uma lista plana de\n * `ValidationIssue` com `expression`/`location` no formato FHIR.\n *\n * Não cobre o spec inteiro de FHIR validation — foca no subset que a\n * RNDS rejeita na prática (cardinalidade, identifiers brasileiros,\n * coding LOINC/UCUM, value sets de status).\n */\n\nimport {\n validateBRDiagnosticReport,\n validateBRLabObservation,\n validateBRPatient,\n} from './profiles';\nimport type { ValidationIssue, ValidationResult } from './types';\n\nconst PROFILE_URI = {\n diagnosticReport: 'https://fhir-brasil.dev.br/ig/StructureDefinition/br-diagnostic-report',\n labObservation: 'https://fhir-brasil.dev.br/ig/StructureDefinition/br-lab-observation',\n patient: 'https://fhir-brasil.dev.br/ig/StructureDefinition/br-patient',\n} as const;\n\ninterface ResourceLike {\n meta?: { profile?: string[] };\n resourceType?: string;\n}\n\ninterface BundleLike {\n entry?: Array<{ resource?: ResourceLike }>;\n resourceType?: string;\n}\n\nexport function validateBundle(bundle: unknown, basePath = 'Bundle'): ValidationResult {\n const issues: ValidationIssue[] = [];\n const b = bundle as BundleLike | undefined;\n const entries = b?.entry ?? [];\n\n entries.forEach((entry, index) => {\n const resource = entry?.resource;\n if (!resource) return;\n const entryPath = `${basePath}.entry[${index}].resource`;\n issues.push(...validateResource(resource, entryPath));\n });\n\n return { issues, valid: !issues.some((i) => i.severity === 'error' || i.severity === 'fatal') };\n}\n\nexport function validateResource(resource: ResourceLike, path: string): ValidationIssue[] {\n const declaredProfiles = resource?.meta?.profile ?? [];\n\n // Quando o cliente declara explicitamente um perfil do IG, validamos contra ele.\n if (declaredProfiles.includes(PROFILE_URI.patient)) {\n return validateBRPatient(resource, path);\n }\n if (declaredProfiles.includes(PROFILE_URI.labObservation)) {\n return validateBRLabObservation(resource, path);\n }\n if (declaredProfiles.includes(PROFILE_URI.diagnosticReport)) {\n return validateBRDiagnosticReport(resource, path);\n }\n\n // Sem `meta.profile`, fallback por resourceType para os tipos cobertos.\n switch (resource?.resourceType) {\n case 'Patient':\n return validateBRPatient(resource, path);\n case 'Observation':\n // BRLabObservation só se aplica a observações laboratoriais. Vital-signs,\n // social-history etc. usam outros perfis e seriam rejeitados injustamente\n // se forçados ao perfil BR.\n //\n // Heurística: aplicar BR apenas quando `category.coding` contém o código\n // `laboratory`. Caso contrário (categoria diferente, OU sem categoria\n // alguma — possível em dados legados), o recurso passa sem checagem de\n // perfil. Esse silêncio é deliberado: rejeitar Observations sem\n // category implicaria adivinhar a intenção do cliente.\n //\n // Para garantir conformidade estrita em ambos os casos, declare\n // `meta.profile` apontando para `br-lab-observation`.\n return looksLikeLabObservation(resource) ? validateBRLabObservation(resource, path) : [];\n case 'DiagnosticReport':\n return validateBRDiagnosticReport(resource, path);\n default:\n // Outros tipos passam sem validação de perfil — é responsabilidade do\n // chamador declarar `meta.profile` se quiser conformidade estrita.\n return [];\n }\n}\n\nconst SYS_OBS_CATEGORY = 'http://terminology.hl7.org/CodeSystem/observation-category';\n\nfunction looksLikeLabObservation(resource: unknown): boolean {\n const r = resource as { category?: { coding?: { system?: string; code?: string }[] }[] };\n const cats = r?.category;\n if (!Array.isArray(cats)) return false;\n return cats.some((cat) =>\n (cat?.coding ?? []).some((c) => c?.system === SYS_OBS_CATEGORY && c?.code === 'laboratory'),\n );\n}\n\nexport {\n validateBRDiagnosticReport,\n validateBRLabObservation,\n validateBRPatient,\n} from './profiles';\nexport type { IssueSeverity, ValidationIssue, ValidationResult } from './types';\n","/**\n * Roteador HTTP do sandbox.\n *\n * Mapeia o subset de endpoints da RNDS consumidos por\n * @precisa-saude/fhir-rnds. Aplica autenticação por rota:\n *\n * - /api/token: exige certificado mTLS quando o sandbox roda em modo\n * `--mtls` (RNDS de fato exige nesse endpoint).\n * - /api/fhir/r4/*: em modo `strict`, exige bearer token assinado +\n * header `Authorization: <CNS>` (igual à API real). Em modo\n * permissivo (padrão sem flags), aceita sem auth — útil para\n * curl / aulas sem fricção.\n * - /.well-known/jwks.json: público sempre.\n */\n\nimport { issueToken, verifyToken } from './auth';\nimport { buildJwks } from './jwks';\nimport type { SigningKeys } from './keys';\nimport type { SandboxStore } from './store';\nimport type { SandboxBundle, SandboxBundleEntry } from './types';\nimport { validateBundle } from './validation';\n\nconst FHIR_PREFIX = '/api/fhir/r4';\nconst TOKEN_PATH = '/api/token';\nconst JWKS_PATH = '/.well-known/jwks.json';\n\nconst NS = {\n cns: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cns',\n cpf: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cpf',\n} as const;\n\nexport interface PeerCertInfo {\n /** Common Name (subject.CN) do cert apresentado, se houver */\n cn?: string;\n /** CNES de 7 dígitos extraído do CN (heurística), se encontrado */\n cnes?: string;\n /** True quando o cliente apresentou um certificado válido (qualquer CA) */\n presented: boolean;\n}\n\nexport interface RouteContext {\n body?: unknown;\n /** Cabeçalhos HTTP recebidos (chaves em lowercase) */\n headers: Record<string, string | undefined>;\n keys: SigningKeys;\n method: string;\n path: string;\n /** Informação extraída do certificado mTLS, quando o servidor está em modo mtls */\n peerCert?: PeerCertInfo;\n query: URLSearchParams;\n store: SandboxStore;\n /** Quando true, /api/token requer cert apresentado e FHIR exige bearer + CNS */\n strict: boolean;\n /**\n * Quando true (padrão), `POST /Bundle` valida cada entry contra os perfis\n * BR* do IG fhir-brasil e rejeita com 422 se houver erros. Em modo\n * permissivo (`false`), aceita qualquer Bundle com estrutura mínima.\n */\n validateProfiles: boolean;\n}\n\nexport interface RouteResponse {\n body: unknown;\n status: number;\n}\n\nexport function dispatch(ctx: RouteContext): RouteResponse {\n if (ctx.method === 'GET' && ctx.path === JWKS_PATH) {\n return { body: buildJwks(ctx.keys), status: 200 };\n }\n\n if (ctx.method === 'POST' && ctx.path === TOKEN_PATH) {\n return handleToken(ctx);\n }\n\n if (!ctx.path.startsWith(FHIR_PREFIX)) {\n return notFound(`Recurso não encontrado: ${ctx.path}`);\n }\n\n if (ctx.strict) {\n const authError = enforceFhirAuth(ctx);\n if (authError) {\n return authError;\n }\n }\n\n const fhirPath = ctx.path.slice(FHIR_PREFIX.length);\n\n if (ctx.method === 'GET') {\n return handleFhirGet(fhirPath, ctx);\n }\n if (ctx.method === 'POST' && fhirPath === '/Bundle') {\n return handleSubmitBundle(ctx);\n }\n\n return {\n body: operationOutcome('error', 'not-supported', `${ctx.method} ${ctx.path} não suportado`),\n status: 405,\n };\n}\n\nfunction handleToken(ctx: RouteContext): RouteResponse {\n if (ctx.strict && !ctx.peerCert?.presented) {\n return {\n body: operationOutcome(\n 'error',\n 'security',\n 'Certificado mTLS é obrigatório em /api/token quando o sandbox está em modo --mtls',\n ),\n status: 401,\n };\n }\n const tokenPayload = issueToken(ctx.keys, {\n identity: ctx.peerCert?.presented\n ? { cn: ctx.peerCert.cn, cnes: ctx.peerCert.cnes }\n : undefined,\n });\n return { body: tokenPayload, status: 200 };\n}\n\nfunction enforceFhirAuth(ctx: RouteContext): RouteResponse | null {\n const bearerHeader = ctx.headers['x-authorization-server'];\n if (!bearerHeader) {\n return {\n body: operationOutcome(\n 'error',\n 'security',\n 'header X-Authorization-Server: Bearer <token> é obrigatório',\n ),\n status: 401,\n };\n }\n const match = /^Bearer\\s+(.+)$/i.exec(bearerHeader);\n if (!match) {\n return {\n body: operationOutcome(\n 'error',\n 'security',\n 'X-Authorization-Server deve usar o esquema \"Bearer <token>\"',\n ),\n status: 401,\n };\n }\n const token = match[1]!.trim();\n const verification = verifyToken(token, ctx.keys);\n if (!verification.valid) {\n return {\n body: operationOutcome('error', 'security', `Token inválido (${verification.reason})`),\n status: 401,\n };\n }\n\n const cnsHeader = ctx.headers['authorization'];\n if (!cnsHeader) {\n return {\n body: operationOutcome(\n 'error',\n 'required',\n 'header Authorization: <CNS-do-profissional> é obrigatório',\n ),\n status: 400,\n };\n }\n if (!/^\\d{15}$/.test(cnsHeader.trim())) {\n return {\n body: operationOutcome('error', 'invalid', 'Authorization deve conter um CNS de 15 dígitos'),\n status: 400,\n };\n }\n\n return null;\n}\n\n/**\n * Tipos cuja busca por paciente o sandbox suporta. Cada um aceita\n * `?subject=Patient/{cns}` ou `?patient=Patient/{cns}` (também tolera\n * só o CNS sem prefixo).\n */\nconst SEARCHABLE_BY_PATIENT = new Set([\n 'Observation',\n 'DiagnosticReport',\n 'Immunization',\n 'Condition',\n 'Encounter',\n]);\n\nfunction handleFhirGet(fhirPath: string, ctx: RouteContext): RouteResponse {\n if (fhirPath === '/Patient') {\n return handlePatientSearch(ctx);\n }\n const patientMatch = /^\\/Patient\\/([^/]+)$/.exec(fhirPath);\n if (patientMatch) {\n const cns = decodeURIComponent(patientMatch[1]!);\n const patient = ctx.store.findPatientByCns(cns);\n return patient\n ? { body: patient, status: 200 }\n : notFound(`Paciente CNS ${cns} não encontrado`);\n }\n const orgMatch = /^\\/Organization\\/([^/]+)$/.exec(fhirPath);\n if (orgMatch) {\n const cnes = decodeURIComponent(orgMatch[1]!);\n const org = ctx.store.findOrganizationByCnes(cnes);\n return org ? { body: org, status: 200 } : notFound(`Organização CNES ${cnes} não encontrada`);\n }\n const practMatch = /^\\/Practitioner\\/([^/]+)$/.exec(fhirPath);\n if (practMatch) {\n const cns = decodeURIComponent(practMatch[1]!);\n const pract = ctx.store.findPractitionerByCns(cns);\n return pract\n ? { body: pract, status: 200 }\n : notFound(`Profissional CNS ${cns} não encontrado`);\n }\n const searchMatch = /^\\/([A-Z][A-Za-z]+)$/.exec(fhirPath);\n if (searchMatch) {\n const resourceType = searchMatch[1]!;\n if (SEARCHABLE_BY_PATIENT.has(resourceType)) {\n return handleResourceSearch(resourceType, ctx);\n }\n }\n return notFound(`Recurso FHIR não suportado: ${fhirPath}`);\n}\n\nfunction handleResourceSearch(resourceType: string, ctx: RouteContext): RouteResponse {\n const ref = ctx.query.get('subject') ?? ctx.query.get('patient');\n if (!ref) {\n return {\n body: operationOutcome(\n 'error',\n 'required',\n `${resourceType} search exige ?subject=Patient/{cns} ou ?patient=Patient/{cns}`,\n ),\n status: 400,\n };\n }\n const cns = ref.startsWith('Patient/') ? ref.slice('Patient/'.length) : ref;\n const matches = ctx.store.searchResourcesByPatient(resourceType, cns);\n const entry: SandboxBundleEntry[] = matches.map((resource) => ({ resource }));\n return {\n body: {\n entry,\n resourceType: 'Bundle',\n total: matches.length,\n type: 'searchset',\n },\n status: 200,\n };\n}\n\nfunction handlePatientSearch(ctx: RouteContext): RouteResponse {\n const identifier = ctx.query.get('identifier');\n if (!identifier) {\n return {\n body: operationOutcome('error', 'required', 'parâmetro identifier é obrigatório em /Patient'),\n status: 400,\n };\n }\n const [system, value] = identifier.split('|');\n if (!system || !value) {\n return {\n body: operationOutcome('error', 'invalid', 'identifier deve ser no formato system|value'),\n status: 400,\n };\n }\n\n let patient = undefined;\n if (system === NS.cpf) {\n patient = ctx.store.findPatientByCpf(value);\n } else if (system === NS.cns) {\n patient = ctx.store.findPatientByCns(value);\n } else {\n return notFound(`NamingSystem não suportado: ${system}`);\n }\n\n return patient\n ? { body: patient, status: 200 }\n : notFound(`Paciente ${system}|${value} não encontrado`);\n}\n\nfunction handleSubmitBundle(ctx: RouteContext): RouteResponse {\n if (typeof ctx.body === 'symbol') {\n // sentinela INVALID_BODY de readBody — JSON malformado\n return {\n body: operationOutcome('error', 'structure', 'corpo da requisição não é JSON válido'),\n status: 400,\n };\n }\n const bundle = ctx.body as SandboxBundle | undefined;\n if (!bundle || typeof bundle !== 'object' || bundle.resourceType !== 'Bundle') {\n return {\n body: operationOutcome('error', 'structure', 'corpo da requisição não é um Bundle FHIR'),\n status: 400,\n };\n }\n if (bundle.type !== 'transaction' && bundle.type !== 'batch') {\n return {\n body: operationOutcome(\n 'error',\n 'invalid',\n `Bundle.type \"${String(bundle.type)}\" não suportado — use transaction ou batch`,\n ),\n status: 400,\n };\n }\n\n // Valida cada entry contra os perfis BR* do IG. Erros disparam 422\n // (FHIR-canônico para validation failure) com OperationOutcome\n // multi-issue, igual à RNDS real.\n if (ctx.validateProfiles) {\n const result = validateBundle(bundle);\n if (!result.valid) {\n return {\n body: {\n issue: result.issues.map((i) => ({\n code: i.code,\n diagnostics: i.diagnostics,\n expression: i.expression,\n severity: i.severity,\n })),\n resourceType: 'OperationOutcome',\n },\n status: 422,\n };\n }\n }\n\n ctx.store.recordBundle(bundle);\n\n // As `location`s retornadas são puramente sintéticas — servem só para\n // imitar o formato de transaction-response da RNDS. O sandbox não\n // resolve esses IDs de volta; os recursos submetidos são consultados\n // via `GET /{ResourceType}?subject=Patient/{cns}` (ou similar).\n const responseEntries: SandboxBundleEntry[] = (bundle.entry ?? []).map(() => ({\n response: {\n location: `Resource/sandbox-${ctx.store.nextResourceId()}`,\n status: '201 Created',\n },\n }));\n const response: SandboxBundle = {\n entry: responseEntries,\n resourceType: 'Bundle',\n type: 'transaction-response',\n };\n return { body: response, status: 200 };\n}\n\nfunction notFound(diagnostics: string): RouteResponse {\n return {\n body: operationOutcome('error', 'not-found', diagnostics),\n status: 404,\n };\n}\n\nfunction operationOutcome(\n severity: 'fatal' | 'error' | 'warning' | 'information',\n code: string,\n diagnostics: string,\n): unknown {\n return {\n issue: [{ code, diagnostics, severity }],\n resourceType: 'OperationOutcome',\n };\n}\n","/**\n * Store em memória dos cenários carregados no sandbox.\n *\n * Indexa pacientes por CPF e CNS, organizações por CNES e\n * profissionais por CNS. Bundles submetidos via POST /Bundle\n * são acumulados em memória (acessíveis via getSubmittedBundles).\n */\n\nimport type {\n SandboxBundle,\n SandboxOrganization,\n SandboxPatient,\n SandboxPractitioner,\n SandboxResource,\n Scenario,\n} from './types';\n\nconst NS = {\n cnes: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cnes',\n cns: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cns',\n cpf: 'http://rnds.saude.gov.br/fhir/r4/NamingSystem/cpf',\n} as const;\n\nexport class SandboxStore {\n private patientsByCpf = new Map<string, SandboxPatient>();\n private patientsByCns = new Map<string, SandboxPatient>();\n private organizationsByCnes = new Map<string, SandboxOrganization>();\n private practitionersByCns = new Map<string, SandboxPractitioner>();\n private submittedBundles: SandboxBundle[] = [];\n private resourceSeq = 0;\n\n load(scenario: Scenario): void {\n this.reset();\n for (const patient of scenario.data.patients) {\n this.indexPatient(patient);\n }\n for (const org of scenario.data.organizations) {\n this.indexOrganization(org);\n }\n for (const pract of scenario.data.practitioners) {\n this.indexPractitioner(pract);\n }\n for (const bundle of scenario.data.submittedBundles ?? []) {\n this.submittedBundles.push(bundle);\n }\n }\n\n reset(): void {\n this.patientsByCpf.clear();\n this.patientsByCns.clear();\n this.organizationsByCnes.clear();\n this.practitionersByCns.clear();\n this.submittedBundles = [];\n this.resourceSeq = 0;\n }\n\n /** Próximo número de sequência global para gerar `Resource/sandbox-N`. */\n nextResourceId(): number {\n this.resourceSeq += 1;\n return this.resourceSeq;\n }\n\n findPatientByCpf(cpf: string): SandboxPatient | undefined {\n return this.patientsByCpf.get(stripFormatting(cpf));\n }\n\n findPatientByCns(cns: string): SandboxPatient | undefined {\n return this.patientsByCns.get(stripFormatting(cns));\n }\n\n findOrganizationByCnes(cnes: string): SandboxOrganization | undefined {\n return this.organizationsByCnes.get(stripFormatting(cnes));\n }\n\n findPractitionerByCns(cns: string): SandboxPractitioner | undefined {\n return this.practitionersByCns.get(stripFormatting(cns));\n }\n\n recordBundle(bundle: SandboxBundle): void {\n this.submittedBundles.push(bundle);\n }\n\n getSubmittedBundles(): readonly SandboxBundle[] {\n return this.submittedBundles;\n }\n\n /**\n * Lista todos os recursos de um tipo presentes nos bundles submetidos\n * (incluindo os pré-carregados pelo cenário). Usado pelos endpoints\n * de busca FHIR (`GET /Observation?subject=...`, etc.).\n */\n listResourcesByType(resourceType: string): SandboxResource[] {\n const out: SandboxResource[] = [];\n for (const bundle of this.submittedBundles) {\n for (const entry of bundle.entry ?? []) {\n if (entry.resource && entry.resource.resourceType === resourceType) {\n out.push(entry.resource);\n }\n }\n }\n return out;\n }\n\n /**\n * Filtra recursos cujo `subject.reference` ou `patient.reference`\n * aponta para o paciente indicado (aceita tanto `Patient/{cns}` quanto\n * apenas o CNS sem prefixo).\n */\n searchResourcesByPatient(resourceType: string, patientCns: string): SandboxResource[] {\n const cns = stripFormatting(patientCns);\n return this.listResourcesByType(resourceType).filter((resource) => {\n const subjectRef = resource.subject?.reference;\n const patientRef = resource.patient?.reference;\n return (\n (subjectRef && referenceMatchesCns(subjectRef, cns)) ||\n (patientRef && referenceMatchesCns(patientRef, cns))\n );\n });\n }\n\n private indexPatient(patient: SandboxPatient): void {\n const cns = patient.id ?? findIdentifier(patient.identifier, NS.cns);\n if (cns) {\n this.patientsByCns.set(stripFormatting(cns), patient);\n }\n const cpf = findIdentifier(patient.identifier, NS.cpf);\n if (cpf) {\n this.patientsByCpf.set(stripFormatting(cpf), patient);\n }\n }\n\n private indexOrganization(org: SandboxOrganization): void {\n const cnes = org.id ?? findIdentifier(org.identifier, NS.cnes);\n if (cnes) {\n this.organizationsByCnes.set(stripFormatting(cnes), org);\n }\n }\n\n private indexPractitioner(pract: SandboxPractitioner): void {\n const cns = pract.id ?? findIdentifier(pract.identifier, NS.cns);\n if (cns) {\n this.practitionersByCns.set(stripFormatting(cns), pract);\n }\n }\n}\n\nfunction findIdentifier(\n ids: { system?: string; value?: string }[] | undefined,\n system: string,\n): string | undefined {\n return ids?.find((id) => id.system === system)?.value;\n}\n\nfunction stripFormatting(value: string): string {\n return value.replace(/[^0-9A-Za-z]/g, '');\n}\n\n/**\n * Casa um reference FHIR contra um CNS. Aceita:\n * - `\"700000000000001\"` (CNS puro)\n * - `\"Patient/700000000000001\"` (relative reference)\n * - `\"http://example.com/Patient/700000000000001\"` (absolute URL)\n *\n * Compara o último segmento estritamente para evitar false-match por sufixo\n * (ex.: `Patient/1700000000000001` não deve casar com `700000000000001`).\n */\nfunction referenceMatchesCns(ref: string, cns: string): boolean {\n const lastSegment = ref.includes('/') ? ref.slice(ref.lastIndexOf('/') + 1) : ref;\n return lastSegment === cns;\n}\n"],"mappings":"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","names":["import_node_fs","CPF","CNS","CNS_PROFISSIONAL","CNS","CNS_PROFISSIONAL","import_node_fs","fs","import_node_crypto","SYS_OBS_CATEGORY","NS","https","http","fs","fs"]}
|
package/dist/cli.d.cts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { S as SandboxOptions } from './types-C61Coait.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* CLI: rnds-sandbox start [opções]
|
|
6
|
+
*
|
|
7
|
+
* Sobe um mock local da RNDS para desenvolvimento.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
interface ParsedArgs {
|
|
11
|
+
command?: 'start' | 'help' | 'scenarios';
|
|
12
|
+
errors: string[];
|
|
13
|
+
options: SandboxOptions;
|
|
14
|
+
}
|
|
15
|
+
declare function parseArgs(argv: string[]): ParsedArgs;
|
|
16
|
+
declare function main(argv?: string[]): Promise<number>;
|
|
17
|
+
|
|
18
|
+
export { type ParsedArgs, main, parseArgs };
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { S as SandboxOptions } from './types-C61Coait.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* CLI: rnds-sandbox start [opções]
|
|
6
|
+
*
|
|
7
|
+
* Sobe um mock local da RNDS para desenvolvimento.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
interface ParsedArgs {
|
|
11
|
+
command?: 'start' | 'help' | 'scenarios';
|
|
12
|
+
errors: string[];
|
|
13
|
+
options: SandboxOptions;
|
|
14
|
+
}
|
|
15
|
+
declare function parseArgs(argv: string[]): ParsedArgs;
|
|
16
|
+
declare function main(argv?: string[]): Promise<number>;
|
|
17
|
+
|
|
18
|
+
export { type ParsedArgs, main, parseArgs };
|