@precisa-saude/fhir 0.32.0 → 0.34.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.
Files changed (76) hide show
  1. package/README.md +11 -9
  2. package/dist/biomarkers.cjs +2 -2
  3. package/dist/biomarkers.js +1 -1
  4. package/dist/{chunk-44QMNDOI.cjs → chunk-376KM7IL.cjs} +18 -11
  5. package/dist/chunk-376KM7IL.cjs.map +1 -0
  6. package/dist/{chunk-WDDW2WCY.js → chunk-4FKZG5GZ.js} +116 -25
  7. package/dist/chunk-4FKZG5GZ.js.map +1 -0
  8. package/dist/{chunk-AZTZYOAV.cjs → chunk-5RC7C7HJ.cjs} +199 -57
  9. package/dist/chunk-5RC7C7HJ.cjs.map +1 -0
  10. package/dist/{chunk-N3ZCOLG2.js → chunk-E6MXDQXW.js} +19 -1
  11. package/dist/chunk-E6MXDQXW.js.map +1 -0
  12. package/dist/{chunk-MNUQ57JR.js → chunk-K3VZ3F5Z.js} +21 -21
  13. package/dist/chunk-K3VZ3F5Z.js.map +1 -0
  14. package/dist/{chunk-4Y43MQQK.js → chunk-NJM45WAH.js} +10 -3
  15. package/dist/chunk-NJM45WAH.js.map +1 -0
  16. package/dist/{chunk-OTVCOSCK.cjs → chunk-NKDUVSDK.cjs} +21 -21
  17. package/dist/chunk-NKDUVSDK.cjs.map +1 -0
  18. package/dist/{chunk-3ILBFLVQ.cjs → chunk-OAFAERDY.cjs} +20 -2
  19. package/dist/chunk-OAFAERDY.cjs.map +1 -0
  20. package/dist/{chunk-PLR54334.js → chunk-P4G534AQ.js} +445 -61
  21. package/dist/chunk-P4G534AQ.js.map +1 -0
  22. package/dist/{chunk-3XIMPALK.js → chunk-Q3H5C6UR.js} +198 -56
  23. package/dist/chunk-Q3H5C6UR.js.map +1 -0
  24. package/dist/{chunk-MKH4Q735.cjs → chunk-T75NZM56.cjs} +116 -25
  25. package/dist/chunk-T75NZM56.cjs.map +1 -0
  26. package/dist/{chunk-555WKD6J.cjs → chunk-VKLWTTUO.cjs} +447 -63
  27. package/dist/chunk-VKLWTTUO.cjs.map +1 -0
  28. package/dist/cli.js +1547 -933
  29. package/dist/{converter-D1Q84Oc9.d.ts → converter-DP8VkkO3.d.cts} +9 -1
  30. package/dist/{converter-DZH9x52r.d.cts → converter-UygMzWlL.d.ts} +9 -1
  31. package/dist/converter.cjs +5 -4
  32. package/dist/converter.cjs.map +1 -1
  33. package/dist/converter.d.cts +3 -2
  34. package/dist/converter.d.ts +3 -2
  35. package/dist/converter.js +4 -3
  36. package/dist/{fhir-types-B1KQmlRb.d.ts → fhir-types-Cn5WFbOI.d.cts} +5 -0
  37. package/dist/{fhir-types-B1KQmlRb.d.cts → fhir-types-Cn5WFbOI.d.ts} +5 -0
  38. package/dist/importer.cjs +5 -4
  39. package/dist/importer.cjs.map +1 -1
  40. package/dist/importer.d.cts +3 -1
  41. package/dist/importer.d.ts +3 -1
  42. package/dist/importer.js +4 -3
  43. package/dist/index.cjs +19 -11
  44. package/dist/index.cjs.map +1 -1
  45. package/dist/index.d.cts +6 -6
  46. package/dist/index.d.ts +6 -6
  47. package/dist/index.js +34 -26
  48. package/dist/index.js.map +1 -1
  49. package/dist/reference-ranges.cjs +8 -3
  50. package/dist/reference-ranges.cjs.map +1 -1
  51. package/dist/reference-ranges.d.cts +83 -1
  52. package/dist/reference-ranges.d.ts +83 -1
  53. package/dist/reference-ranges.js +9 -4
  54. package/dist/units.cjs +7 -2
  55. package/dist/units.cjs.map +1 -1
  56. package/dist/units.d.cts +53 -5
  57. package/dist/units.d.ts +53 -5
  58. package/dist/units.js +6 -1
  59. package/dist/validators.cjs +4 -2
  60. package/dist/validators.cjs.map +1 -1
  61. package/dist/validators.d.cts +1 -1
  62. package/dist/validators.d.ts +1 -1
  63. package/dist/validators.js +3 -1
  64. package/package.json +1 -1
  65. package/dist/chunk-3ILBFLVQ.cjs.map +0 -1
  66. package/dist/chunk-3XIMPALK.js.map +0 -1
  67. package/dist/chunk-44QMNDOI.cjs.map +0 -1
  68. package/dist/chunk-4Y43MQQK.js.map +0 -1
  69. package/dist/chunk-555WKD6J.cjs.map +0 -1
  70. package/dist/chunk-AZTZYOAV.cjs.map +0 -1
  71. package/dist/chunk-MKH4Q735.cjs.map +0 -1
  72. package/dist/chunk-MNUQ57JR.js.map +0 -1
  73. package/dist/chunk-N3ZCOLG2.js.map +0 -1
  74. package/dist/chunk-OTVCOSCK.cjs.map +0 -1
  75. package/dist/chunk-PLR54334.js.map +0 -1
  76. package/dist/chunk-WDDW2WCY.js.map +0 -1
package/README.md CHANGED
@@ -82,15 +82,15 @@ import { validateFHIRObservation } from '@precisa-saude/fhir/validators';
82
82
 
83
83
  ## Módulos
84
84
 
85
- | Sub-path | Descrição |
86
- | ------------------- | ---------------------------------------------------------------------- |
87
- | `/biomarkers` | Definições com códigos LOINC, nomes pt/en, sub-categorias |
88
- | `/category-groups` | Agrupamento de 10 categorias clínicas top-level sobre 20 subcategorias |
89
- | `/reference-ranges` | Faixas de referência por sexo/idade/gestação (SBPC/ML, SBC, SBD, OMS) |
90
- | `/converter` | Converte dados laboratoriais para FHIR R4 Bundle |
91
- | `/importer` | Importa FHIR Bundle de volta para estruturas internas |
92
- | `/units` | Mapeamento de unidades, conversão para UCUM |
93
- | `/validators` | Validação de recursos FHIR (DiagnosticReport, Observation, Bundle) |
85
+ | Sub-path | Descrição |
86
+ | ------------------- | ------------------------------------------------------------------------- |
87
+ | `/biomarkers` | Definições com códigos LOINC, nomes pt/en, sub-categorias |
88
+ | `/category-groups` | Agrupamento de 10 categorias clínicas top-level sobre 20 subcategorias |
89
+ | `/reference-ranges` | Faixas de referência por sexo/idade/gestação (SBPC/ML, SBC, SBD, OMS) |
90
+ | `/converter` | Converte dados laboratoriais para FHIR R4 Bundle |
91
+ | `/importer` | Importa FHIR Bundle de volta para estruturas internas |
92
+ | `/units` | Mapeamento de unidades, conversão para UCUM (`resolveUcum`, `isUcumCode`) |
93
+ | `/validators` | Validação de recursos FHIR (DiagnosticReport, Observation, Bundle) |
94
94
 
95
95
  ## Escopo das faixas de referência
96
96
 
@@ -107,6 +107,8 @@ const range = getReferenceRange('TSH', {
107
107
  // → { max: 2.5, min: 0.1, ... } (alvo ATA 2017 para 1º trimestre)
108
108
  ```
109
109
 
110
+ Cada faixa diz que tipo de afirmação ela é (`kind`: intervalo de referência do ensaio, limiar de decisão de diretriz ou distribuição populacional) e, por limite, se ele é corte clínico ou só desenho (`minKind`/`maxKind`). Para sinalizar um valor contra a faixa do catálogo, use `flagAgainstCatalogRange`, que ignora os limites de desenho; o `direction` diz para que lado o marcador melhora e não decide flag. Detalhes em [docs/biomarcadores.md](../../docs/biomarcadores.md#tipo-da-faixa).
111
+
110
112
  O metadado opcional `fastingRequired` em `BiomarkerReferenceRange` indica se a amostra exige jejum estrito (ex.: `Glucose`, `Insulin`, `HOMA_IR`) ou se o jejum é preferido mas não obrigatório (ex.: `Triglycerides`, que aceita dosagem não-jejum por SBC 2017/2025).
111
113
 
112
114
  ## Aviso médico
@@ -30,7 +30,7 @@
30
30
 
31
31
 
32
32
 
33
- var _chunkMKH4Q735cjs = require('./chunk-MKH4Q735.cjs');
33
+ var _chunkT75NZM56cjs = require('./chunk-T75NZM56.cjs');
34
34
 
35
35
 
36
36
 
@@ -63,5 +63,5 @@ var _chunkMKH4Q735cjs = require('./chunk-MKH4Q735.cjs');
63
63
 
64
64
 
65
65
 
66
- exports.BIOMARKER_DEFINITIONS = _chunkMKH4Q735cjs.BIOMARKER_DEFINITIONS; exports.CAC_INDICATOR_CODES = _chunkMKH4Q735cjs.CAC_INDICATOR_CODES; exports.DEXA_CATEGORIES = _chunkMKH4Q735cjs.DEXA_CATEGORIES; exports.DEXA_INDICATOR_CODES = _chunkMKH4Q735cjs.DEXA_INDICATOR_CODES; exports.codeToLoinc = _chunkMKH4Q735cjs.codeToLoinc; exports.filterVisibleBiomarkers = _chunkMKH4Q735cjs.filterVisibleBiomarkers; exports.findCodeByName = _chunkMKH4Q735cjs.findCodeByName; exports.generateCacFullReference = _chunkMKH4Q735cjs.generateCacFullReference; exports.generateDexaFullReference = _chunkMKH4Q735cjs.generateDexaFullReference; exports.generateFilteredLLMReference = _chunkMKH4Q735cjs.generateFilteredLLMReference; exports.generateLLMReference = _chunkMKH4Q735cjs.generateLLMReference; exports.getAllCodes = _chunkMKH4Q735cjs.getAllCodes; exports.getAllDefinitions = _chunkMKH4Q735cjs.getAllDefinitions; exports.getAllLoincCodes = _chunkMKH4Q735cjs.getAllLoincCodes; exports.getAllSearchPatterns = _chunkMKH4Q735cjs.getAllSearchPatterns; exports.getBiomarkersByCategory = _chunkMKH4Q735cjs.getBiomarkersByCategory; exports.getBiomarkersForCategories = _chunkMKH4Q735cjs.getBiomarkersForCategories; exports.getDefinitionByCode = _chunkMKH4Q735cjs.getDefinitionByCode; exports.getDefinitionByLoinc = _chunkMKH4Q735cjs.getDefinitionByLoinc; exports.getDefinitionsBySex = _chunkMKH4Q735cjs.getDefinitionsBySex; exports.getSexForCode = _chunkMKH4Q735cjs.getSexForCode; exports.getVisibleDefinitions = _chunkMKH4Q735cjs.getVisibleDefinitions; exports.isBiomarkerVisible = _chunkMKH4Q735cjs.isBiomarkerVisible; exports.isCacDocument = _chunkMKH4Q735cjs.isCacDocument; exports.isDexaDocument = _chunkMKH4Q735cjs.isDexaDocument; exports.isValidCode = _chunkMKH4Q735cjs.isValidCode; exports.isValidLoinc = _chunkMKH4Q735cjs.isValidLoinc; exports.loincToCode = _chunkMKH4Q735cjs.loincToCode; exports.normalizeCode = _chunkMKH4Q735cjs.normalizeCode; exports.toBiomarkerTests = _chunkMKH4Q735cjs.toBiomarkerTests; exports.validateLoincNameMatch = _chunkMKH4Q735cjs.validateLoincNameMatch;
66
+ exports.BIOMARKER_DEFINITIONS = _chunkT75NZM56cjs.BIOMARKER_DEFINITIONS; exports.CAC_INDICATOR_CODES = _chunkT75NZM56cjs.CAC_INDICATOR_CODES; exports.DEXA_CATEGORIES = _chunkT75NZM56cjs.DEXA_CATEGORIES; exports.DEXA_INDICATOR_CODES = _chunkT75NZM56cjs.DEXA_INDICATOR_CODES; exports.codeToLoinc = _chunkT75NZM56cjs.codeToLoinc; exports.filterVisibleBiomarkers = _chunkT75NZM56cjs.filterVisibleBiomarkers; exports.findCodeByName = _chunkT75NZM56cjs.findCodeByName; exports.generateCacFullReference = _chunkT75NZM56cjs.generateCacFullReference; exports.generateDexaFullReference = _chunkT75NZM56cjs.generateDexaFullReference; exports.generateFilteredLLMReference = _chunkT75NZM56cjs.generateFilteredLLMReference; exports.generateLLMReference = _chunkT75NZM56cjs.generateLLMReference; exports.getAllCodes = _chunkT75NZM56cjs.getAllCodes; exports.getAllDefinitions = _chunkT75NZM56cjs.getAllDefinitions; exports.getAllLoincCodes = _chunkT75NZM56cjs.getAllLoincCodes; exports.getAllSearchPatterns = _chunkT75NZM56cjs.getAllSearchPatterns; exports.getBiomarkersByCategory = _chunkT75NZM56cjs.getBiomarkersByCategory; exports.getBiomarkersForCategories = _chunkT75NZM56cjs.getBiomarkersForCategories; exports.getDefinitionByCode = _chunkT75NZM56cjs.getDefinitionByCode; exports.getDefinitionByLoinc = _chunkT75NZM56cjs.getDefinitionByLoinc; exports.getDefinitionsBySex = _chunkT75NZM56cjs.getDefinitionsBySex; exports.getSexForCode = _chunkT75NZM56cjs.getSexForCode; exports.getVisibleDefinitions = _chunkT75NZM56cjs.getVisibleDefinitions; exports.isBiomarkerVisible = _chunkT75NZM56cjs.isBiomarkerVisible; exports.isCacDocument = _chunkT75NZM56cjs.isCacDocument; exports.isDexaDocument = _chunkT75NZM56cjs.isDexaDocument; exports.isValidCode = _chunkT75NZM56cjs.isValidCode; exports.isValidLoinc = _chunkT75NZM56cjs.isValidLoinc; exports.loincToCode = _chunkT75NZM56cjs.loincToCode; exports.normalizeCode = _chunkT75NZM56cjs.normalizeCode; exports.toBiomarkerTests = _chunkT75NZM56cjs.toBiomarkerTests; exports.validateLoincNameMatch = _chunkT75NZM56cjs.validateLoincNameMatch;
67
67
  //# sourceMappingURL=biomarkers.cjs.map
@@ -30,7 +30,7 @@ import {
30
30
  normalizeCode,
31
31
  toBiomarkerTests,
32
32
  validateLoincNameMatch
33
- } from "./chunk-WDDW2WCY.js";
33
+ } from "./chunk-4FKZG5GZ.js";
34
34
  export {
35
35
  BIOMARKER_DEFINITIONS,
36
36
  CAC_INDICATOR_CODES,
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
- var _chunk3ILBFLVQcjs = require('./chunk-3ILBFLVQ.cjs');
3
+ var _chunkOAFAERDYcjs = require('./chunk-OAFAERDY.cjs');
4
4
 
5
5
 
6
6
 
@@ -11,7 +11,7 @@ var _chunkOR67NJDZcjs = require('./chunk-OR67NJDZ.cjs');
11
11
 
12
12
 
13
13
 
14
- var _chunkMKH4Q735cjs = require('./chunk-MKH4Q735.cjs');
14
+ var _chunkT75NZM56cjs = require('./chunk-T75NZM56.cjs');
15
15
 
16
16
  // src/importer.ts
17
17
  var MAX_OBSERVATIONS = 5e3;
@@ -33,11 +33,11 @@ function resolveBiomarkerCode(observation) {
33
33
  } else {
34
34
  reason = "No code found in observation coding";
35
35
  }
36
- const fromLoinc = loincCode ? _chunkMKH4Q735cjs.loincToCode.call(void 0, loincCode) : void 0;
36
+ const fromLoinc = loincCode ? _chunkT75NZM56cjs.loincToCode.call(void 0, loincCode) : void 0;
37
37
  if (fromLoinc) return { internalCode: fromLoinc, loincCode, reason };
38
- if (declaredCode && _chunkMKH4Q735cjs.isValidCode.call(void 0, declaredCode)) {
39
- const canonical = _chunkMKH4Q735cjs.normalizeCode.call(void 0, declaredCode);
40
- return { internalCode: canonical, loincCode: _chunkMKH4Q735cjs.codeToLoinc.call(void 0, canonical), reason };
38
+ if (declaredCode && _chunkT75NZM56cjs.isValidCode.call(void 0, declaredCode)) {
39
+ const canonical = _chunkT75NZM56cjs.normalizeCode.call(void 0, declaredCode);
40
+ return { internalCode: canonical, loincCode: _chunkT75NZM56cjs.codeToLoinc.call(void 0, canonical), reason };
41
41
  }
42
42
  return { loincCode, reason };
43
43
  }
@@ -74,7 +74,7 @@ function mapFHIRObservationToInternal(observation, index) {
74
74
  skipped: { index, loincCode, reason, resourceType: "Observation" }
75
75
  };
76
76
  }
77
- const definition = _chunkMKH4Q735cjs.getDefinitionByCode.call(void 0, internalCode);
77
+ const definition = _chunkT75NZM56cjs.getDefinitionByCode.call(void 0, internalCode);
78
78
  let value;
79
79
  let unit = "";
80
80
  let isQualitative = false;
@@ -107,26 +107,33 @@ function mapFHIRObservationToInternal(observation, index) {
107
107
  }
108
108
  let referenceMin;
109
109
  let referenceMax;
110
+ let referenceKind;
110
111
  if (_optionalChain([observation, 'access', _18 => _18.referenceRange, 'optionalAccess', _19 => _19[0]])) {
111
112
  referenceMin = _optionalChain([observation, 'access', _20 => _20.referenceRange, 'access', _21 => _21[0], 'access', _22 => _22.low, 'optionalAccess', _23 => _23.value]);
112
113
  referenceMax = _optionalChain([observation, 'access', _24 => _24.referenceRange, 'access', _25 => _25[0], 'access', _26 => _26.high, 'optionalAccess', _27 => _27.value]);
114
+ const meaning = _optionalChain([observation, 'access', _28 => _28.referenceRange, 'access', _29 => _29[0], 'access', _30 => _30.type, 'optionalAccess', _31 => _31.coding, 'optionalAccess', _32 => _32.find, 'call', _33 => _33(
115
+ (c) => c.system === "http://terminology.hl7.org/CodeSystem/referencerange-meaning"
116
+ ), 'optionalAccess', _34 => _34.code]);
117
+ if (meaning === "normal") referenceKind = "reference-interval";
118
+ else if (meaning === "recommended") referenceKind = "decision-threshold";
113
119
  }
114
120
  const imported = {
115
121
  biomarkerCode: internalCode,
116
- biomarkerName: _optionalChain([definition, 'optionalAccess', _28 => _28.names, 'access', _29 => _29.pt, 'access', _30 => _30[0]]) || _optionalChain([definition, 'optionalAccess', _31 => _31.names, 'access', _32 => _32.en, 'access', _33 => _33[0]]) || observation.code.text || internalCode,
122
+ biomarkerName: _optionalChain([definition, 'optionalAccess', _35 => _35.names, 'access', _36 => _36.pt, 'access', _37 => _37[0]]) || _optionalChain([definition, 'optionalAccess', _38 => _38.names, 'access', _39 => _39.en, 'access', _40 => _40[0]]) || observation.code.text || internalCode,
117
123
  collectionDate,
118
124
  flag: extractFlag(observation),
119
125
  isQualitative,
120
126
  loincCode,
127
+ ...referenceKind && { referenceKind },
121
128
  referenceMax,
122
129
  referenceMin,
123
- unit: unit || _optionalChain([definition, 'optionalAccess', _34 => _34.unit]) || "",
130
+ unit: unit || _optionalChain([definition, 'optionalAccess', _41 => _41.unit]) || "",
124
131
  value
125
132
  };
126
133
  return { observation: imported };
127
134
  }
128
135
  function processImportBundle(data) {
129
- const validationErrors = _chunk3ILBFLVQcjs.validateFHIRImportBundle.call(void 0, data);
136
+ const validationErrors = _chunkOAFAERDYcjs.validateFHIRImportBundle.call(void 0, data);
130
137
  if (validationErrors.length > 0) {
131
138
  return {
132
139
  errors: validationErrors,
@@ -162,4 +169,4 @@ function processImportBundle(data) {
162
169
 
163
170
 
164
171
  exports.MAX_OBSERVATIONS = MAX_OBSERVATIONS; exports.MAX_FILE_SIZE = MAX_FILE_SIZE; exports.extractObservationsFromBundle = extractObservationsFromBundle; exports.mapFHIRObservationToInternal = mapFHIRObservationToInternal; exports.processImportBundle = processImportBundle;
165
- //# sourceMappingURL=chunk-44QMNDOI.cjs.map
172
+ //# sourceMappingURL=chunk-376KM7IL.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/fhir-brasil/fhir-brasil/packages/core/dist/chunk-376KM7IL.cjs","../src/importer.ts"],"names":[],"mappings":"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","file":"/home/runner/work/fhir-brasil/fhir-brasil/packages/core/dist/chunk-376KM7IL.cjs","sourcesContent":[null,"/**\n * FHIR Importer\n *\n * Parses FHIR R4 Bundles and extracts Observation resources with known LOINC codes,\n * mapping them to internal biomarker codes for storage as lab results.\n */\n\nimport {\n codeToLoinc,\n getDefinitionByCode,\n isValidCode,\n loincToCode,\n normalizeCode,\n} from './biomarkers';\nimport { BIOMARKER_CODE_SYSTEM, LOINC_SYSTEM } from './code-systems';\nimport type { FHIRBundle, FHIRObservation } from './fhir-types';\nimport { validateFHIRImportBundle } from './validators';\n\nexport interface ImportedObservation {\n biomarkerCode: string;\n biomarkerName: string;\n collectionDate: string;\n flag: 'H' | 'L' | '';\n isQualitative: boolean;\n /** Ausente nos biomarcadores sem LOINC publicado, como composição corporal. */\n loincCode?: string;\n /** Lido do `referenceRange.type`, quando o Bundle o traz. */\n referenceKind?: 'decision-threshold' | 'reference-interval';\n referenceMax?: number;\n referenceMin?: number;\n unit: string;\n value: number | string;\n}\n\nexport interface SkippedEntry {\n index: number;\n loincCode?: string;\n reason: string;\n resourceType?: string;\n}\n\nexport interface ImportError {\n details: string;\n field: string;\n}\n\nexport interface FHIRImportResult {\n errors: ImportError[];\n imported: ImportedObservation[];\n skipped: SkippedEntry[];\n totalProcessed: number;\n}\n\n/**\n * Limites de importação.\n *\n * Uma Observation exportada ocupa cerca de 1,25KB em JSON compacto e 2,75KB\n * quando o arquivo vem indentado, medido sobre um histórico real de 998\n * Observations em 61 laudos. Nesse tamanho, 5000 Observations dão 6,0MB\n * compactos ou 13,1MB indentados, e por isso o teto de arquivo é 15MB: cobre\n * as duas formas com folga.\n *\n * Na densidade desse mesmo histórico (16 Observations por laudo), 5000\n * equivalem a cerca de 300 laudos.\n */\nconst MAX_OBSERVATIONS = 5000;\nconst MAX_FILE_SIZE = 15 * 1024 * 1024; // 15MB\n\n/**\n * Resolve o código interno do biomarcador a partir do `code.coding`.\n *\n * LOINC primeiro, que é o vocabulário que arquivos de terceiros usam. Quando\n * não resolve, cai para o coding de códigos internos, presente nos arquivos\n * exportados pela própria plataforma.\n *\n * O fallback cobre dois casos: biomarcadores sem LOINC publicado (composição\n * corporal, densidade óssea, escore de cálcio) e arquivos antigos, exportados\n * quando esses biomarcadores saíam com o placeholder `99999-9`, que não\n * resolve para nada.\n */\nfunction resolveBiomarkerCode(observation: FHIRObservation): {\n internalCode?: string;\n loincCode?: string;\n reason: string;\n} {\n const coding = observation.code?.coding ?? [];\n const loincCode = coding.find((c) => c.system === LOINC_SYSTEM)?.code;\n const declaredCode = coding.find((c) => c.system === BIOMARKER_CODE_SYSTEM)?.code;\n\n const seenCodes = [\n ...(loincCode ? [`LOINC ${loincCode}`] : []),\n ...(declaredCode ? [`biomarker code ${declaredCode}`] : []),\n ];\n\n // Três motivos distintos de descarte, que antes se confundiam num só. Sem\n // essa separação, um arquivo em SNOMED relatava \"nenhum código encontrado\",\n // sugerindo `coding` vazio quando na verdade o código existia e estava num\n // system que não tratamos. Para importação de terceiros, é a diferença entre\n // um diagnóstico acionável e um enigma.\n let reason: string;\n if (seenCodes.length > 0) {\n reason = `Unknown code: ${seenCodes.join(', ')}`;\n } else if (coding.length > 0) {\n const systems = [...new Set(coding.map((c) => c.system ?? '(sem system)'))];\n reason = `No code in a supported system (found: ${systems.join(', ')})`;\n } else {\n reason = 'No code found in observation coding';\n }\n\n const fromLoinc = loincCode ? loincToCode(loincCode) : undefined;\n if (fromLoinc) return { internalCode: fromLoinc, loincCode, reason };\n\n if (declaredCode && isValidCode(declaredCode)) {\n // `isValidCode` aceita alias, mas alias não serve como código armazenado:\n // 49 definições têm um, e tanto `codeToLoinc` quanto as faixas de\n // referência são indexadas só pelo canônico. Sem normalizar, `VLDL_Cholesterol`\n // entraria no lugar de `VLDL` e perderia o LOINC 13458-5 que ele tem.\n // Importar um Bundle é fronteira de dados, que é onde `normalizeCode` deve\n // ser aplicado.\n const canonical = normalizeCode(declaredCode);\n\n // `codeToLoinc` devolve undefined para quem não tem LOINC, que é o caso\n // esperado aqui. O campo fica de fora em vez de receber um valor inventado.\n return { internalCode: canonical, loincCode: codeToLoinc(canonical), reason };\n }\n\n return { loincCode, reason };\n}\n\n/**\n * Extract interpretation flag from Observation\n */\nfunction extractFlag(observation: FHIRObservation): 'H' | 'L' | '' {\n const code = observation.interpretation?.[0]?.coding?.[0]?.code;\n if (code === 'H' || code === 'HH') return 'H';\n if (code === 'L' || code === 'LL') return 'L';\n return '';\n}\n\n/**\n * Extract Observation resources from a FHIR Bundle\n */\nexport function extractObservationsFromBundle(bundle: FHIRBundle): {\n observations: FHIRObservation[];\n skipped: SkippedEntry[];\n} {\n const observations: FHIRObservation[] = [];\n const skipped: SkippedEntry[] = [];\n\n for (let i = 0; i < bundle.entry.length; i++) {\n const entry = bundle.entry[i]!;\n if (!entry.resource) {\n skipped.push({ index: i, reason: 'Entry has no resource' });\n continue;\n }\n\n if (entry.resource.resourceType !== 'Observation') {\n // Non-observation resources are silently skipped (Patient, DiagnosticReport, etc.)\n continue;\n }\n\n if (observations.length >= MAX_OBSERVATIONS) {\n skipped.push({ index: i, reason: `Maximum of ${MAX_OBSERVATIONS} observations exceeded` });\n continue;\n }\n\n observations.push(entry.resource as FHIRObservation);\n }\n\n return { observations, skipped };\n}\n\n/**\n * Map a FHIR Observation to internal format using LOINC→biomarker code lookup\n */\nexport function mapFHIRObservationToInternal(\n observation: FHIRObservation,\n index: number,\n): { observation: ImportedObservation } | { skipped: SkippedEntry } {\n const { internalCode, loincCode, reason } = resolveBiomarkerCode(observation);\n\n if (!internalCode) {\n return {\n skipped: { index, loincCode, reason, resourceType: 'Observation' },\n };\n }\n\n const definition = getDefinitionByCode(internalCode);\n\n // Extract value\n let value: number | string;\n let unit = '';\n let isQualitative = false;\n\n if (observation.valueQuantity?.value !== undefined) {\n value = observation.valueQuantity.value;\n unit = observation.valueQuantity.unit || observation.valueQuantity.code || '';\n } else if (observation.valueString) {\n value = observation.valueString;\n isQualitative = true;\n } else {\n return {\n skipped: {\n index,\n loincCode,\n reason: 'Observation has no value (valueQuantity or valueString)',\n resourceType: 'Observation',\n },\n };\n }\n\n // Extract collection date (effectiveDateTime or effectivePeriod.start)\n const collectionDate = observation.effectiveDateTime || observation.effectivePeriod?.start || '';\n if (!collectionDate) {\n return {\n skipped: {\n index,\n loincCode,\n reason: 'Observation has no effectiveDateTime or effectivePeriod.start',\n resourceType: 'Observation',\n },\n };\n }\n\n // Extract reference ranges\n let referenceMin: number | undefined;\n let referenceMax: number | undefined;\n let referenceKind: ImportedObservation['referenceKind'];\n if (observation.referenceRange?.[0]) {\n referenceMin = observation.referenceRange[0].low?.value;\n referenceMax = observation.referenceRange[0].high?.value;\n const meaning = observation.referenceRange[0].type?.coding?.find(\n (c) => c.system === 'http://terminology.hl7.org/CodeSystem/referencerange-meaning',\n )?.code;\n if (meaning === 'normal') referenceKind = 'reference-interval';\n else if (meaning === 'recommended') referenceKind = 'decision-threshold';\n }\n\n const imported: ImportedObservation = {\n biomarkerCode: internalCode,\n biomarkerName:\n definition?.names.pt[0] || definition?.names.en[0] || observation.code.text || internalCode,\n collectionDate,\n flag: extractFlag(observation),\n isQualitative,\n loincCode,\n ...(referenceKind && { referenceKind }),\n referenceMax,\n referenceMin,\n unit: unit || definition?.unit || '',\n value,\n };\n\n return { observation: imported };\n}\n\n/**\n * Process a complete FHIR Bundle for import\n */\nexport function processImportBundle(data: unknown): FHIRImportResult {\n // Structural validation\n const validationErrors = validateFHIRImportBundle(data);\n if (validationErrors.length > 0) {\n return {\n errors: validationErrors,\n imported: [],\n skipped: [],\n totalProcessed: 0,\n };\n }\n\n const bundle = data as FHIRBundle;\n\n // Extract observations\n const { observations, skipped } = extractObservationsFromBundle(bundle);\n\n // Map each observation to internal format\n const imported: ImportedObservation[] = [];\n const allSkipped: SkippedEntry[] = [...skipped];\n\n for (let i = 0; i < observations.length; i++) {\n const result = mapFHIRObservationToInternal(observations[i]!, i);\n\n if ('observation' in result) {\n imported.push(result.observation);\n } else {\n allSkipped.push(result.skipped);\n }\n }\n\n return {\n errors: [],\n imported,\n skipped: allSkipped,\n totalProcessed: observations.length,\n };\n}\n\nexport { MAX_FILE_SIZE, MAX_OBSERVATIONS };\n"]}
@@ -56,6 +56,10 @@ var BIOMARKER_DEFINITIONS = [
56
56
  {
57
57
  category: "coracao",
58
58
  code: "LDL_Medium",
59
+ // 96735-6 é "in Serum" só, enquanto as vizinhas LDL_Small (43727-7),
60
+ // LDL_ParticleNumber (54434-6) e HDL_Large (43729-3) são Ser/Plas. É o
61
+ // único código para a subfração média, e o perfil por RMN roda em soro.
62
+ // Material registrado de propósito.
59
63
  loinc: "96735-6",
60
64
  names: {
61
65
  en: ["LDL Medium", "Medium LDL Particles"],
@@ -1023,14 +1027,16 @@ var BIOMARKER_DEFINITIONS = [
1023
1027
  },
1024
1028
  {
1025
1029
  // LOINC 99620-7 = "Omega 3 fatty acids (w3) [Moles/volume] in RBC.lysate".
1026
- // Alinha à matriz das entradas irmãs Omega3_EPA (75097-6) e Omega3_DHA
1027
- // (75095-0), ambas em hemácias. Anteriormente 35178-3 (mesmo analito em
1028
- // Ser/Plas), incompatível com o uso clínico do Índice Ômega-3 (Harris &
1029
- // von Schacky 2004), que é definido em membranas de hemácias.
1030
- // Ressalva: LOINC declara moles/volume; o biomarcador armazena %.
1031
- // Não há LOINC vigente para "Omega 3 total em % em RBC" — o `Omega3_Index`
1032
- // (88998-0) cobre apenas EPA+DHA. Mantemos `unit: '%'` por consistência
1033
- // com EPA/DHA (75095-0/75097-6 são [Entitic substance], também não-%).
1030
+ // Anteriormente 35178-3 (mesmo analito em Ser/Plas), incompatível com o
1031
+ // uso clínico do Índice Ômega-3 (Harris & von Schacky 2004), que é
1032
+ // definido em membranas de hemácias.
1033
+ //
1034
+ // Compromisso declarado, e não erro: o LOINC 2.82 não tem código de fração
1035
+ // ("ômega-3 total / ácidos graxos totais") para o total, só para os ácidos
1036
+ // individuais e para EPA+DPA+DHA (90911-9). O componente confere; a
1037
+ // propriedade é moles/volume enquanto o laudo imprime %. O teste de eixos
1038
+ // (`loinc-axes.test.ts`) lista esta entrada como exceção com este motivo.
1039
+ // Mesmo compromisso em `Omega6_Total` (99621-5).
1034
1040
  category: "nutrientes",
1035
1041
  code: "Omega3_Total",
1036
1042
  loinc: "99620-7",
@@ -1044,7 +1050,18 @@ var BIOMARKER_DEFINITIONS = [
1044
1050
  category: "nutrientes",
1045
1051
  code: "Omega3_DHA",
1046
1052
  codeAliases: ["DHA"],
1047
- loinc: "75095-0",
1053
+ // Ácidos graxos individuais: fração do total (% dos ácidos graxos C14-C22),
1054
+ // que é o que o perfil de ácidos graxos e o Índice Ômega-3 imprimem. Os
1055
+ // códigos vêm do painel 90918-4 ("Fatty acid omega-3 and omega-6 panel -
1056
+ // Blood"), o mesmo de onde já saem as razões AA/EPA (90909-3) e ω6/ω3
1057
+ // (90910-1). Até out/2026 apontavam para os códigos [Entitic substance]
1058
+ // em hemácias (75095-0, 75097-6, 75110-7, 75117-2), que são quantidade por
1059
+ // célula, e para 48371-9, que é moles/volume em soro: componente certo,
1060
+ // propriedade errada nos cinco, desde mar/2026. Ficam como alias porque o
1061
+ // analito é o mesmo. Material: o painel em soro/plasma (88884-2, C14-C24)
1062
+ // existe, e é a troca a fazer se um laboratório imprimir o perfil em soro.
1063
+ loinc: "90914-3",
1064
+ loincAliases: ["75095-0"],
1048
1065
  names: {
1049
1066
  en: ["Omega-3 DHA", "DHA", "Docosahexaenoic Acid"],
1050
1067
  pt: ["\xD4mega-3: DHA", "DHA", "\xC1cido Docosahexaenoico"]
@@ -1055,7 +1072,9 @@ var BIOMARKER_DEFINITIONS = [
1055
1072
  category: "nutrientes",
1056
1073
  code: "Omega3_DPA",
1057
1074
  codeAliases: ["DPA"],
1058
- loinc: "48371-9",
1075
+ // Fração em sangue, painel 90918-4. Ver `Omega3_DHA`.
1076
+ loinc: "90913-5",
1077
+ loincAliases: ["48371-9"],
1059
1078
  names: {
1060
1079
  en: ["Omega-3 DPA", "DPA", "Docosapentaenoic Acid"],
1061
1080
  pt: ["\xD4mega-3: DPA", "DPA", "\xC1cido Docosapentaenoico"]
@@ -1066,7 +1085,9 @@ var BIOMARKER_DEFINITIONS = [
1066
1085
  category: "nutrientes",
1067
1086
  code: "Omega3_EPA",
1068
1087
  codeAliases: ["EPA"],
1069
- loinc: "75097-6",
1088
+ // Fração em sangue, painel 90918-4. Ver `Omega3_DHA`.
1089
+ loinc: "90912-7",
1090
+ loincAliases: ["75097-6"],
1070
1091
  names: {
1071
1092
  en: ["Omega-3 EPA", "EPA", "Eicosapentaenoic Acid"],
1072
1093
  pt: ["\xD4mega-3: EPA", "EPA", "\xC1cido Eicosapentaenoico"]
@@ -1076,7 +1097,12 @@ var BIOMARKER_DEFINITIONS = [
1076
1097
  {
1077
1098
  category: "nutrientes",
1078
1099
  code: "EPADPADHA",
1079
- loinc: "90908-5",
1100
+ // 90911-9 é a fração EPA+DPA+DHA / ácidos graxos C14-C22 em sangue, o
1101
+ // valor em %. Até out/2026 apontava para 90908-5, que é a *interpretação*
1102
+ // desse mesmo valor (ordinal: risco alto, moderado, baixo), e não o
1103
+ // número. Sem alias: código ordinal carregando valor numérico é o erro
1104
+ // que se quer parar de aceitar.
1105
+ loinc: "90911-9",
1080
1106
  names: {
1081
1107
  en: ["Omega-3 EPA+DPA+DHA", "EPA+DPA+DHA"],
1082
1108
  pt: ["\xD4mega-3: EPA+DPA+DHA"]
@@ -1097,7 +1123,12 @@ var BIOMARKER_DEFINITIONS = [
1097
1123
  {
1098
1124
  category: "nutrientes",
1099
1125
  code: "Omega6_Total",
1100
- loinc: "35177-5",
1126
+ // 99621-5 é "Omega 6 fatty acids (w6) [Moles/volume] in RBC.lysate", o
1127
+ // par exato do 99620-7 de `Omega3_Total`, com o mesmo compromisso de
1128
+ // propriedade documentado lá. Até out/2026 apontava para 35177-5, que é
1129
+ // ácidos graxos poli-insaturados totais em soro: ômega-3 e ômega-6
1130
+ // somados, outro componente. Sem alias.
1131
+ loinc: "99621-5",
1101
1132
  names: {
1102
1133
  en: ["Omega-6 Total", "Total Omega-6"],
1103
1134
  pt: ["\xD4mega-6 Total"]
@@ -1108,7 +1139,9 @@ var BIOMARKER_DEFINITIONS = [
1108
1139
  category: "nutrientes",
1109
1140
  code: "Omega6_AA",
1110
1141
  codeAliases: ["Arachidonic_Acid"],
1111
- loinc: "75110-7",
1142
+ // Fração em sangue, painel 90918-4. Ver `Omega3_DHA`.
1143
+ loinc: "90916-8",
1144
+ loincAliases: ["75110-7"],
1112
1145
  names: {
1113
1146
  en: ["Omega-6 Arachidonic Acid", "Arachidonic Acid", "AA"],
1114
1147
  pt: ["\xD4mega-6: \xC1cido Araquid\xF4nico", "\xC1cido Araquid\xF4nico", "AA"]
@@ -1119,7 +1152,9 @@ var BIOMARKER_DEFINITIONS = [
1119
1152
  category: "nutrientes",
1120
1153
  code: "Omega6_LA",
1121
1154
  codeAliases: ["Linoleic_Acid"],
1122
- loinc: "75117-2",
1155
+ // Fração em sangue, painel 90918-4. Ver `Omega3_DHA`.
1156
+ loinc: "90917-6",
1157
+ loincAliases: ["75117-2"],
1123
1158
  names: {
1124
1159
  en: ["Omega-6 Linoleic Acid", "Linoleic Acid", "LA"],
1125
1160
  pt: ["\xD4mega-6: \xC1cido Linoleico", "\xC1cido Linoleico", "LA"]
@@ -1200,7 +1235,11 @@ var BIOMARKER_DEFINITIONS = [
1200
1235
  {
1201
1236
  category: "nutrientes",
1202
1237
  code: "Zinc",
1203
- loinc: "8245-3",
1238
+ // 5763-8 é "Zinc [Mass/volume] in Serum or Plasma", o zinco sérico da
1239
+ // rotina brasileira (o nome em inglês já dizia "Serum Zinc"). Até out/2026
1240
+ // apontava para 8245-3, o mesmo analito em sangue total, que tem faixa de
1241
+ // referência própria. Sem alias: sangue total é outro material.
1242
+ loinc: "5763-8",
1204
1243
  names: {
1205
1244
  en: ["Zinc", "Serum Zinc"],
1206
1245
  pt: ["Zinco"]
@@ -1301,6 +1340,9 @@ var BIOMARKER_DEFINITIONS = [
1301
1340
  {
1302
1341
  category: "figado",
1303
1342
  code: "Globulin",
1343
+ // 2336-6 é "Globulin [Mass/volume] in Serum", soro só: o LOINC 2.82 não
1344
+ // tem a versão Ser/Plas da globulina total (as frações alfa, beta e gama
1345
+ // têm). Material registrado de propósito.
1304
1346
  loinc: "2336-6",
1305
1347
  names: {
1306
1348
  en: ["Globulin", "Serum Globulin"],
@@ -1580,6 +1622,13 @@ var BIOMARKER_DEFINITIONS = [
1580
1622
  {
1581
1623
  category: "rins",
1582
1624
  code: "BUN_Creatinine_Ratio",
1625
+ // 3097-3 é "Urea nitrogen/Creatinine [Mass Ratio]", a razão BUN/creatinina,
1626
+ // e a faixa de referência (10-20, Tietz) é a dessa convenção. O laudo
1627
+ // brasileiro imprime "Relação Ureia/Creatinina", cuja faixa é outra (cerca
1628
+ // de 21-43) e cujo código é 56997-0 ("Urea/Creatinine [Mass Ratio] in
1629
+ // Serum or Plasma"). Trocar só o código deixaria a faixa errada do outro
1630
+ // lado; a separação em duas grandezas, como em `Glucose_Fasting`, é
1631
+ // decisão à parte, registrada em `reference-ranges.ts`.
1583
1632
  loinc: "3097-3",
1584
1633
  names: {
1585
1634
  en: ["BUN/Creatinine Ratio", "Urea/Creatinine Ratio"],
@@ -1747,7 +1796,12 @@ var BIOMARKER_DEFINITIONS = [
1747
1796
  category: "urina",
1748
1797
  code: "Bacteria_Urine",
1749
1798
  codeAliases: ["UrineBacteria"],
1750
- loinc: "630-4",
1799
+ // 5769-5 é "Bacteria [#/area] in Urine sediment by Microscopy high power
1800
+ // field", a contagem do sedimento que a unidade /HPF declara. Até out/2026
1801
+ // apontava para 630-4, "Bacteria identified in Urine by Culture": outro
1802
+ // exame, nominal, que identifica a espécie em cultura. Sem alias:
1803
+ // urocultura não é sedimento.
1804
+ loinc: "5769-5",
1751
1805
  names: {
1752
1806
  en: ["Urine Bacteria", "Bacteria Urine", "Bacteria, Urine", "Bacteria"],
1753
1807
  pt: ["Bact\xE9rias na Urina", "Bact\xE9rias"]
@@ -1866,7 +1920,14 @@ var BIOMARKER_DEFINITIONS = [
1866
1920
  {
1867
1921
  category: "urina",
1868
1922
  code: "RBC_Urine",
1869
- loinc: "5808-1",
1923
+ // 13945-1 é "Erythrocytes [#/area] in Urine sediment by Microscopy high
1924
+ // power field", o /HPF que o laudo imprime e que `Leukocytes_Urine` já usa
1925
+ // em 5821-4. Até out/2026 apontava para 5808-1, o mesmo exame em #/volume
1926
+ // (por mL): analito e material certos, propriedade errada. Fica como alias
1927
+ // porque o analito é o mesmo, e laudo de analisador automático que conte
1928
+ // por mL continua resolvendo em RBC_Urine.
1929
+ loinc: "13945-1",
1930
+ loincAliases: ["5808-1"],
1870
1931
  names: {
1871
1932
  en: ["Urine RBC", "Red Blood Cells in Urine", "RBC Urine", "RBC, Urine"],
1872
1933
  pt: ["Hem\xE1cias na Urina"]
@@ -1961,6 +2022,10 @@ var BIOMARKER_DEFINITIONS = [
1961
2022
  {
1962
2023
  category: "autoimunidade",
1963
2024
  code: "Gliadin_Deamidated_IgA",
2025
+ // 63453-5 e 63459-2 (IgG) afirmam método, "by Immunoassay", e material,
2026
+ // "Serum". É o que os kits de DGP usam. A propriedade é unidades
2027
+ // arbitrárias por volume, e o laudo imprime U/mL; até out/2026 a unidade
2028
+ // declarada era "U", sem o volume.
1964
2029
  loinc: "63453-5",
1965
2030
  names: {
1966
2031
  en: [
@@ -1974,7 +2039,7 @@ var BIOMARKER_DEFINITIONS = [
1974
2039
  ],
1975
2040
  pt: ["Anticorpos Anti-Gliadina Deamidada IgA", "DGP IgA"]
1976
2041
  },
1977
- unit: "U"
2042
+ unit: "U/mL"
1978
2043
  },
1979
2044
  {
1980
2045
  category: "autoimunidade",
@@ -1992,7 +2057,7 @@ var BIOMARKER_DEFINITIONS = [
1992
2057
  ],
1993
2058
  pt: ["Anticorpos Anti-Gliadina Deamidada IgG", "DGP IgG"]
1994
2059
  },
1995
- unit: "U"
2060
+ unit: "U/mL"
1996
2061
  },
1997
2062
  {
1998
2063
  category: "autoimunidade",
@@ -2383,6 +2448,10 @@ var BIOMARKER_DEFINITIONS = [
2383
2448
  {
2384
2449
  category: "composicao-corporal",
2385
2450
  code: "TotalBodyWater",
2451
+ // 101683-1 é "Body water mass", em kg; o aparelho de bioimpedância imprime
2452
+ // litros. É o único código de água corporal total no LOINC 2.82 (o outro,
2453
+ // 101684-9, é o percentual), e para água 1 L pesa 1 kg, então o número não
2454
+ // muda. O teste de eixos lista a entrada como exceção com este motivo.
2386
2455
  loinc: "101683-1",
2387
2456
  names: {
2388
2457
  en: ["Total Body Water", "Body Water", "TBW", "Total Water"],
@@ -2448,6 +2517,10 @@ var BIOMARKER_DEFINITIONS = [
2448
2517
  {
2449
2518
  category: "composicao-corporal",
2450
2519
  code: "PhaseAngle",
2520
+ // 107160-4 é "Phase angle Xc/R [Ratio] Bioelectrical impedance analysis",
2521
+ // único código de ângulo de fase. O aparelho imprime graus (arctan Xc/R)
2522
+ // e o LOINC declara razão com unidade-exemplo %. Fica em graus, que é o
2523
+ // que o laudo traz, e o teste de eixos lista a entrada como exceção.
2451
2524
  loinc: "107160-4",
2452
2525
  names: {
2453
2526
  en: ["Phase Angle", "Whole Body Phase Angle", "PhA", "AnglePhase"],
@@ -2538,9 +2611,9 @@ var BIOMARKER_DEFINITIONS = [
2538
2611
  {
2539
2612
  category: "composicao-corporal",
2540
2613
  code: "WaistCircumference",
2541
- // 8280-0 é a medida em si. 56086-2, que parecia o óbvio pela busca, é
2542
- // "Adult Waist Circumference Protocol", um protocolo PhenX e não um
2543
- // resultado.
2614
+ // 8280-0 é a medida em si, e afirma sítio e método: "at umbilicus by Tape
2615
+ // measure". 56086-2, que parecia o óbvio pela busca, é "Adult Waist
2616
+ // Circumference Protocol", um protocolo PhenX e não um resultado.
2544
2617
  loinc: "8280-0",
2545
2618
  names: {
2546
2619
  en: ["Waist Circumference", "Abdominal Circumference", "Waist"],
@@ -2950,6 +3023,10 @@ var BIOMARKER_DEFINITIONS = [
2950
3023
  {
2951
3024
  category: "coracao",
2952
3025
  code: "TroponinI",
3026
+ // 49563-0 afirma método: limite de detecção ≤ 0,01 ng/mL, o ensaio de alta
3027
+ // sensibilidade. Um resultado de troponina I convencional pede o código
3028
+ // sem método, 10839-9. Assimétrico com `TroponinT`, que fica no 6598-7 sem
3029
+ // método de propósito: a hs-cTnT em ng/L é a convenção dos laudos.
2953
3030
  loinc: "49563-0",
2954
3031
  names: {
2955
3032
  en: ["Troponin I", "cTnI", "Cardiac Troponin I", "hs-TnI", "High-Sensitivity Troponin I"],
@@ -2960,6 +3037,9 @@ var BIOMARKER_DEFINITIONS = [
2960
3037
  {
2961
3038
  category: "coracao",
2962
3039
  code: "TroponinT",
3040
+ // 6598-7 não afirma método. A unidade ng/L é a convenção do ensaio de alta
3041
+ // sensibilidade (hs-cTnT), e o ensaio convencional em ng/mL converte por
3042
+ // fator exato (ver `units.ts`). Ver `TroponinI` para a assimetria.
2963
3043
  loinc: "6598-7",
2964
3044
  names: {
2965
3045
  en: ["Troponin T", "cTnT", "Cardiac Troponin T", "hs-TnT", "High-Sensitivity Troponin T"],
@@ -2996,6 +3076,11 @@ var BIOMARKER_DEFINITIONS = [
2996
3076
  {
2997
3077
  category: "figado",
2998
3078
  code: "LDH",
3079
+ // 14804-9 afirma método: reação lactato → piruvato (L→P). O código sem
3080
+ // método, 2532-0, está DISCOURAGED, então um método tem que ser escolhido,
3081
+ // e L→P é o do procedimento de referência IFCC que os laboratórios
3082
+ // brasileiros usam, ainda que o laudo raramente imprima a direção. Se um
3083
+ // laudo declarar P→L, o código é outro (14805-6).
2999
3084
  loinc: "14804-9",
3000
3085
  // 2532-0 é o código genérico anterior, que o LOINC marca como DISCOURAGED.
3001
3086
  // Fica como alias para que laudo antigo e dado já armazenado continuem
@@ -3126,7 +3211,13 @@ var BIOMARKER_DEFINITIONS = [
3126
3211
  {
3127
3212
  category: "pancreas",
3128
3213
  code: "BetaHydroxybutyrate",
3129
- loinc: "53060-0",
3214
+ // 6873-4 é "Beta hydroxybutyrate [Moles/volume] in Serum or Plasma", o
3215
+ // que o laudo dosa em mmol/L. Até out/2026 apontava para 53060-0, que é
3216
+ // butirilcarnitina (C4) em líquido amniótico: analito e material errados
3217
+ // desde abr/2026, e nenhum check pegou porque o código existe e está
3218
+ // ACTIVE. Sem alias para o código antigo: ele nunca significou BHB, e
3219
+ // aceitá-lo na importação faria um laudo de carnitina virar cetona.
3220
+ loinc: "6873-4",
3130
3221
  names: {
3131
3222
  en: ["Beta-Hydroxybutyrate", "\u03B2-Hydroxybutyrate", "BHB", "Ketone Bodies"],
3132
3223
  pt: ["Beta-Hidroxibutirato", "\u03B2-Hidroxibutirato", "BHB", "Corpos Cet\xF4nicos"]
@@ -3465,4 +3556,4 @@ export {
3465
3556
  getBiomarkersByCategory,
3466
3557
  getBiomarkersForCategories
3467
3558
  };
3468
- //# sourceMappingURL=chunk-WDDW2WCY.js.map
3559
+ //# sourceMappingURL=chunk-4FKZG5GZ.js.map