iptuapi 1.2.0 → 2.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.
- package/README.md +230 -44
- package/dist/index.d.mts +276 -78
- package/dist/index.d.ts +276 -78
- package/dist/index.js +450 -98
- package/dist/index.mjs +444 -97
- package/package.json +25 -3
package/dist/index.mjs
CHANGED
|
@@ -1,166 +1,513 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
var
|
|
3
|
-
|
|
2
|
+
var CidadeEnum = {
|
|
3
|
+
SAO_PAULO: "sp",
|
|
4
|
+
BELO_HORIZONTE: "bh",
|
|
5
|
+
RECIFE: "recife"
|
|
6
|
+
};
|
|
7
|
+
var IPTUAPIError = class _IPTUAPIError extends Error {
|
|
8
|
+
statusCode;
|
|
9
|
+
requestId;
|
|
10
|
+
responseBody;
|
|
11
|
+
constructor(message, statusCode, requestId, responseBody) {
|
|
4
12
|
super(message);
|
|
5
|
-
this.statusCode = statusCode;
|
|
6
13
|
this.name = "IPTUAPIError";
|
|
14
|
+
this.statusCode = statusCode;
|
|
15
|
+
this.requestId = requestId;
|
|
16
|
+
this.responseBody = responseBody;
|
|
17
|
+
Object.setPrototypeOf(this, _IPTUAPIError.prototype);
|
|
18
|
+
}
|
|
19
|
+
get isRetryable() {
|
|
20
|
+
return this.statusCode ? [429, 500, 502, 503, 504].includes(this.statusCode) : false;
|
|
7
21
|
}
|
|
8
22
|
};
|
|
9
|
-
var AuthenticationError = class extends IPTUAPIError {
|
|
10
|
-
constructor(message = "API Key inv\xE1lida ou expirada") {
|
|
11
|
-
super(message, 401);
|
|
23
|
+
var AuthenticationError = class _AuthenticationError extends IPTUAPIError {
|
|
24
|
+
constructor(message = "API Key inv\xE1lida ou expirada", requestId, responseBody) {
|
|
25
|
+
super(message, 401, requestId, responseBody);
|
|
12
26
|
this.name = "AuthenticationError";
|
|
27
|
+
Object.setPrototypeOf(this, _AuthenticationError.prototype);
|
|
13
28
|
}
|
|
14
29
|
};
|
|
15
|
-
var
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
30
|
+
var ForbiddenError = class _ForbiddenError extends IPTUAPIError {
|
|
31
|
+
requiredPlan;
|
|
32
|
+
constructor(message = "Plano n\xE3o autorizado para este recurso", requiredPlan, requestId, responseBody) {
|
|
33
|
+
super(message, 403, requestId, responseBody);
|
|
34
|
+
this.name = "ForbiddenError";
|
|
35
|
+
this.requiredPlan = requiredPlan;
|
|
36
|
+
Object.setPrototypeOf(this, _ForbiddenError.prototype);
|
|
19
37
|
}
|
|
20
38
|
};
|
|
21
|
-
var NotFoundError = class extends IPTUAPIError {
|
|
22
|
-
constructor(message = "Recurso n\xE3o encontrado") {
|
|
23
|
-
super(message, 404);
|
|
39
|
+
var NotFoundError = class _NotFoundError extends IPTUAPIError {
|
|
40
|
+
constructor(message = "Recurso n\xE3o encontrado", requestId, responseBody) {
|
|
41
|
+
super(message, 404, requestId, responseBody);
|
|
24
42
|
this.name = "NotFoundError";
|
|
43
|
+
Object.setPrototypeOf(this, _NotFoundError.prototype);
|
|
25
44
|
}
|
|
26
45
|
};
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
46
|
+
var RateLimitError = class _RateLimitError extends IPTUAPIError {
|
|
47
|
+
retryAfter;
|
|
48
|
+
limit;
|
|
49
|
+
remaining;
|
|
50
|
+
constructor(message = "Limite de requisi\xE7\xF5es excedido", retryAfter, limit, remaining, requestId, responseBody) {
|
|
51
|
+
super(message, 429, requestId, responseBody);
|
|
52
|
+
this.name = "RateLimitError";
|
|
53
|
+
this.retryAfter = retryAfter;
|
|
54
|
+
this.limit = limit;
|
|
55
|
+
this.remaining = remaining;
|
|
56
|
+
Object.setPrototypeOf(this, _RateLimitError.prototype);
|
|
57
|
+
}
|
|
58
|
+
get isRetryable() {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var ValidationError = class _ValidationError extends IPTUAPIError {
|
|
63
|
+
errors;
|
|
64
|
+
constructor(message = "Par\xE2metros inv\xE1lidos", errors, requestId, responseBody) {
|
|
65
|
+
super(message, 400, requestId, responseBody);
|
|
66
|
+
this.name = "ValidationError";
|
|
67
|
+
this.errors = errors;
|
|
68
|
+
Object.setPrototypeOf(this, _ValidationError.prototype);
|
|
31
69
|
}
|
|
32
70
|
};
|
|
71
|
+
var ServerError = class _ServerError extends IPTUAPIError {
|
|
72
|
+
constructor(message = "Erro interno do servidor", statusCode = 500, requestId, responseBody) {
|
|
73
|
+
super(message, statusCode, requestId, responseBody);
|
|
74
|
+
this.name = "ServerError";
|
|
75
|
+
Object.setPrototypeOf(this, _ServerError.prototype);
|
|
76
|
+
}
|
|
77
|
+
get isRetryable() {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
var TimeoutError = class _TimeoutError extends IPTUAPIError {
|
|
82
|
+
timeoutMs;
|
|
83
|
+
constructor(message = "Timeout na requisi\xE7\xE3o", timeoutMs) {
|
|
84
|
+
super(message, 408);
|
|
85
|
+
this.name = "TimeoutError";
|
|
86
|
+
this.timeoutMs = timeoutMs;
|
|
87
|
+
Object.setPrototypeOf(this, _TimeoutError.prototype);
|
|
88
|
+
}
|
|
89
|
+
get isRetryable() {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var NetworkError = class _NetworkError extends IPTUAPIError {
|
|
94
|
+
originalError;
|
|
95
|
+
constructor(message = "Erro de conex\xE3o com a API", originalError) {
|
|
96
|
+
super(message);
|
|
97
|
+
this.name = "NetworkError";
|
|
98
|
+
this.originalError = originalError;
|
|
99
|
+
Object.setPrototypeOf(this, _NetworkError.prototype);
|
|
100
|
+
}
|
|
101
|
+
get isRetryable() {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
var DEFAULT_RETRY_CONFIG = {
|
|
106
|
+
maxRetries: 3,
|
|
107
|
+
initialDelay: 500,
|
|
108
|
+
maxDelay: 1e4,
|
|
109
|
+
backoffFactor: 2,
|
|
110
|
+
retryableStatuses: [429, 500, 502, 503, 504]
|
|
111
|
+
};
|
|
33
112
|
var IPTUClient = class {
|
|
34
113
|
apiKey;
|
|
35
114
|
baseUrl;
|
|
36
115
|
timeout;
|
|
116
|
+
retryConfig;
|
|
117
|
+
logger;
|
|
118
|
+
logRequests;
|
|
119
|
+
logResponses;
|
|
120
|
+
userAgent;
|
|
121
|
+
_rateLimit;
|
|
122
|
+
_lastRequestId;
|
|
37
123
|
constructor(apiKey, options = {}) {
|
|
124
|
+
if (!apiKey) {
|
|
125
|
+
throw new Error("API Key \xE9 obrigat\xF3ria");
|
|
126
|
+
}
|
|
38
127
|
this.apiKey = apiKey;
|
|
39
128
|
this.baseUrl = options.baseUrl || "https://iptuapi.com.br/api/v1";
|
|
40
129
|
this.timeout = options.timeout || 3e4;
|
|
130
|
+
this.retryConfig = { ...DEFAULT_RETRY_CONFIG, ...options.retry };
|
|
131
|
+
this.logger = options.logger;
|
|
132
|
+
this.logRequests = options.logRequests || false;
|
|
133
|
+
this.logResponses = options.logResponses || false;
|
|
134
|
+
this.userAgent = options.userAgent || "iptuapi-js/2.0.0";
|
|
135
|
+
}
|
|
136
|
+
// ===========================================================================
|
|
137
|
+
// Properties
|
|
138
|
+
// ===========================================================================
|
|
139
|
+
/** Rate limit info from last request */
|
|
140
|
+
get rateLimit() {
|
|
141
|
+
return this._rateLimit;
|
|
142
|
+
}
|
|
143
|
+
/** Request ID from last request (useful for support) */
|
|
144
|
+
get lastRequestId() {
|
|
145
|
+
return this._lastRequestId;
|
|
146
|
+
}
|
|
147
|
+
// ===========================================================================
|
|
148
|
+
// Private Methods
|
|
149
|
+
// ===========================================================================
|
|
150
|
+
log(level, message, ...args) {
|
|
151
|
+
if (this.logger && this.logger[level]) {
|
|
152
|
+
this.logger[level](message, ...args);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
sleep(ms) {
|
|
156
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
157
|
+
}
|
|
158
|
+
calculateDelay(attempt) {
|
|
159
|
+
const delay = this.retryConfig.initialDelay * Math.pow(this.retryConfig.backoffFactor, attempt);
|
|
160
|
+
return Math.min(delay, this.retryConfig.maxDelay);
|
|
161
|
+
}
|
|
162
|
+
extractRateLimit(headers) {
|
|
163
|
+
const limit = headers.get("X-RateLimit-Limit");
|
|
164
|
+
const remaining = headers.get("X-RateLimit-Remaining");
|
|
165
|
+
const reset = headers.get("X-RateLimit-Reset");
|
|
166
|
+
if (limit && remaining && reset) {
|
|
167
|
+
const resetTimestamp = parseInt(reset, 10);
|
|
168
|
+
return {
|
|
169
|
+
limit: parseInt(limit, 10),
|
|
170
|
+
remaining: parseInt(remaining, 10),
|
|
171
|
+
reset: resetTimestamp,
|
|
172
|
+
resetDate: new Date(resetTimestamp * 1e3)
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
177
|
+
async handleErrorResponse(response, requestId) {
|
|
178
|
+
let body = {};
|
|
179
|
+
try {
|
|
180
|
+
body = await response.json();
|
|
181
|
+
} catch {
|
|
182
|
+
body = { detail: response.statusText };
|
|
183
|
+
}
|
|
184
|
+
const message = body.detail || `HTTP ${response.status}`;
|
|
185
|
+
switch (response.status) {
|
|
186
|
+
case 400:
|
|
187
|
+
case 422:
|
|
188
|
+
throw new ValidationError(
|
|
189
|
+
message,
|
|
190
|
+
body.errors,
|
|
191
|
+
requestId,
|
|
192
|
+
body
|
|
193
|
+
);
|
|
194
|
+
case 401:
|
|
195
|
+
throw new AuthenticationError(message, requestId, body);
|
|
196
|
+
case 403:
|
|
197
|
+
throw new ForbiddenError(
|
|
198
|
+
message,
|
|
199
|
+
body.required_plan,
|
|
200
|
+
requestId,
|
|
201
|
+
body
|
|
202
|
+
);
|
|
203
|
+
case 404:
|
|
204
|
+
throw new NotFoundError(message, requestId, body);
|
|
205
|
+
case 429:
|
|
206
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
207
|
+
throw new RateLimitError(
|
|
208
|
+
message,
|
|
209
|
+
retryAfter ? parseInt(retryAfter, 10) : void 0,
|
|
210
|
+
this._rateLimit?.limit,
|
|
211
|
+
this._rateLimit?.remaining,
|
|
212
|
+
requestId,
|
|
213
|
+
body
|
|
214
|
+
);
|
|
215
|
+
case 500:
|
|
216
|
+
case 502:
|
|
217
|
+
case 503:
|
|
218
|
+
case 504:
|
|
219
|
+
throw new ServerError(message, response.status, requestId, body);
|
|
220
|
+
default:
|
|
221
|
+
throw new IPTUAPIError(message, response.status, requestId, body);
|
|
222
|
+
}
|
|
41
223
|
}
|
|
42
224
|
async request(method, endpoint, params, body) {
|
|
43
225
|
const url = new URL(`${this.baseUrl}${endpoint}`);
|
|
44
226
|
if (params) {
|
|
45
227
|
Object.entries(params).forEach(([key, value]) => {
|
|
46
|
-
if (value
|
|
228
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
229
|
+
url.searchParams.append(key, String(value));
|
|
230
|
+
}
|
|
47
231
|
});
|
|
48
232
|
}
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
throw new AuthenticationError();
|
|
68
|
-
case 403:
|
|
69
|
-
throw new ForbiddenError();
|
|
70
|
-
case 404:
|
|
71
|
-
throw new NotFoundError();
|
|
72
|
-
case 429:
|
|
73
|
-
throw new RateLimitError();
|
|
74
|
-
default:
|
|
75
|
-
const errorData = await response.json().catch(() => ({}));
|
|
76
|
-
throw new IPTUAPIError(
|
|
77
|
-
errorData.detail || `Erro na API: ${response.statusText}`,
|
|
78
|
-
response.status
|
|
233
|
+
const headers = {
|
|
234
|
+
"X-API-Key": this.apiKey,
|
|
235
|
+
"Content-Type": "application/json",
|
|
236
|
+
Accept: "application/json",
|
|
237
|
+
"User-Agent": this.userAgent
|
|
238
|
+
};
|
|
239
|
+
let lastError;
|
|
240
|
+
let attempt = 0;
|
|
241
|
+
while (attempt <= this.retryConfig.maxRetries) {
|
|
242
|
+
const controller = new AbortController();
|
|
243
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
244
|
+
try {
|
|
245
|
+
if (this.logRequests) {
|
|
246
|
+
this.log(
|
|
247
|
+
"debug",
|
|
248
|
+
`Request: ${method} ${url}`,
|
|
249
|
+
params ? { params } : {},
|
|
250
|
+
body ? { body } : {}
|
|
79
251
|
);
|
|
252
|
+
}
|
|
253
|
+
const startTime = Date.now();
|
|
254
|
+
const response = await fetch(url.toString(), {
|
|
255
|
+
method,
|
|
256
|
+
headers,
|
|
257
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
258
|
+
signal: controller.signal
|
|
259
|
+
});
|
|
260
|
+
clearTimeout(timeoutId);
|
|
261
|
+
const elapsedMs = Date.now() - startTime;
|
|
262
|
+
this._rateLimit = this.extractRateLimit(response.headers);
|
|
263
|
+
this._lastRequestId = response.headers.get("X-Request-ID") || void 0;
|
|
264
|
+
if (this.logResponses) {
|
|
265
|
+
this.log(
|
|
266
|
+
"debug",
|
|
267
|
+
`Response: ${response.status} ${url} (${elapsedMs}ms)`
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
if (response.ok) {
|
|
271
|
+
return await response.json();
|
|
272
|
+
}
|
|
273
|
+
if (this.retryConfig.retryableStatuses.includes(response.status) && attempt < this.retryConfig.maxRetries) {
|
|
274
|
+
const delay = this.calculateDelay(attempt);
|
|
275
|
+
this.log(
|
|
276
|
+
"warn",
|
|
277
|
+
`Request failed with ${response.status}, retrying in ${delay}ms (attempt ${attempt + 1}/${this.retryConfig.maxRetries})`
|
|
278
|
+
);
|
|
279
|
+
await this.sleep(delay);
|
|
280
|
+
attempt++;
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
await this.handleErrorResponse(response, this._lastRequestId);
|
|
284
|
+
} catch (error) {
|
|
285
|
+
clearTimeout(timeoutId);
|
|
286
|
+
if (error instanceof IPTUAPIError) {
|
|
287
|
+
throw error;
|
|
288
|
+
}
|
|
289
|
+
if (error instanceof Error) {
|
|
290
|
+
if (error.name === "AbortError") {
|
|
291
|
+
lastError = new TimeoutError(
|
|
292
|
+
`Timeout ap\xF3s ${this.timeout}ms`,
|
|
293
|
+
this.timeout
|
|
294
|
+
);
|
|
295
|
+
} else if (error.message.includes("fetch") || error.message.includes("network")) {
|
|
296
|
+
lastError = new NetworkError(
|
|
297
|
+
`Erro de conex\xE3o: ${error.message}`,
|
|
298
|
+
error
|
|
299
|
+
);
|
|
300
|
+
} else {
|
|
301
|
+
lastError = error;
|
|
302
|
+
}
|
|
303
|
+
if (attempt < this.retryConfig.maxRetries) {
|
|
304
|
+
const delay = this.calculateDelay(attempt);
|
|
305
|
+
this.log(
|
|
306
|
+
"warn",
|
|
307
|
+
`Request failed: ${error.message}, retrying in ${delay}ms (attempt ${attempt + 1}/${this.retryConfig.maxRetries})`
|
|
308
|
+
);
|
|
309
|
+
await this.sleep(delay);
|
|
310
|
+
attempt++;
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
throw lastError || error;
|
|
80
315
|
}
|
|
81
|
-
} catch (error) {
|
|
82
|
-
clearTimeout(timeoutId);
|
|
83
|
-
if (error instanceof IPTUAPIError) throw error;
|
|
84
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
85
|
-
throw new IPTUAPIError("Timeout na requisi\xE7\xE3o", 408);
|
|
86
|
-
}
|
|
87
|
-
throw error;
|
|
88
316
|
}
|
|
317
|
+
throw lastError || new IPTUAPIError("Max retries exceeded");
|
|
318
|
+
}
|
|
319
|
+
async consultaEndereco(paramsOrLogradouro, numero, cidade) {
|
|
320
|
+
let params;
|
|
321
|
+
if (typeof paramsOrLogradouro === "string") {
|
|
322
|
+
params = {
|
|
323
|
+
logradouro: paramsOrLogradouro,
|
|
324
|
+
numero,
|
|
325
|
+
cidade: cidade || "sp"
|
|
326
|
+
};
|
|
327
|
+
} else {
|
|
328
|
+
params = {
|
|
329
|
+
logradouro: paramsOrLogradouro.logradouro,
|
|
330
|
+
numero: paramsOrLogradouro.numero,
|
|
331
|
+
complemento: paramsOrLogradouro.complemento,
|
|
332
|
+
cidade: paramsOrLogradouro.cidade || "sp",
|
|
333
|
+
incluir_historico: paramsOrLogradouro.incluirHistorico,
|
|
334
|
+
incluir_comparaveis: paramsOrLogradouro.incluirComparaveis,
|
|
335
|
+
incluir_zoneamento: paramsOrLogradouro.incluirZoneamento
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
return this.request(
|
|
339
|
+
"GET",
|
|
340
|
+
"/consulta/endereco",
|
|
341
|
+
params
|
|
342
|
+
);
|
|
89
343
|
}
|
|
90
344
|
/**
|
|
91
|
-
* Busca dados de IPTU por
|
|
345
|
+
* Busca dados de IPTU por número SQL (contribuinte).
|
|
346
|
+
*
|
|
347
|
+
* @param sql - Número SQL do imóvel
|
|
348
|
+
* @param cidade - Cidade da consulta
|
|
349
|
+
* @param options - Opções adicionais
|
|
350
|
+
* @returns Dados completos do imóvel
|
|
92
351
|
*/
|
|
93
|
-
async
|
|
94
|
-
return this.request("GET",
|
|
95
|
-
|
|
96
|
-
|
|
352
|
+
async consultaSQL(sql, cidade = "sp", options) {
|
|
353
|
+
return this.request("GET", `/consulta/sql/${sql}`, {
|
|
354
|
+
cidade,
|
|
355
|
+
incluir_historico: options?.incluirHistorico,
|
|
356
|
+
incluir_comparaveis: options?.incluirComparaveis
|
|
97
357
|
});
|
|
98
358
|
}
|
|
99
359
|
/**
|
|
100
|
-
* Busca
|
|
360
|
+
* Busca imóveis por CEP.
|
|
361
|
+
*
|
|
362
|
+
* @param cep - CEP do imóvel
|
|
363
|
+
* @param cidade - Cidade da consulta
|
|
364
|
+
* @returns Lista de imóveis no CEP
|
|
101
365
|
*/
|
|
102
|
-
async
|
|
103
|
-
|
|
366
|
+
async consultaCEP(cep, cidade = "sp") {
|
|
367
|
+
const cleanCep = cep.replace(/\D/g, "");
|
|
368
|
+
return this.request(
|
|
369
|
+
"GET",
|
|
370
|
+
`/consulta/cep/${cleanCep}`,
|
|
371
|
+
{ cidade }
|
|
372
|
+
);
|
|
104
373
|
}
|
|
105
374
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* @param
|
|
109
|
-
* @param
|
|
110
|
-
* @
|
|
111
|
-
* @param limit - Limite de resultados (default: 20)
|
|
375
|
+
* Consulta zoneamento por coordenadas.
|
|
376
|
+
*
|
|
377
|
+
* @param latitude - Latitude do ponto
|
|
378
|
+
* @param longitude - Longitude do ponto
|
|
379
|
+
* @returns Dados de zoneamento
|
|
112
380
|
*/
|
|
113
|
-
async
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
381
|
+
async consultaZoneamento(latitude, longitude) {
|
|
382
|
+
return this.request("GET", "/consulta/zoneamento", {
|
|
383
|
+
latitude,
|
|
384
|
+
longitude
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
// ===========================================================================
|
|
388
|
+
// Valuation Endpoints (Pro+)
|
|
389
|
+
// ===========================================================================
|
|
390
|
+
/**
|
|
391
|
+
* Estima o valor de mercado do imóvel usando ML.
|
|
392
|
+
* Disponível apenas para planos Pro e Enterprise.
|
|
393
|
+
*
|
|
394
|
+
* @param params - Parâmetros do imóvel
|
|
395
|
+
* @returns Estimativa de valor
|
|
396
|
+
* @throws {ForbiddenError} Se o plano não permitir
|
|
397
|
+
*/
|
|
398
|
+
async valuationEstimate(params) {
|
|
399
|
+
return this.request(
|
|
400
|
+
"POST",
|
|
401
|
+
"/valuation/estimate",
|
|
402
|
+
void 0,
|
|
403
|
+
{
|
|
404
|
+
area_terreno: params.area_terreno,
|
|
405
|
+
area_construida: params.area_construida,
|
|
406
|
+
bairro: params.bairro,
|
|
407
|
+
zona: params.zona,
|
|
408
|
+
tipo_uso: params.tipo_uso,
|
|
409
|
+
tipo_padrao: params.tipo_padrao,
|
|
410
|
+
ano_construcao: params.ano_construcao,
|
|
411
|
+
cidade: params.cidade || "sp"
|
|
412
|
+
}
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Valuation em lote (até 100 imóveis).
|
|
417
|
+
* Disponível apenas para plano Enterprise.
|
|
418
|
+
*
|
|
419
|
+
* @param imoveis - Lista de imóveis para avaliar
|
|
420
|
+
* @returns Resultados de valuation para cada imóvel
|
|
421
|
+
*/
|
|
422
|
+
async valuationBatch(imoveis) {
|
|
423
|
+
return this.request(
|
|
424
|
+
"POST",
|
|
425
|
+
"/valuation/estimate/batch",
|
|
426
|
+
void 0,
|
|
427
|
+
{ imoveis }
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Busca imóveis comparáveis para análise.
|
|
432
|
+
*
|
|
433
|
+
* @param bairro - Nome do bairro
|
|
434
|
+
* @param areaMin - Área mínima em m²
|
|
435
|
+
* @param areaMax - Área máxima em m²
|
|
436
|
+
* @param options - Opções adicionais
|
|
437
|
+
* @returns Lista de imóveis comparáveis
|
|
438
|
+
*/
|
|
439
|
+
async valuationComparables(bairro, areaMin, areaMax, options) {
|
|
440
|
+
return this.request("GET", "/valuation/comparables", {
|
|
441
|
+
bairro,
|
|
442
|
+
area_min: areaMin,
|
|
443
|
+
area_max: areaMax,
|
|
444
|
+
tipo_uso: options?.tipoUso,
|
|
445
|
+
cidade: options?.cidade || "sp",
|
|
446
|
+
limit: options?.limit || 10
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
// ===========================================================================
|
|
450
|
+
// Dados Endpoints
|
|
451
|
+
// ===========================================================================
|
|
452
|
+
/**
|
|
453
|
+
* Histórico de valores IPTU de um imóvel.
|
|
454
|
+
*
|
|
455
|
+
* @param sql - Número SQL do imóvel
|
|
456
|
+
* @param cidade - Cidade da consulta
|
|
457
|
+
* @returns Lista com histórico anual
|
|
458
|
+
*/
|
|
459
|
+
async dadosIPTUHistorico(sql, cidade = "sp") {
|
|
122
460
|
return this.request(
|
|
123
461
|
"GET",
|
|
124
|
-
`/dados/iptu/${
|
|
125
|
-
|
|
462
|
+
`/dados/iptu/historico/${sql}`,
|
|
463
|
+
{ cidade }
|
|
126
464
|
);
|
|
127
465
|
}
|
|
128
466
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* @param
|
|
132
|
-
* @
|
|
467
|
+
* Consulta dados de empresa por CNPJ.
|
|
468
|
+
*
|
|
469
|
+
* @param cnpj - CNPJ da empresa
|
|
470
|
+
* @returns Dados cadastrais
|
|
133
471
|
*/
|
|
134
|
-
async
|
|
135
|
-
const
|
|
136
|
-
if (ano !== void 0) {
|
|
137
|
-
params.ano = ano.toString();
|
|
138
|
-
}
|
|
472
|
+
async dadosCNPJ(cnpj) {
|
|
473
|
+
const cleanCnpj = cnpj.replace(/\D/g, "");
|
|
139
474
|
return this.request(
|
|
140
475
|
"GET",
|
|
141
|
-
`/dados/
|
|
142
|
-
params
|
|
476
|
+
`/dados/cnpj/${cleanCnpj}`
|
|
143
477
|
);
|
|
144
478
|
}
|
|
145
479
|
/**
|
|
146
|
-
*
|
|
480
|
+
* Correção monetária pelo IPCA.
|
|
481
|
+
*
|
|
482
|
+
* @param valor - Valor a corrigir
|
|
483
|
+
* @param dataOrigem - Data do valor original (YYYY-MM)
|
|
484
|
+
* @param dataDestino - Data destino (default: atual)
|
|
485
|
+
* @returns Valor corrigido e fator de correção
|
|
147
486
|
*/
|
|
148
|
-
async
|
|
487
|
+
async dadosIPCACorrigir(valor, dataOrigem, dataDestino) {
|
|
149
488
|
return this.request(
|
|
150
|
-
"
|
|
151
|
-
"/
|
|
152
|
-
|
|
153
|
-
|
|
489
|
+
"GET",
|
|
490
|
+
"/dados/ipca/corrigir",
|
|
491
|
+
{
|
|
492
|
+
valor,
|
|
493
|
+
data_origem: dataOrigem,
|
|
494
|
+
data_destino: dataDestino
|
|
495
|
+
}
|
|
154
496
|
);
|
|
155
497
|
}
|
|
156
498
|
};
|
|
157
499
|
var index_default = IPTUClient;
|
|
158
500
|
export {
|
|
159
501
|
AuthenticationError,
|
|
502
|
+
CidadeEnum,
|
|
160
503
|
ForbiddenError,
|
|
161
504
|
IPTUAPIError,
|
|
162
505
|
IPTUClient,
|
|
506
|
+
NetworkError,
|
|
163
507
|
NotFoundError,
|
|
164
508
|
RateLimitError,
|
|
509
|
+
ServerError,
|
|
510
|
+
TimeoutError,
|
|
511
|
+
ValidationError,
|
|
165
512
|
index_default as default
|
|
166
513
|
};
|
package/package.json
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iptuapi",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "SDK oficial para a IPTU API - Dados de IPTU de São Paulo, Belo Horizonte e Recife",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
8
15
|
"files": [
|
|
9
16
|
"dist"
|
|
10
17
|
],
|
|
11
18
|
"scripts": {
|
|
12
19
|
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:watch": "vitest",
|
|
22
|
+
"test:coverage": "vitest run --coverage",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"lint": "eslint src tests",
|
|
13
25
|
"prepublishOnly": "npm run build"
|
|
14
26
|
},
|
|
15
27
|
"keywords": [
|
|
@@ -20,7 +32,10 @@
|
|
|
20
32
|
"recife",
|
|
21
33
|
"imóveis",
|
|
22
34
|
"dados",
|
|
23
|
-
"
|
|
35
|
+
"real estate",
|
|
36
|
+
"property",
|
|
37
|
+
"typescript",
|
|
38
|
+
"sdk"
|
|
24
39
|
],
|
|
25
40
|
"author": "IPTU API <contato@iptuapi.com.br>",
|
|
26
41
|
"license": "MIT",
|
|
@@ -29,9 +44,16 @@
|
|
|
29
44
|
"url": "https://github.com/iptuapi/iptuapi-js"
|
|
30
45
|
},
|
|
31
46
|
"homepage": "https://iptuapi.com.br",
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/iptuapi/iptuapi-js/issues"
|
|
49
|
+
},
|
|
32
50
|
"devDependencies": {
|
|
51
|
+
"@types/node": "^20.10.0",
|
|
52
|
+
"@vitest/coverage-v8": "^1.0.0",
|
|
53
|
+
"msw": "^2.0.0",
|
|
33
54
|
"tsup": "^8.0.0",
|
|
34
|
-
"typescript": "^5.3.0"
|
|
55
|
+
"typescript": "^5.3.0",
|
|
56
|
+
"vitest": "^1.0.0"
|
|
35
57
|
},
|
|
36
58
|
"engines": {
|
|
37
59
|
"node": ">=18"
|