ibge-br-mcp 3.2.0 → 4.0.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 (101) hide show
  1. package/README.md +49 -19
  2. package/README.pt-BR.md +16 -14
  3. package/dist/cache.d.ts +29 -0
  4. package/dist/cache.d.ts.map +1 -1
  5. package/dist/cache.js +38 -0
  6. package/dist/cache.js.map +1 -1
  7. package/dist/config.d.ts +9 -9
  8. package/dist/config.js +9 -9
  9. package/dist/provenance.d.ts +172 -0
  10. package/dist/provenance.d.ts.map +1 -0
  11. package/dist/provenance.js +193 -0
  12. package/dist/provenance.js.map +1 -0
  13. package/dist/resources.js +2 -2
  14. package/dist/resources.js.map +1 -1
  15. package/dist/server.d.ts.map +1 -1
  16. package/dist/server.js +27 -55
  17. package/dist/server.js.map +1 -1
  18. package/dist/stats.d.ts.map +1 -1
  19. package/dist/stats.js +21 -6
  20. package/dist/stats.js.map +1 -1
  21. package/dist/structured.d.ts +10 -0
  22. package/dist/structured.d.ts.map +1 -1
  23. package/dist/structured.js +16 -0
  24. package/dist/structured.js.map +1 -1
  25. package/dist/tools/calendario.d.ts.map +1 -1
  26. package/dist/tools/calendario.js +7 -0
  27. package/dist/tools/calendario.js.map +1 -1
  28. package/dist/tools/censo.d.ts +1 -1
  29. package/dist/tools/censo.d.ts.map +1 -1
  30. package/dist/tools/censo.js +24 -2
  31. package/dist/tools/censo.js.map +1 -1
  32. package/dist/tools/cidades.d.ts.map +1 -1
  33. package/dist/tools/cidades.js +87 -9
  34. package/dist/tools/cidades.js.map +1 -1
  35. package/dist/tools/cnae.d.ts.map +1 -1
  36. package/dist/tools/cnae.js +46 -7
  37. package/dist/tools/cnae.js.map +1 -1
  38. package/dist/tools/comparar.d.ts +11 -3
  39. package/dist/tools/comparar.d.ts.map +1 -1
  40. package/dist/tools/comparar.js +83 -32
  41. package/dist/tools/comparar.js.map +1 -1
  42. package/dist/tools/datasaude.d.ts +7 -0
  43. package/dist/tools/datasaude.d.ts.map +1 -1
  44. package/dist/tools/datasaude.js +41 -25
  45. package/dist/tools/datasaude.js.map +1 -1
  46. package/dist/tools/estados.d.ts.map +1 -1
  47. package/dist/tools/estados.js +17 -2
  48. package/dist/tools/estados.js.map +1 -1
  49. package/dist/tools/geocodigo.d.ts.map +1 -1
  50. package/dist/tools/geocodigo.js +31 -0
  51. package/dist/tools/geocodigo.js.map +1 -1
  52. package/dist/tools/index.d.ts +1 -2
  53. package/dist/tools/index.d.ts.map +1 -1
  54. package/dist/tools/index.js +1 -2
  55. package/dist/tools/index.js.map +1 -1
  56. package/dist/tools/indicadores.d.ts +9 -1
  57. package/dist/tools/indicadores.d.ts.map +1 -1
  58. package/dist/tools/indicadores.js +52 -11
  59. package/dist/tools/indicadores.js.map +1 -1
  60. package/dist/tools/localidade.d.ts.map +1 -1
  61. package/dist/tools/localidade.js +16 -6
  62. package/dist/tools/localidade.js.map +1 -1
  63. package/dist/tools/malhas-tema.d.ts.map +1 -1
  64. package/dist/tools/malhas-tema.js +33 -4
  65. package/dist/tools/malhas-tema.js.map +1 -1
  66. package/dist/tools/malhas.d.ts.map +1 -1
  67. package/dist/tools/malhas.js +12 -0
  68. package/dist/tools/malhas.js.map +1 -1
  69. package/dist/tools/municipios.d.ts.map +1 -1
  70. package/dist/tools/municipios.js +11 -1
  71. package/dist/tools/municipios.js.map +1 -1
  72. package/dist/tools/nomes.d.ts.map +1 -1
  73. package/dist/tools/nomes.js +13 -0
  74. package/dist/tools/nomes.js.map +1 -1
  75. package/dist/tools/noticias.d.ts.map +1 -1
  76. package/dist/tools/noticias.js +12 -4
  77. package/dist/tools/noticias.js.map +1 -1
  78. package/dist/tools/paises.d.ts.map +1 -1
  79. package/dist/tools/paises.js +26 -2
  80. package/dist/tools/paises.js.map +1 -1
  81. package/dist/tools/pesquisas.d.ts.map +1 -1
  82. package/dist/tools/pesquisas.js +20 -2
  83. package/dist/tools/pesquisas.js.map +1 -1
  84. package/dist/tools/sidra-metadados.d.ts.map +1 -1
  85. package/dist/tools/sidra-metadados.js +8 -0
  86. package/dist/tools/sidra-metadados.js.map +1 -1
  87. package/dist/tools/sidra-tabelas.d.ts.map +1 -1
  88. package/dist/tools/sidra-tabelas.js +11 -1
  89. package/dist/tools/sidra-tabelas.js.map +1 -1
  90. package/dist/tools/sidra.d.ts +1 -0
  91. package/dist/tools/sidra.d.ts.map +1 -1
  92. package/dist/tools/sidra.js +33 -14
  93. package/dist/tools/sidra.js.map +1 -1
  94. package/dist/tools/vizinhos.d.ts.map +1 -1
  95. package/dist/tools/vizinhos.js +11 -0
  96. package/dist/tools/vizinhos.js.map +1 -1
  97. package/package.json +4 -1
  98. package/dist/tools/populacao.d.ts +0 -29
  99. package/dist/tools/populacao.d.ts.map +0 -1
  100. package/dist/tools/populacao.js +0 -123
  101. package/dist/tools/populacao.js.map +0 -1
package/README.md CHANGED
@@ -1,5 +1,3 @@
1
- [![Verified on MseeP](https://mseep.net/pr/sidneybissoli-ibge-br-mcp-badge.png)](https://mseep.ai/app/sidneybissoli-ibge-br-mcp)
2
-
3
1
  # IBGE Brasil MCP Server
4
2
 
5
3
  [![npm version](https://img.shields.io/npm/v/ibge-br-mcp.svg)](https://www.npmjs.com/package/ibge-br-mcp)
@@ -9,8 +7,8 @@
9
7
  [![LobeHub](https://lobehub.com/badge/mcp/sidneybissoli-ibge-br-mcp)](https://lobehub.com/mcp/sidneybissoli-ibge-br-mcp)
10
8
  [![smithery badge](https://smithery.ai/badge/sidneybissoli/ibge-br-mcp)](https://smithery.ai/server/sidneybissoli/ibge-br-mcp)
11
9
  [![ibge-br-mcp MCP server](https://glama.ai/mcp/servers/@SidneyBissoli/ibge-br-mcp/badges/score.svg)](https://glama.ai/mcp/servers/@SidneyBissoli/ibge-br-mcp)
12
- [![Tests](https://img.shields.io/badge/tests-456%20passed-brightgreen.svg)](https://github.com/SidneyBissoli/ibge-br-mcp)
13
- [![Coverage](https://img.shields.io/badge/coverage-core%2097%25-brightgreen.svg)](https://github.com/SidneyBissoli/ibge-br-mcp)
10
+ [![CI](https://github.com/SidneyBissoli/ibge-br-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/SidneyBissoli/ibge-br-mcp/actions/workflows/ci.yml)
11
+ [![Coverage](https://img.shields.io/badge/coverage-%E2%89%A588%25-brightgreen.svg)](https://github.com/SidneyBissoli/ibge-br-mcp/blob/main/vitest.config.ts)
14
12
  [![GitHub stars](https://img.shields.io/github/stars/SidneyBissoli/ibge-br-mcp?style=flat&logo=github)](https://github.com/SidneyBissoli/ibge-br-mcp)
15
13
  [![GitHub Sponsors](https://img.shields.io/github/sponsors/SidneyBissoli?logo=githubsponsors&label=Sponsor&color=db61a2)](https://github.com/sponsors/SidneyBissoli)
16
14
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -25,25 +23,60 @@ This server implements the [Model Context Protocol (MCP)](https://modelcontextpr
25
23
 
26
24
  ## See it in action
27
25
 
28
- Ask your assistant, in plain Portuguese:
26
+ Ask your assistant, in English or Portuguese:
29
27
 
30
- - *"Qual era a população de Belo Horizonte no Censo 2022?"* → `ibge_cidades` / `ibge_censo`
31
- - *"Liste os municípios do Espírito Santo."* → `ibge_municipios`
32
- - *"Compare o PIB per capita das capitais do Sudeste."* → `ibge_comparar`
28
+ - *"What was Belo Horizonte's population in the 2022 Census?"* → `ibge_cidades` / `ibge_censo`
29
+ - *"List the municipalities of Espírito Santo."* → `ibge_municipios`
30
+ - *"Compare GDP across the Southeast state capitals."* → `ibge_comparar`
33
31
 
34
32
  The answers come live from the official IBGE APIs — exact figures with the table and period they came from, not numbers guessed from training data.
35
33
 
34
+ Want to see a whole analysis rather than a single answer? The
35
+ [**end-to-end demo**](docs/demo.md) works one real question — *which state grew
36
+ most between the 2010 and 2022 Censuses, and what drove it* — from first call to
37
+ conclusion, with every figure as it came back. The
38
+ [**practical examples**](examples/README.md) are seven shorter recipes, including
39
+ ranking all 5,570 municipalities in a single call.
40
+
36
41
  ## Features
37
42
 
38
- - **22 specialized tools** covering all major IBGE data domains
43
+ - **21 specialized tools** covering all major IBGE data domains
44
+ - **Provenance block on every response** — source, canonical URL, reference
45
+ period, real extraction timestamp, ready-to-use citation, and legal regime
46
+ (see [Data provenance](#data-provenance))
39
47
  - **Reference resources & analysis prompts** (MCP catalogs + ready-made templates)
40
- - **460 automated tests** with 97%+ core coverage
48
+ - **565 automated tests** 88% overall coverage, 92% across the tools
41
49
  - **Automatic caching** with configurable TTL for optimal performance
42
50
  - **Retry mechanism** with exponential backoff for network resilience
43
51
  - **Comprehensive validation** for all input parameters
44
52
  - **Standardized error handling** with helpful suggestions
45
53
  - **Full TypeScript support** with strict typing
46
54
 
55
+ ## Data provenance
56
+
57
+ Since v3.3.0 every successful tool response carries a **provenance block**
58
+ ([portfolio contract v1.0](https://www.npmjs.com/package/@sbissoli/mcp-provenance)),
59
+ so each number is citable, auditable, and reproducible. The block is emitted on
60
+ three channels:
61
+
62
+ 1. `structuredContent.provenance` (parseable, visible to the model) — exactly
63
+ six keys: `source` (the IBGE API queried), `source_url` (canonical URL that
64
+ reproduces the query), `data_vintage` (reference period when the source
65
+ exposes one; `null` otherwise), `retrieved_at` (the REAL upstream extraction
66
+ instant, preserved across cache hits, Brasília time), `citation`
67
+ ("Fonte: IBGE — [pesquisa/tabela], [URL], extraído em [data]."), and
68
+ `license` — plus `attribution`, the canonical list of source URLs.
69
+ 2. `_meta` under `br.com.sidneybissoli.ibge/provenance` and `.../attribution`
70
+ (out-of-band mirror for audit/UI, zero model tokens).
71
+ 3. A compact text footer appended to the Markdown, for text-only clients.
72
+
73
+ The IBGE APIs declare no license of their own; the legal regime is Brazil's
74
+ open-data framework — Lei 12.527/2011 (LAI) and Decreto 8.777/2016
75
+ (unrestricted reuse, free use, obligation limited to crediting the source).
76
+ Statistics-mode responses (`estatisticas=true`) and `ibge_comparar` are marked
77
+ `derived` with an explanatory note in the canonical block, since the
78
+ aggregates are computed server-side from the raw IBGE values.
79
+
47
80
  ## Available Tools
48
81
 
49
82
  ### Localities & Geography
@@ -83,7 +116,6 @@ The answers come live from the official IBGE APIs — exact figures with the tab
83
116
  ### Demographics
84
117
  | Tool | Description |
85
118
  |:-----|:------------|
86
- | `ibge_populacao` | Real-time Brazilian population projection |
87
119
  | `ibge_nomes` | Name frequency and rankings in Brazil |
88
120
 
89
121
  ### Classifications
@@ -110,13 +142,12 @@ The answers come live from the official IBGE APIs — exact figures with the tab
110
142
 
111
143
  ## Which tool should I use?
112
144
 
113
- With 22 tools, several can touch the same topic. Quick guide for the common overlaps:
145
+ With 21 tools, several can touch the same topic. Quick guide for the common overlaps:
114
146
 
115
147
  ### Population & demographics
116
148
 
117
149
  | You want… | Use |
118
150
  |:----------|:----|
119
- | Brazil's population right now (real-time) | `ibge_populacao` |
120
151
  | A single municipality/state panel (population, HDI, GDP…) | `ibge_cidades` |
121
152
  | Census data or historical series (1970–2022) | `ibge_censo` |
122
153
  | Rank/compare 2–10 localities on one indicator | `ibge_comparar` |
@@ -189,7 +220,7 @@ Add to your Claude Desktop configuration file (`claude_desktop_config.json`):
189
220
  "mcpServers": {
190
221
  "ibge-br-mcp": {
191
222
  "command": "npx",
192
- "args": ["ibge-br-mcp"]
223
+ "args": ["-y", "ibge-br-mcp"]
193
224
  }
194
225
  }
195
226
  }
@@ -215,7 +246,7 @@ Or if installed from source:
215
246
  "mcpServers": {
216
247
  "ibge-br-mcp": {
217
248
  "command": "npx",
218
- "args": ["ibge-br-mcp"]
249
+ "args": ["-y", "ibge-br-mcp"]
219
250
  }
220
251
  }
221
252
  }
@@ -507,7 +538,6 @@ ibge-br-mcp/
507
538
  │ ├── localidade.ts # ibge_localidade
508
539
  │ ├── geocodigo.ts # ibge_geocodigo
509
540
  │ ├── censo.ts # ibge_censo
510
- │ ├── populacao.ts # ibge_populacao
511
541
  │ ├── sidra.ts # ibge_sidra
512
542
  │ ├── sidra-tabelas.ts # ibge_sidra_tabelas
513
543
  │ ├── sidra-metadados.ts# ibge_sidra_metadados
@@ -534,7 +564,7 @@ ibge-br-mcp/
534
564
 
535
565
  ## Testing
536
566
 
537
- The project includes a comprehensive test suite with 227 tests covering:
567
+ The project includes a comprehensive test suite with 565 tests covering:
538
568
 
539
569
  - Validation functions
540
570
  - Retry mechanism
@@ -551,8 +581,8 @@ npm test
551
581
 
552
582
  This project maintains high code quality standards:
553
583
 
554
- - **227 automated tests** covering validation, caching, retry logic, formatting, and integrations
555
- - **97%+ test coverage** on core modules (cache, validation, errors, types)
584
+ - **565 automated tests** covering validation, caching, retry logic, formatting, and integrations
585
+ - **88% overall test coverage** cache and validation modules above 97%
556
586
  - **ESLint** for code linting with zero warnings
557
587
  - **Prettier** for consistent code formatting
558
588
  - **TypeScript strict mode** for type safety
package/README.pt-BR.md CHANGED
@@ -1,5 +1,3 @@
1
- [![Verified on MseeP](https://mseep.net/pr/sidneybissoli-ibge-br-mcp-badge.png)](https://mseep.ai/app/sidneybissoli-ibge-br-mcp)
2
-
3
1
  # ibge-br-mcp
4
2
 
5
3
  [![npm version](https://img.shields.io/npm/v/ibge-br-mcp.svg)](https://www.npmjs.com/package/ibge-br-mcp)
@@ -9,8 +7,8 @@
9
7
  [![LobeHub](https://lobehub.com/badge/mcp/sidneybissoli-ibge-br-mcp)](https://lobehub.com/mcp/sidneybissoli-ibge-br-mcp)
10
8
  [![smithery badge](https://smithery.ai/badge/sidneybissoli/ibge-br-mcp)](https://smithery.ai/server/sidneybissoli/ibge-br-mcp)
11
9
  [![ibge-br-mcp MCP server](https://glama.ai/mcp/servers/@SidneyBissoli/ibge-br-mcp/badges/score.svg)](https://glama.ai/mcp/servers/@SidneyBissoli/ibge-br-mcp)
12
- [![Tests](https://img.shields.io/badge/tests-456%20passed-brightgreen.svg)](https://github.com/SidneyBissoli/ibge-br-mcp)
13
- [![Coverage](https://img.shields.io/badge/coverage-core%2097%25-brightgreen.svg)](https://github.com/SidneyBissoli/ibge-br-mcp)
10
+ [![CI](https://github.com/SidneyBissoli/ibge-br-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/SidneyBissoli/ibge-br-mcp/actions/workflows/ci.yml)
11
+ [![Coverage](https://img.shields.io/badge/coverage-%E2%89%A588%25-brightgreen.svg)](https://github.com/SidneyBissoli/ibge-br-mcp/blob/main/vitest.config.ts)
14
12
  [![GitHub stars](https://img.shields.io/github/stars/SidneyBissoli/ibge-br-mcp?style=flat&logo=github)](https://github.com/SidneyBissoli/ibge-br-mcp)
15
13
  [![GitHub Sponsors](https://img.shields.io/github/sponsors/SidneyBissoli?logo=githubsponsors&label=Sponsor&color=db61a2)](https://github.com/sponsors/SidneyBissoli)
16
14
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -29,15 +27,22 @@ Pergunte ao seu assistente, em português:
29
27
 
30
28
  - *"Qual era a população de Belo Horizonte no Censo 2022?"* → `ibge_cidades` / `ibge_censo`
31
29
  - *"Liste os municípios do Espírito Santo."* → `ibge_municipios`
32
- - *"Compare o PIB per capita das capitais do Sudeste."* → `ibge_comparar`
30
+ - *"Compare o PIB das capitais do Sudeste."* → `ibge_comparar`
33
31
 
34
32
  As respostas vêm ao vivo das APIs oficiais do IBGE — valores exatos com a tabela e o período de onde vieram, não números chutados do treino.
35
33
 
34
+ Quer ver uma análise inteira, e não uma resposta só? A
35
+ [**demo ponta a ponta**](docs/demo.pt-BR.md) percorre uma pergunta real — *qual
36
+ estado mais cresceu entre os Censos de 2010 e 2022, e o que puxou o crescimento*
37
+ — da primeira chamada à conclusão, com cada número como ele voltou. Os
38
+ [**exemplos práticos**](examples/README.pt-BR.md) são sete receitas mais curtas,
39
+ entre elas ranquear os 5.570 municípios numa chamada só.
40
+
36
41
  ## Recursos
37
42
 
38
- - **22 ferramentas especializadas** cobrindo todos os principais domínios de dados do IBGE
43
+ - **21 ferramentas especializadas** cobrindo todos os principais domínios de dados do IBGE
39
44
  - **Resources de referência & prompts de análise** (catálogos MCP + templates prontos)
40
- - **460 testes automatizados** com 97%+ de cobertura no core
45
+ - **565 testes automatizados** 88% de cobertura geral, 92% nas tools
41
46
  - **Cache automático** com TTL configurável para performance otimizada
42
47
  - **Mecanismo de retry** com backoff exponencial para resiliência de rede
43
48
  - **Validação abrangente** para todos os parâmetros de entrada
@@ -83,7 +88,6 @@ As respostas vêm ao vivo das APIs oficiais do IBGE — valores exatos com a tab
83
88
  ### Demografia
84
89
  | Ferramenta | Descrição |
85
90
  |:-----------|:----------|
86
- | `ibge_populacao` | Projeção populacional brasileira em tempo real |
87
91
  | `ibge_nomes` | Frequência e rankings de nomes no Brasil |
88
92
 
89
93
  ### Classificações
@@ -110,13 +114,12 @@ As respostas vêm ao vivo das APIs oficiais do IBGE — valores exatos com a tab
110
114
 
111
115
  ## Qual ferramenta usar?
112
116
 
113
- Com 22 ferramentas, várias podem tocar no mesmo assunto. Guia rápido para as sobreposições comuns:
117
+ Com 21 ferramentas, várias podem tocar no mesmo assunto. Guia rápido para as sobreposições comuns:
114
118
 
115
119
  ### População e demografia
116
120
 
117
121
  | Você quer… | Use |
118
122
  |:-----------|:----|
119
- | População do Brasil agora (tempo real) | `ibge_populacao` |
120
123
  | Painel de um único município/UF (população, IDH, PIB…) | `ibge_cidades` |
121
124
  | Dados censitários ou série histórica (1970–2022) | `ibge_censo` |
122
125
  | Ranquear/comparar 2–10 localidades num indicador | `ibge_comparar` |
@@ -511,7 +514,6 @@ ibge-br-mcp/
511
514
  │ ├── localidade.ts # ibge_localidade
512
515
  │ ├── geocodigo.ts # ibge_geocodigo
513
516
  │ ├── censo.ts # ibge_censo
514
- │ ├── populacao.ts # ibge_populacao
515
517
  │ ├── sidra.ts # ibge_sidra
516
518
  │ ├── sidra-tabelas.ts # ibge_sidra_tabelas
517
519
  │ ├── sidra-metadados.ts# ibge_sidra_metadados
@@ -538,7 +540,7 @@ ibge-br-mcp/
538
540
 
539
541
  ## Testes
540
542
 
541
- O projeto inclui uma suíte de testes abrangente com 227 testes cobrindo:
543
+ O projeto inclui uma suíte de testes abrangente com 565 testes cobrindo:
542
544
 
543
545
  - Funções de validação
544
546
  - Mecanismo de retry
@@ -555,8 +557,8 @@ npm test
555
557
 
556
558
  Este projeto mantém altos padrões de qualidade de código:
557
559
 
558
- - **227 testes automatizados** cobrindo validação, cache, retry, formatação e integrações
559
- - **97%+ de cobertura de testes** nos módulos core (cache, validation, errors, types)
560
+ - **565 testes automatizados** cobrindo validação, cache, retry, formatação e integrações
561
+ - **88% de cobertura de testes no total** os módulos cache e validation acima de 97%
560
562
  - **ESLint** para linting de código sem warnings
561
563
  - **Prettier** para formatação consistente
562
564
  - **TypeScript modo strict** para segurança de tipos
package/dist/cache.d.ts CHANGED
@@ -2,8 +2,19 @@
2
2
  * Simple in-memory cache with TTL support for IBGE API requests
3
3
  */
4
4
  import { type RetryOptions } from "./retry.js";
5
+ /**
6
+ * Metadata of the last `cachedFetch` call for a cache key: the REAL instant the
7
+ * data was extracted from the upstream (preserved across cache hits — it is the
8
+ * legally relevant extraction date for the provenance block) and whether that
9
+ * last call was served from cache.
10
+ */
11
+ export interface FetchMeta {
12
+ retrievedAt: Date;
13
+ servedFromCache: boolean;
14
+ }
5
15
  declare class RequestCache {
6
16
  private cache;
17
+ private fetchMeta;
7
18
  private defaultTTL;
8
19
  constructor(defaultTTLMinutes?: number);
9
20
  /**
@@ -26,6 +37,16 @@ declare class RequestCache {
26
37
  * Clear all cached data
27
38
  */
28
39
  clear(): void;
40
+ /** Records a real upstream fetch for a key (called by `cachedFetch` on a miss). */
41
+ recordFetch(key: string, retrievedAt: number): void;
42
+ /**
43
+ * Records a cache hit for a key, preserving the original fetch instant.
44
+ * Entries seeded via `set()` directly (tests) have no recorded fetch; the hit
45
+ * instant is the best available approximation then.
46
+ */
47
+ recordHit(key: string): void;
48
+ /** Fetch metadata of the last `cachedFetch` call for this key, if any. */
49
+ meta(key: string): FetchMeta | null;
29
50
  /**
30
51
  * Remove all expired entries
31
52
  */
@@ -53,5 +74,13 @@ export declare function cacheKey(base: string, params?: Record<string, string |
53
74
  * Fetch with cache support and automatic retry on network failures
54
75
  */
55
76
  export declare function cachedFetch<T>(url: string, cacheKeyStr: string, ttlMinutes?: number, retryOptions?: RetryOptions): Promise<T>;
77
+ /**
78
+ * Fetch metadata of the last `cachedFetch` call for a cache key — the REAL
79
+ * upstream extraction instant (`retrieved_at` of the provenance contract v1.0,
80
+ * preserved across cache hits) and whether the last call was a cache hit.
81
+ * Query it right after `cachedFetch` with the same key; the ~40 existing call
82
+ * sites stay unchanged (parallel-map design, `ibge/docs/03` §3).
83
+ */
84
+ export declare function lastFetchMeta(cacheKeyStr: string): FetchMeta | null;
56
85
  export {};
57
86
  //# sourceMappingURL=cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAO/D,cAAM,YAAY;IAChB,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,UAAU,CAAS;gBAEf,iBAAiB,GAAE,MAAW;IAI1C;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAY7B;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAQvD;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,OAAO,IAAI,IAAI;IASf;;OAEG;IACH,KAAK,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE;CAO1C;AAGD,eAAO,MAAM,KAAK,cAAuB,CAAC;AAG1C,eAAO,MAAM,SAAS;;;;;CAKZ,CAAC;AAEX;;GAEG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,GAC7D,MAAM,CAUR;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,CAAC,EACjC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,CAAC,CAAC,CAoBZ"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAO/D;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,IAAI,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,cAAM,YAAY;IAChB,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,SAAS,CAA6E;IAC9F,OAAO,CAAC,UAAU,CAAS;gBAEf,iBAAiB,GAAE,MAAW;IAI1C;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAY7B;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAQvD;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKzB;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb,mFAAmF;IACnF,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAInD;;;;OAIG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQ5B,0EAA0E;IAC1E,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAMnC;;OAEG;IACH,OAAO,IAAI,IAAI;IASf;;OAEG;IACH,KAAK,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE;CAO1C;AAGD,eAAO,MAAM,KAAK,cAAuB,CAAC;AAG1C,eAAO,MAAM,SAAS;;;;;CAKZ,CAAC;AAEX;;GAEG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,GAC7D,MAAM,CAUR;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,CAAC,EACjC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAEnE"}
package/dist/cache.js CHANGED
@@ -4,6 +4,7 @@
4
4
  import { fetchWithRetry } from "./retry.js";
5
5
  class RequestCache {
6
6
  cache = new Map();
7
+ fetchMeta = new Map();
7
8
  defaultTTL;
8
9
  constructor(defaultTTLMinutes = 15) {
9
10
  this.defaultTTL = defaultTTLMinutes * 60 * 1000;
@@ -42,12 +43,37 @@ class RequestCache {
42
43
  */
43
44
  delete(key) {
44
45
  this.cache.delete(key);
46
+ this.fetchMeta.delete(key);
45
47
  }
46
48
  /**
47
49
  * Clear all cached data
48
50
  */
49
51
  clear() {
50
52
  this.cache.clear();
53
+ this.fetchMeta.clear();
54
+ }
55
+ /** Records a real upstream fetch for a key (called by `cachedFetch` on a miss). */
56
+ recordFetch(key, retrievedAt) {
57
+ this.fetchMeta.set(key, { retrievedAt, servedFromCache: false });
58
+ }
59
+ /**
60
+ * Records a cache hit for a key, preserving the original fetch instant.
61
+ * Entries seeded via `set()` directly (tests) have no recorded fetch; the hit
62
+ * instant is the best available approximation then.
63
+ */
64
+ recordHit(key) {
65
+ const existing = this.fetchMeta.get(key);
66
+ this.fetchMeta.set(key, {
67
+ retrievedAt: existing?.retrievedAt ?? Date.now(),
68
+ servedFromCache: true,
69
+ });
70
+ }
71
+ /** Fetch metadata of the last `cachedFetch` call for this key, if any. */
72
+ meta(key) {
73
+ const m = this.fetchMeta.get(key);
74
+ if (!m)
75
+ return null;
76
+ return { retrievedAt: new Date(m.retrievedAt), servedFromCache: m.servedFromCache };
51
77
  }
52
78
  /**
53
79
  * Remove all expired entries
@@ -100,6 +126,7 @@ export async function cachedFetch(url, cacheKeyStr, ttlMinutes, retryOptions) {
100
126
  // Check cache first
101
127
  const cached = cache.get(cacheKeyStr);
102
128
  if (cached !== null) {
129
+ cache.recordHit(cacheKeyStr);
103
130
  return cached;
104
131
  }
105
132
  // Fetch from API with retry support
@@ -110,6 +137,17 @@ export async function cachedFetch(url, cacheKeyStr, ttlMinutes, retryOptions) {
110
137
  const data = (await response.json());
111
138
  // Store in cache
112
139
  cache.set(cacheKeyStr, data, ttlMinutes);
140
+ cache.recordFetch(cacheKeyStr, Date.now());
113
141
  return data;
114
142
  }
143
+ /**
144
+ * Fetch metadata of the last `cachedFetch` call for a cache key — the REAL
145
+ * upstream extraction instant (`retrieved_at` of the provenance contract v1.0,
146
+ * preserved across cache hits) and whether the last call was a cache hit.
147
+ * Query it right after `cachedFetch` with the same key; the ~40 existing call
148
+ * sites stay unchanged (parallel-map design, `ibge/docs/03` §3).
149
+ */
150
+ export function lastFetchMeta(cacheKeyStr) {
151
+ return cache.meta(cacheKeyStr);
152
+ }
115
153
  //# sourceMappingURL=cache.js.map
package/dist/cache.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -106,16 +106,16 @@ export declare const SIDRA_TABLES: {
106
106
  readonly POPULACAO_ESTIMATIVA: "6579";
107
107
  readonly POPULACAO_CENSO_2022: "9514";
108
108
  readonly POPULACAO_CENSOS_HISTORICO: "200";
109
- readonly PIB_CORRENTE: "6706";
109
+ readonly PIB_CORRENTE: "1846";
110
110
  readonly PIB_PER_CAPITA: "5938";
111
- readonly AREA_TERRITORIAL: "1705";
112
- readonly DENSIDADE_DEMOGRAFICA: "1712";
113
- readonly TAXA_DESOCUPACAO: "4714";
114
- readonly RENDIMENTO_MEDIO: "6381";
115
- readonly IPCA_MENSAL: "1737";
116
- readonly IPCA_ACUMULADO: "1736";
117
- readonly ALFABETIZACAO: "4312";
118
- readonly DOMICILIOS: "4311";
111
+ readonly AREA_TERRITORIAL: "4714";
112
+ readonly DENSIDADE_DEMOGRAFICA: "4714";
113
+ readonly TAXA_DESOCUPACAO: "4099";
114
+ readonly RENDIMENTO_MEDIO: "5436";
115
+ readonly IPCA_MENSAL: "7060";
116
+ readonly IPCA_ACUMULADO: "1737";
117
+ readonly ALFABETIZACAO: "9543";
118
+ readonly DOMICILIOS: "4711";
119
119
  };
120
120
  /**
121
121
  * Regex patterns for validation
package/dist/config.js CHANGED
@@ -271,19 +271,19 @@ export const SIDRA_TABLES = {
271
271
  POPULACAO_CENSO_2022: "9514",
272
272
  POPULACAO_CENSOS_HISTORICO: "200",
273
273
  // Economy
274
- PIB_CORRENTE: "6706",
274
+ PIB_CORRENTE: "1846",
275
275
  PIB_PER_CAPITA: "5938",
276
- AREA_TERRITORIAL: "1705",
277
- DENSIDADE_DEMOGRAFICA: "1712",
276
+ AREA_TERRITORIAL: "4714",
277
+ DENSIDADE_DEMOGRAFICA: "4714",
278
278
  // Labor
279
- TAXA_DESOCUPACAO: "4714",
280
- RENDIMENTO_MEDIO: "6381",
279
+ TAXA_DESOCUPACAO: "4099",
280
+ RENDIMENTO_MEDIO: "5436",
281
281
  // Prices
282
- IPCA_MENSAL: "1737",
283
- IPCA_ACUMULADO: "1736",
282
+ IPCA_MENSAL: "7060",
283
+ IPCA_ACUMULADO: "1737",
284
284
  // Census themes
285
- ALFABETIZACAO: "4312",
286
- DOMICILIOS: "4311",
285
+ ALFABETIZACAO: "9543",
286
+ DOMICILIOS: "4711",
287
287
  };
288
288
  // ============================================================================
289
289
  // Validation Patterns
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Provenance block (portfolio contract v1.0) — pt-BR adapter over
3
+ * `@sbissoli/mcp-provenance`. The canonical model, the `concise`/`detailed`
4
+ * projections, serialization determinism, timezone handling and the footer
5
+ * wording live in the package; this module binds them to the IBGE server:
6
+ *
7
+ * - one `ProvenanceContext` for the whole server (namespace
8
+ * `br.com.sidneybissoli.ibge`, pt-BR footer, Brasília time, `concise` mode);
9
+ * - the source registry (`FONTES_IBGE`) — one entry per IBGE API consumed;
10
+ * - the normative license block (no explicit license upstream — the legal
11
+ * basis is LAI + Decreto 8.777/2016, verbatim verification `ibge/docs/01`,
12
+ * 2026-08-08). Never use the IBGE logo/brand;
13
+ * - `provenienciaIbge(...)`, the per-call builder every tool uses. It pulls
14
+ * the REAL extraction instant (`retrieved_at`) and `served_from_cache` from
15
+ * the cache layer via `lastFetchMeta` (contract: cache hits keep the
16
+ * original fetch instant — it is the legally relevant extraction date).
17
+ *
18
+ * Emission happens in `toMcpResult` (`structured.ts`): tools attach the
19
+ * canonical block to their `StructuredToolResult` and the handler emits the
20
+ * three channels — `structuredContent.provenance` + `attribution` (parseable,
21
+ * visible to the model), `_meta` under namespaced keys (out-of-band, zero
22
+ * model tokens), and the compact text footer appended to the Markdown.
23
+ *
24
+ * `derived` semantics (same rule as senado-br-mcp): raw data that is only
25
+ * filtered/paginated/reserialized → `false`; the D2 statistics modes
26
+ * (aggregation/rankings computed server-side) → `true` + `derivation_note`.
27
+ */
28
+ import { z } from "zod";
29
+ import { type CanonicalProvenance, type ConciseBlock } from "@sbissoli/mcp-provenance";
30
+ /** Single provenance context for the server: `_meta` namespace, locale, timezone, mode. */
31
+ export declare const provenanceContext: import("@sbissoli/mcp-provenance").ProvenanceContext;
32
+ /** Canonical envelope v1.0 (post-validation). */
33
+ export type Provenance = CanonicalProvenance;
34
+ /** Namespaced `_meta` keys (stable — audit/UI consumers read by these keys). */
35
+ export declare const PROVENANCE_META_KEY: string;
36
+ export declare const ATTRIBUTION_META_KEY: string;
37
+ /**
38
+ * Normative license block (shared by every response): the IBGE APIs declare no
39
+ * license of their own — the legal regime is LAI (Lei 12.527/2011) + Decreto
40
+ * 8.777/2016 (unrestricted reuse, free use, obligation limited to crediting
41
+ * the source). Verbatim verification: `ibge/docs/01`, 2026-08-08.
42
+ */
43
+ export declare const IBGE_LICENSE: {
44
+ readonly id: null;
45
+ readonly name: "Dados abertos do Poder Executivo federal (Lei 12.527/2011; Decreto 8.777/2016)";
46
+ readonly url: null;
47
+ readonly terms_url: "https://www.planalto.gov.br/ccivil_03/_ato2015-2018/2016/decreto/d8777.htm";
48
+ readonly verified_at: "2026-08-08";
49
+ };
50
+ /**
51
+ * Source registry — one entry per IBGE API this server consumes. `name` is
52
+ * what the concise projection shows as `source`; `endpoint` is the base URL
53
+ * actually queried. Text only, never the IBGE logo/brand (docs/01).
54
+ */
55
+ export declare const FONTES_IBGE: {
56
+ readonly LOCALIDADES: {
57
+ readonly name: "IBGE — API de Localidades";
58
+ readonly endpoint: "https://servicodados.ibge.gov.br/api/v1/localidades";
59
+ };
60
+ readonly SIDRA: {
61
+ readonly name: "IBGE — SIDRA (Banco de Tabelas Estatísticas)";
62
+ readonly endpoint: "https://apisidra.ibge.gov.br/values";
63
+ };
64
+ readonly AGREGADOS: {
65
+ readonly name: "IBGE — API de Agregados (SIDRA)";
66
+ readonly endpoint: "https://servicodados.ibge.gov.br/api/v3/agregados";
67
+ };
68
+ readonly NOMES: {
69
+ readonly name: "IBGE — API de Nomes (Censo Demográfico 2010)";
70
+ readonly endpoint: "https://servicodados.ibge.gov.br/api/v2/censos/nomes";
71
+ };
72
+ readonly MALHAS: {
73
+ readonly name: "IBGE — API de Malhas Geográficas";
74
+ readonly endpoint: "https://servicodados.ibge.gov.br/api/v3/malhas";
75
+ };
76
+ readonly NOTICIAS: {
77
+ readonly name: "IBGE — API de Notícias";
78
+ readonly endpoint: "https://servicodados.ibge.gov.br/api/v3/noticias";
79
+ };
80
+ readonly POPULACAO: {
81
+ readonly name: "IBGE — API de Projeções de População";
82
+ readonly endpoint: "https://servicodados.ibge.gov.br/api/v1/projecoes/populacao";
83
+ };
84
+ readonly CNAE: {
85
+ readonly name: "IBGE — API CNAE";
86
+ readonly endpoint: "https://servicodados.ibge.gov.br/api/v2/cnae";
87
+ };
88
+ readonly CALENDARIO: {
89
+ readonly name: "IBGE — API de Calendário de Divulgações";
90
+ readonly endpoint: "https://servicodados.ibge.gov.br/api/v3/calendario";
91
+ };
92
+ readonly PAISES: {
93
+ readonly name: "IBGE — API de Países";
94
+ readonly endpoint: "https://servicodados.ibge.gov.br/api/v1/paises";
95
+ };
96
+ readonly PESQUISAS: {
97
+ readonly name: "IBGE — API de Pesquisas (Cidades@)";
98
+ readonly endpoint: "https://servicodados.ibge.gov.br/api/v1/pesquisas";
99
+ };
100
+ };
101
+ export type FonteIbge = keyof typeof FONTES_IBGE;
102
+ export interface ProvenienciaIbgeOptions {
103
+ /** Which IBGE API answered this response. */
104
+ fonte: FonteIbge;
105
+ /** The URL effectively queried (canonical reproduction of the request). */
106
+ url: string;
107
+ /**
108
+ * Cache key of the main `cachedFetch` call — used to pull the REAL upstream
109
+ * extraction instant and `served_from_cache` from the cache layer. Omit only
110
+ * for static catalogs maintained in code (contract: builder default).
111
+ */
112
+ chaveCache?: string;
113
+ /** "[pesquisa/tabela]" of the citation, e.g. "SIDRA, Tabela 6579 (Estimativas de população)". */
114
+ pesquisa: string;
115
+ /** Dataset identifier within the source (e.g. the SIDRA table code), when there is one. */
116
+ dataset?: string;
117
+ /** Reference period exposed by the source (SIDRA period); null/omitted when not exposed. */
118
+ dataVintage?: string | null;
119
+ /** D2 statistics modes: the server derived aggregates from the raw records. */
120
+ derivado?: {
121
+ nota: string;
122
+ };
123
+ }
124
+ /**
125
+ * Builds the canonical provenance block for one tool response. Citation
126
+ * follows the pattern fixed by the verbatim verification (docs/01):
127
+ * "Fonte: IBGE — [pesquisa/tabela], [URL], extraído em [data]."
128
+ */
129
+ export declare function provenienciaIbge(opts: ProvenienciaIbgeOptions): Provenance;
130
+ /** Fixed derivation note for the D2 statistics modes (estatisticas/agruparPor/topN). */
131
+ export declare const NOTA_DERIVACAO_ESTATISTICAS = "Estat\u00EDsticas (distribui\u00E7\u00E3o, agregados e rankings) computadas pelo servidor a partir dos registros brutos retornados pela fonte; os valores individuais permanecem os originais do IBGE.";
132
+ /**
133
+ * Reference period of a SIDRA-style result, extracted from the standard period
134
+ * column when the source exposes one (docs/03: "período SIDRA quando exposto;
135
+ * null senão"). Distinct values are joined as a deterministic range
136
+ * ("2022" or "2020–2023"); no period column → null.
137
+ */
138
+ export declare function extrairPeriodoSidra(colunas: string[], registros: Array<Record<string, string>>): string | null;
139
+ /** Concise projection of a block (the shape embedded in `structuredContent`/`_meta`). */
140
+ export declare const provenanceBlockSchema: z.ZodObject<{
141
+ source: z.ZodString;
142
+ source_url: z.ZodString;
143
+ data_vintage: z.ZodNullable<z.ZodString>;
144
+ retrieved_at: z.ZodString;
145
+ citation: z.ZodString;
146
+ license: z.ZodNullable<z.ZodString>;
147
+ }, z.core.$strip>;
148
+ /**
149
+ * Extends a tool's output schema with the provenance channel of the contract
150
+ * v1.0: the concise block + the `attribution` URL list (MCP RFC #711). Every
151
+ * successful response carries both (wired in `toMcpResult`).
152
+ */
153
+ export declare function comProveniencia<T extends z.ZodObject<z.ZodRawShape>>(schema: T): z.ZodObject<{
154
+ readonly [x: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
155
+ provenance: z.ZodObject<{
156
+ source: z.ZodString;
157
+ source_url: z.ZodString;
158
+ data_vintage: z.ZodNullable<z.ZodString>;
159
+ retrieved_at: z.ZodString;
160
+ citation: z.ZodString;
161
+ license: z.ZodNullable<z.ZodString>;
162
+ }, z.core.$strip>;
163
+ attribution: z.ZodArray<z.ZodString>;
164
+ }, z.core.$strip>;
165
+ /** Concise projection + attribution list for a block (used by `toMcpResult`). */
166
+ export declare function projetarProveniencia(p: Provenance): {
167
+ provenance: ConciseBlock;
168
+ attribution: string[];
169
+ };
170
+ /** Compact text footer for the Markdown channel (fixed wording, contract v1.0). */
171
+ export declare function rodapeProveniencia(p: Provenance): string;
172
+ //# sourceMappingURL=provenance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../src/provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,YAAY,EAClB,MAAM,0BAA0B,CAAC;AAIlC,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB,sDAK5B,CAAC;AAEH,iDAAiD;AACjD,MAAM,MAAM,UAAU,GAAG,mBAAmB,CAAC;AAE7C,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,QAAwC,CAAC;AACzE,eAAO,MAAM,oBAAoB,QAAyC,CAAC;AAE3E;;;;;GAKG;AACH,eAAO,MAAM,YAAY;;;;;;CAMf,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6Cd,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,WAAW,CAAC;AAajD,MAAM,WAAW,uBAAuB;IACtC,6CAA6C;IAC7C,KAAK,EAAE,SAAS,CAAC;IACjB,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iGAAiG;IACjG,QAAQ,EAAE,MAAM,CAAC;IACjB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4FAA4F;IAC5F,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,GAAG,UAAU,CAiB1E;AAED,wFAAwF;AACxF,eAAO,MAAM,2BAA2B,2MACmJ,CAAC;AAE5L;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACvC,MAAM,GAAG,IAAI,CAYf;AAED,yFAAyF;AACzF,eAAO,MAAM,qBAAqB;;;;;;;iBAYhC,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;;;;;;;;;;;kBAS9E;AAED,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,UAAU,GAAG;IACnD,UAAU,EAAE,YAAY,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAEA;AAED,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAExD"}