brasil-ceps-offline 2.1.3 → 2.1.5
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/README.md +48 -0
- package/dist/bin/cli.js +3 -2
- package/dist/config.d.ts +1 -20
- package/dist/config.js +36 -21
- package/dist/index.d.ts +1 -0
- package/dist/index.js +50 -4
- package/dist/scripts/download-db.d.ts +1 -1
- package/dist/scripts/download-db.js +37 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -148,6 +148,54 @@ import type {
|
|
|
148
148
|
|
|
149
149
|
---
|
|
150
150
|
|
|
151
|
+
## ☁️ Deploy na Vercel / Next.js
|
|
152
|
+
|
|
153
|
+
A Vercel não executa `postinstall` durante o build de produção por padrão. Siga os passos abaixo para garantir que o banco de dados seja baixado antes do deploy.
|
|
154
|
+
|
|
155
|
+
### 1. Adicione o sync ao script de build (`package.json`)
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"scripts": {
|
|
160
|
+
"build": "npx brasil-ceps-offline sync ./public/.db && next build"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 2. Inclua o banco no rastreamento de arquivos (`next.config.js`)
|
|
166
|
+
|
|
167
|
+
O Next.js usa **Output File Tracing** para empacotar apenas os arquivos necessários. O SQLite precisa ser incluído explicitamente:
|
|
168
|
+
|
|
169
|
+
```js
|
|
170
|
+
// next.config.js
|
|
171
|
+
/** @type {import('next').NextConfig} */
|
|
172
|
+
const nextConfig = {
|
|
173
|
+
experimental: {
|
|
174
|
+
outputFileTracingIncludes: {
|
|
175
|
+
// Inclui o banco para todas as rotas da API
|
|
176
|
+
'/api/**': [
|
|
177
|
+
'./public/.db/**',
|
|
178
|
+
'./node_modules/brasil-ceps-offline/.db/**',
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
module.exports = nextConfig;
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 3. Variável de ambiente (opcional)
|
|
188
|
+
|
|
189
|
+
Se preferir armazenar o banco fora de `node_modules` (ex: em `/tmp` na Vercel):
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
BRASIL_CEPS_DB_PATH=/tmp/ceps.sqlite
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
> **Atenção:** O diretório `/tmp` na Vercel é efêmero — o banco precisará ser baixado a cada cold start. Para produção de alta disponibilidade, use o caminho padrão via `node_modules`.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
151
199
|
## ⚖️ Licença e Fonte dos Dados
|
|
152
200
|
|
|
153
201
|
**Código fonte:** MIT License
|
package/dist/bin/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ function printHelp() {
|
|
|
15
15
|
brasil-ceps-offline — CLI de gerenciamento do banco de dados
|
|
16
16
|
|
|
17
17
|
Uso:
|
|
18
|
-
npx brasil-ceps-offline <comando>
|
|
18
|
+
npx brasil-ceps-offline <comando> [destino]
|
|
19
19
|
|
|
20
20
|
Comandos:
|
|
21
21
|
sync Baixa ou atualiza o banco de dados para a versão mais recente
|
|
@@ -24,6 +24,7 @@ Comandos:
|
|
|
24
24
|
|
|
25
25
|
Exemplos:
|
|
26
26
|
npx brasil-ceps-offline sync
|
|
27
|
+
npx brasil-ceps-offline sync ./public/.db
|
|
27
28
|
npx brasil-ceps-offline status
|
|
28
29
|
`.trim());
|
|
29
30
|
}
|
|
@@ -58,7 +59,7 @@ async function main() {
|
|
|
58
59
|
const command = (process.argv[2] ?? 'help');
|
|
59
60
|
switch (command) {
|
|
60
61
|
case 'sync':
|
|
61
|
-
await (0, download_db_1.downloadDatabase)();
|
|
62
|
+
await (0, download_db_1.downloadDatabase)(process.argv[3]);
|
|
62
63
|
break;
|
|
63
64
|
case 'status':
|
|
64
65
|
printStatus();
|
package/dist/config.d.ts
CHANGED
|
@@ -1,21 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* Caminho para o banco de dados SQLite
|
|
3
|
-
*/
|
|
1
|
+
export declare const DB_DIR: string;
|
|
4
2
|
export declare const DB_PATH: string;
|
|
5
|
-
/**
|
|
6
|
-
* URL padrão para download do banco de dados (GitHub Releases)
|
|
7
|
-
* NOTA: Você precisa substituir isso pela URL real do seu repositório
|
|
8
|
-
*/
|
|
9
|
-
export declare const DEFAULT_DOWNLOAD_URL: string;
|
|
10
|
-
/**
|
|
11
|
-
* Timeout para downloads (30 segundos)
|
|
12
|
-
*/
|
|
13
|
-
export declare const DOWNLOAD_TIMEOUT: number;
|
|
14
|
-
/**
|
|
15
|
-
* Tamanho máximo de chunk para downloads (1MB)
|
|
16
|
-
*/
|
|
17
|
-
export declare const CHUNK_SIZE: number;
|
|
18
|
-
/**
|
|
19
|
-
* Número de tentativas de retry para download
|
|
20
|
-
*/
|
|
21
|
-
export declare const MAX_RETRIES = 3;
|
package/dist/config.js
CHANGED
|
@@ -3,27 +3,42 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.DB_PATH = exports.DB_DIR = void 0;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
9
|
/**
|
|
9
|
-
*
|
|
10
|
+
* Resolve o diretório `.db` tentando múltiplos candidatos em ordem de prioridade.
|
|
11
|
+
*
|
|
12
|
+
* Prioridade:
|
|
13
|
+
* 1. Vercel / Next.js build — `<cwd>/node_modules/brasil-ceps-offline/.db`
|
|
14
|
+
* 2. Instalação npm padrão — dois níveis acima de `dist/scripts/` → `<pkg>/.db`
|
|
15
|
+
* 3. Desenvolvimento local — um nível acima de `dist/` → `<pkg>/.db`
|
|
16
|
+
* 4. Variável de ambiente — `BRASIL_CEPS_DB_PATH` (caminho completo para o .sqlite)
|
|
17
|
+
*
|
|
18
|
+
* Retorna o primeiro diretório que já contenha `ceps.sqlite`, ou o caminho
|
|
19
|
+
* do candidato nº 1 como destino de instalação quando nenhum arquivo existe ainda.
|
|
10
20
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
function resolveDbDir() {
|
|
22
|
+
// Permite override total via env (útil em deploys customizados)
|
|
23
|
+
if (process.env.BRASIL_CEPS_DB_PATH) {
|
|
24
|
+
return path_1.default.dirname(process.env.BRASIL_CEPS_DB_PATH);
|
|
25
|
+
}
|
|
26
|
+
const candidates = [
|
|
27
|
+
// 1. Vercel/Next (cwd = raiz do projeto do usuário)
|
|
28
|
+
path_1.default.join(process.cwd(), 'node_modules', 'brasil-ceps-offline', '.db'),
|
|
29
|
+
// 2. npm install padrão: dist/scripts/ → ../../.db
|
|
30
|
+
path_1.default.join(__dirname, '..', '..', '.db'),
|
|
31
|
+
// 3. Fallback: dist/ → ../.db
|
|
32
|
+
path_1.default.join(__dirname, '..', '.db'),
|
|
33
|
+
];
|
|
34
|
+
// Retorna o primeiro candidato que já tem o banco instalado
|
|
35
|
+
for (const dir of candidates) {
|
|
36
|
+
if (fs_1.default.existsSync(path_1.default.join(dir, 'ceps.sqlite'))) {
|
|
37
|
+
return dir;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Nenhum banco encontrado → usa o candidato nº 1 como destino de instalação
|
|
41
|
+
return candidates[0];
|
|
42
|
+
}
|
|
43
|
+
exports.DB_DIR = resolveDbDir();
|
|
44
|
+
exports.DB_PATH = process.env.BRASIL_CEPS_DB_PATH ?? path_1.default.join(exports.DB_DIR, 'ceps.sqlite');
|
package/dist/index.d.ts
CHANGED
|
@@ -129,4 +129,5 @@ export declare function getCepsInRadius(centerCep: string, radiusKm: number, lim
|
|
|
129
129
|
export declare function getTimezone(cep: string): TimezoneResult | null;
|
|
130
130
|
/** Valida se o código IBGE informado corresponde ao CEP. */
|
|
131
131
|
export declare function validateIbge(cep: string, ibgeProvided: number): IbgeValidationResult | null;
|
|
132
|
+
export { downloadDatabase } from './scripts/download-db';
|
|
132
133
|
export type { Address, DistanceResult, AddressWithDistance, TimezoneResult, IbgeValidationResult, Coordinates, FallbackOptions, BrasilCepsConfig, } from './types';
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.brasilCeps = exports.BrasilCepsOffline = void 0;
|
|
6
|
+
exports.downloadDatabase = exports.brasilCeps = exports.BrasilCepsOffline = void 0;
|
|
7
7
|
exports.init = init;
|
|
8
8
|
exports.findByCep = findByCep;
|
|
9
9
|
exports.findByAddress = findByAddress;
|
|
@@ -13,12 +13,48 @@ exports.getCepsInRadius = getCepsInRadius;
|
|
|
13
13
|
exports.getTimezone = getTimezone;
|
|
14
14
|
exports.validateIbge = validateIbge;
|
|
15
15
|
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
16
|
-
const
|
|
16
|
+
const fs_1 = __importDefault(require("fs"));
|
|
17
|
+
const path_1 = __importDefault(require("path"));
|
|
17
18
|
const database_1 = require("./database");
|
|
18
19
|
const SELECT_ALL = `
|
|
19
20
|
cep, state, city, neighborhood, street,
|
|
20
21
|
ibge, ddd, timezone, latitude, longitude
|
|
21
22
|
`;
|
|
23
|
+
function log(msg) { console.log(`[brasil-ceps-offline] ${msg}`); }
|
|
24
|
+
function resolveDatabasePath() {
|
|
25
|
+
const envPath = process.env.BRASIL_CEPS_DB_PATH;
|
|
26
|
+
if (envPath) {
|
|
27
|
+
if (!fs_1.default.existsSync(envPath)) {
|
|
28
|
+
throw new Error(`BRASIL_CEPS_DB_PATH definido, mas arquivo não existe: ${envPath}`);
|
|
29
|
+
}
|
|
30
|
+
return { dbPath: envPath, mode: 'env' };
|
|
31
|
+
}
|
|
32
|
+
const candidates = [
|
|
33
|
+
{
|
|
34
|
+
mode: 'serverless',
|
|
35
|
+
dbPath: path_1.default.join(process.cwd(), 'public', '.db', 'ceps.sqlite'),
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
mode: 'node',
|
|
39
|
+
dbPath: path_1.default.join(process.cwd(), 'node_modules', 'brasil-ceps-offline', '.db', 'ceps.sqlite'),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
mode: 'relative',
|
|
43
|
+
dbPath: path_1.default.join(__dirname, '..', '..', '.db', 'ceps.sqlite'),
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
mode: 'cwd',
|
|
47
|
+
dbPath: path_1.default.join(process.cwd(), '.db', 'ceps.sqlite'),
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
for (const candidate of candidates) {
|
|
51
|
+
if (fs_1.default.existsSync(candidate.dbPath))
|
|
52
|
+
return candidate;
|
|
53
|
+
}
|
|
54
|
+
const tried = candidates.map((c) => `- ${c.dbPath}`).join('\n');
|
|
55
|
+
throw new Error(`Banco de dados não encontrado. Caminhos testados:\n${tried}\n` +
|
|
56
|
+
`Execute "npx brasil-ceps-offline sync" (Node) ou "npx brasil-ceps-offline sync ./public/.db" (Vercel/Next).`);
|
|
57
|
+
}
|
|
22
58
|
/**
|
|
23
59
|
* Motor de Inteligência Geográfica Offline para CEPs brasileiros.
|
|
24
60
|
* Dados do Censo IBGE 2022 — sem rede, sem API keys, sem limites.
|
|
@@ -42,13 +78,21 @@ class BrasilCepsOffline {
|
|
|
42
78
|
initialize(_config) {
|
|
43
79
|
if (this.isInitialized)
|
|
44
80
|
return;
|
|
81
|
+
const { dbPath, mode } = resolveDatabasePath();
|
|
82
|
+
if (mode === 'serverless') {
|
|
83
|
+
log(`Modo Serverless detectado. Usando banco em ${path_1.default.join(process.cwd(), 'public', '.db')}`);
|
|
84
|
+
}
|
|
45
85
|
try {
|
|
46
|
-
|
|
86
|
+
// Valida explicitamente antes de instanciar o better-sqlite3 (evita erros opacos em serverless)
|
|
87
|
+
if (!fs_1.default.existsSync(dbPath)) {
|
|
88
|
+
throw new Error(`Arquivo não existe: ${dbPath}`);
|
|
89
|
+
}
|
|
90
|
+
this.db = new better_sqlite3_1.default(dbPath, { readonly: true, fileMustExist: true });
|
|
47
91
|
this.db.pragma('cache_size = -32000'); // 32 MB cache
|
|
48
92
|
this.isInitialized = true;
|
|
49
93
|
}
|
|
50
94
|
catch (error) {
|
|
51
|
-
throw new Error(`Falha ao abrir o banco de dados em [${
|
|
95
|
+
throw new Error(`Falha ao abrir o banco de dados em [${dbPath}]: ${error}`);
|
|
52
96
|
}
|
|
53
97
|
}
|
|
54
98
|
/**
|
|
@@ -400,3 +444,5 @@ function validateIbge(cep, ibgeProvided) {
|
|
|
400
444
|
exports.brasilCeps.initialize();
|
|
401
445
|
return exports.brasilCeps.validateIbge(cep, ibgeProvided);
|
|
402
446
|
}
|
|
447
|
+
var download_db_1 = require("./scripts/download-db");
|
|
448
|
+
Object.defineProperty(exports, "downloadDatabase", { enumerable: true, get: function () { return download_db_1.downloadDatabase; } });
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare function downloadDatabase(): Promise<void>;
|
|
1
|
+
declare function downloadDatabase(customPath?: string): Promise<void>;
|
|
2
2
|
export { downloadDatabase };
|
|
@@ -9,6 +9,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const promises_1 = require("stream/promises");
|
|
10
10
|
const stream_1 = require("stream");
|
|
11
11
|
const zlib_1 = __importDefault(require("zlib"));
|
|
12
|
+
const config_1 = require("../config");
|
|
12
13
|
// ─── Constantes ──────────────────────────────────────────────────────────────
|
|
13
14
|
const REPO = 'kaique-oliveira/brasil-ceps-offline';
|
|
14
15
|
const ASSET_NAME = 'brasil-ceps.sqlite.gz';
|
|
@@ -16,32 +17,30 @@ const GITHUB_API = `https://api.github.com/repos/${REPO}/releases/latest`;
|
|
|
16
17
|
/** URL estática de fallback — usada se a API do GitHub falhar ou atingir rate limit. */
|
|
17
18
|
const FALLBACK_URL = `https://github.com/${REPO}/releases/download/v2.0.5/${ASSET_NAME}`;
|
|
18
19
|
const USER_AGENT = 'brasil-ceps-offline-installer';
|
|
19
|
-
const DB_DIR = path_1.default.join(__dirname, '..', '..', '.db');
|
|
20
|
-
const DB_PATH = path_1.default.join(DB_DIR, 'ceps.sqlite');
|
|
21
|
-
const VERSION_FILE = path_1.default.join(DB_DIR, 'version.json');
|
|
22
20
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
23
21
|
function log(msg) { console.log(`[brasil-ceps-offline] ${msg}`); }
|
|
24
22
|
function warn(msg) { console.warn(`[brasil-ceps-offline] ⚠️ ${msg}`); }
|
|
25
|
-
function readVersionCache() {
|
|
23
|
+
function readVersionCache(versionFile) {
|
|
26
24
|
try {
|
|
27
|
-
if (!fs_1.default.existsSync(
|
|
25
|
+
if (!fs_1.default.existsSync(versionFile))
|
|
28
26
|
return null;
|
|
29
|
-
return JSON.parse(fs_1.default.readFileSync(
|
|
27
|
+
return JSON.parse(fs_1.default.readFileSync(versionFile, 'utf-8'));
|
|
30
28
|
}
|
|
31
29
|
catch {
|
|
32
30
|
return null;
|
|
33
31
|
}
|
|
34
32
|
}
|
|
35
|
-
function writeVersionCache(tag) {
|
|
33
|
+
function writeVersionCache(versionFile, tag) {
|
|
36
34
|
const data = { tag, downloadedAt: new Date().toISOString() };
|
|
37
|
-
fs_1.default.writeFileSync(
|
|
35
|
+
fs_1.default.writeFileSync(versionFile, JSON.stringify(data, null, 2));
|
|
38
36
|
}
|
|
39
|
-
function hasValidSchema() {
|
|
37
|
+
function hasValidSchema(dbPath) {
|
|
40
38
|
try {
|
|
41
|
-
if (!fs_1.default.existsSync(
|
|
39
|
+
if (!fs_1.default.existsSync(dbPath))
|
|
42
40
|
return false;
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
43
42
|
const Database = require('better-sqlite3');
|
|
44
|
-
const db = new Database(
|
|
43
|
+
const db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
|
45
44
|
const cols = db.pragma('table_info(addresses)');
|
|
46
45
|
db.close();
|
|
47
46
|
return cols.some((c) => c.name === 'timezone');
|
|
@@ -51,10 +50,6 @@ function hasValidSchema() {
|
|
|
51
50
|
}
|
|
52
51
|
}
|
|
53
52
|
// ─── Descoberta dinâmica do release ──────────────────────────────────────────
|
|
54
|
-
/**
|
|
55
|
-
* Tarefa 1: Consulta a API do GitHub para descobrir a tag e URL do asset mais recente.
|
|
56
|
-
* Tarefa 3: Retorna null em caso de falha (rate limit, rede, etc.) — o chamador usa o fallback.
|
|
57
|
-
*/
|
|
58
53
|
async function fetchLatestRelease() {
|
|
59
54
|
try {
|
|
60
55
|
log('Consultando GitHub API para release mais recente...');
|
|
@@ -88,7 +83,7 @@ async function fetchLatestRelease() {
|
|
|
88
83
|
}
|
|
89
84
|
}
|
|
90
85
|
// ─── Download e descompactação ────────────────────────────────────────────────
|
|
91
|
-
async function downloadAndExtract(url) {
|
|
86
|
+
async function downloadAndExtract(url, dbPath) {
|
|
92
87
|
log(`Baixando banco de dados de: ${url}`);
|
|
93
88
|
const res = await fetch(url, {
|
|
94
89
|
headers: { 'User-Agent': USER_AGENT },
|
|
@@ -98,64 +93,64 @@ async function downloadAndExtract(url) {
|
|
|
98
93
|
if (!res.body)
|
|
99
94
|
throw new Error('Corpo da resposta vazio.');
|
|
100
95
|
const nodeStream = stream_1.Readable.fromWeb(res.body);
|
|
101
|
-
const fileStream = fs_1.default.createWriteStream(
|
|
96
|
+
const fileStream = fs_1.default.createWriteStream(dbPath);
|
|
102
97
|
await (0, promises_1.pipeline)(nodeStream, zlib_1.default.createGunzip(), fileStream);
|
|
103
98
|
log('Banco descompactado com sucesso.');
|
|
104
99
|
}
|
|
105
100
|
// ─── Ponto de entrada ─────────────────────────────────────────────────────────
|
|
106
|
-
async function downloadDatabase() {
|
|
101
|
+
async function downloadDatabase(customPath) {
|
|
107
102
|
if (process.env.SKIP_POSTINSTALL_DB === 'true') {
|
|
108
103
|
log('CI/CD detectado (SKIP_POSTINSTALL_DB=true). Pulando download.');
|
|
109
104
|
return;
|
|
110
105
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
106
|
+
const dbDir = customPath ? path_1.default.resolve(customPath) : config_1.DB_DIR;
|
|
107
|
+
const dbPath = customPath ? path_1.default.join(dbDir, 'ceps.sqlite') : config_1.DB_PATH;
|
|
108
|
+
const versionFile = path_1.default.join(dbDir, 'version.json');
|
|
109
|
+
// Garante que o diretório existe antes de qualquer operação
|
|
110
|
+
if (!fs_1.default.existsSync(dbDir))
|
|
111
|
+
fs_1.default.mkdirSync(dbDir, { recursive: true });
|
|
112
|
+
log(`Banco será instalado em: ${dbPath}`);
|
|
114
113
|
const release = await fetchLatestRelease();
|
|
115
114
|
const tag = release?.tag ?? 'fallback';
|
|
116
115
|
const downloadUrl = release?.downloadUrl ?? FALLBACK_URL;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (cache && cache.tag === tag && tag !== 'fallback' && hasValidSchema()) {
|
|
116
|
+
const cache = readVersionCache(versionFile);
|
|
117
|
+
if (cache && cache.tag === tag && tag !== 'fallback' && hasValidSchema(dbPath)) {
|
|
120
118
|
log(`Banco já está na versão mais recente (${tag}). Download ignorado.`);
|
|
121
119
|
return;
|
|
122
120
|
}
|
|
123
121
|
if (cache && cache.tag !== tag && tag !== 'fallback') {
|
|
124
122
|
log(`Nova versão disponível: ${cache.tag} → ${tag}. Atualizando banco...`);
|
|
125
|
-
if (fs_1.default.existsSync(
|
|
126
|
-
fs_1.default.unlinkSync(
|
|
123
|
+
if (fs_1.default.existsSync(dbPath))
|
|
124
|
+
fs_1.default.unlinkSync(dbPath);
|
|
127
125
|
}
|
|
128
|
-
else if (!hasValidSchema()) {
|
|
126
|
+
else if (!hasValidSchema(dbPath)) {
|
|
129
127
|
log('Banco ausente ou com schema desatualizado. Iniciando download...');
|
|
130
|
-
if (fs_1.default.existsSync(
|
|
131
|
-
fs_1.default.unlinkSync(
|
|
128
|
+
if (fs_1.default.existsSync(dbPath))
|
|
129
|
+
fs_1.default.unlinkSync(dbPath);
|
|
132
130
|
}
|
|
133
131
|
try {
|
|
134
|
-
await downloadAndExtract(downloadUrl);
|
|
135
|
-
// Grava cache de versão apenas quando obteve tag real da API
|
|
132
|
+
await downloadAndExtract(downloadUrl, dbPath);
|
|
136
133
|
if (tag !== 'fallback') {
|
|
137
|
-
writeVersionCache(tag);
|
|
138
|
-
log(`Versão ${tag} salva em ${
|
|
134
|
+
writeVersionCache(versionFile, tag);
|
|
135
|
+
log(`Versão ${tag} salva em ${versionFile}.`);
|
|
139
136
|
}
|
|
140
137
|
log('🚀 Banco de dados pronto. Zero-latência ativada.');
|
|
141
138
|
}
|
|
142
139
|
catch (err) {
|
|
143
|
-
// Se a URL principal falhou e já era o fallback, propaga o erro
|
|
144
140
|
if (downloadUrl === FALLBACK_URL) {
|
|
145
|
-
if (fs_1.default.existsSync(
|
|
146
|
-
fs_1.default.unlinkSync(
|
|
141
|
+
if (fs_1.default.existsSync(dbPath))
|
|
142
|
+
fs_1.default.unlinkSync(dbPath);
|
|
147
143
|
throw new Error(`Falha no download (incluindo fallback): ${err.message}`);
|
|
148
144
|
}
|
|
149
|
-
// URL dinâmica falhou → tenta o fallback estático
|
|
150
145
|
warn(`Download falhou: ${err.message}. Tentando URL de fallback...`);
|
|
151
|
-
if (fs_1.default.existsSync(
|
|
152
|
-
fs_1.default.unlinkSync(
|
|
153
|
-
await downloadAndExtract(FALLBACK_URL);
|
|
146
|
+
if (fs_1.default.existsSync(dbPath))
|
|
147
|
+
fs_1.default.unlinkSync(dbPath);
|
|
148
|
+
await downloadAndExtract(FALLBACK_URL, dbPath);
|
|
154
149
|
log('🚀 Banco de dados instalado via fallback.');
|
|
155
150
|
}
|
|
156
151
|
}
|
|
157
|
-
// Executa automaticamente
|
|
158
|
-
// Quando importado
|
|
152
|
+
// Executa automaticamente quando invocado diretamente (postinstall).
|
|
153
|
+
// Quando importado como módulo (CLI, testes), não executa.
|
|
159
154
|
if (require.main === module) {
|
|
160
155
|
downloadDatabase().catch((err) => {
|
|
161
156
|
console.error(`[brasil-ceps-offline] ❌ Erro crítico no instalador: ${err.message}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brasil-ceps-offline",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.5",
|
|
4
4
|
"description": "Motor de Inteligência Geográfica Offline para CEPs brasileiros — dados do Censo IBGE 2022 com IBGE, DDD, fuso horário e coordenadas",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|