reddb-sdk 1.0.3 → 1.0.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.
Files changed (2) hide show
  1. package/lib/RedDBClient.js +72 -16
  2. package/package.json +1 -1
@@ -1,34 +1,71 @@
1
1
  const fetch = require('node-fetch');
2
2
 
3
3
  class RedDBClient {
4
- constructor(baseURL, reddbPassword, adminPassword = null) {
4
+ constructor(baseURL, reddbPassword, adminPassword = null, options = {}) {
5
+ if (!baseURL) throw new Error('baseURL é obrigatório');
6
+
5
7
  this.baseURL = baseURL.replace(/\/$/, '');
6
8
  this.reddbPassword = reddbPassword;
7
9
  this.adminPassword = adminPassword;
10
+
11
+ this.timeout = options.timeout || 5000;
12
+ this.retries = options.retries ?? 2;
13
+ this.debug = options.debug || false;
14
+ }
15
+
16
+ _log(...args) {
17
+ if (this.debug) console.log('[RedDB]', ...args);
8
18
  }
9
19
 
10
20
  async _safeJson(res) {
11
21
  const text = await res.text();
22
+
12
23
  try {
13
24
  return JSON.parse(text);
14
25
  } catch {
15
- throw new Error(`Resposta inválida (não é JSON):\n${text}`);
26
+ throw new Error(`Resposta inválida do servidor:\n${text}`);
16
27
  }
17
28
  }
18
29
 
19
- async _request(path, options = {}, isAdmin = false) {
20
- const headers = { 'Content-Type': 'application/json', ...(options.headers || {}) };
30
+ async _fetchWithTimeout(url, options) {
31
+ const controller = new AbortController();
32
+ const id = setTimeout(() => controller.abort(), this.timeout);
33
+
34
+ try {
35
+ const res = await fetch(url, { ...options, signal: controller.signal });
36
+ clearTimeout(id);
37
+ return res;
38
+ } catch (err) {
39
+ clearTimeout(id);
40
+
41
+ if (err.name === 'AbortError') {
42
+ throw new Error('Timeout: cluster não respondeu a tempo');
43
+ }
44
+
45
+ throw new Error('Cluster offline ou inacessível');
46
+ }
47
+ }
21
48
 
49
+ async _request(path, options = {}, isAdmin = false) {
22
50
  let url = `${this.baseURL}${path}`;
23
- let body = options.body ? JSON.parse(options.body) : {};
51
+ let body = {};
52
+
53
+ // aceita body como objeto OU string
54
+ if (options.body) {
55
+ body = typeof options.body === 'string'
56
+ ? JSON.parse(options.body)
57
+ : options.body;
58
+ }
24
59
 
25
60
  body.reddbPassword = this.reddbPassword;
26
61
 
27
62
  if (isAdmin) {
28
- if (!this.adminPassword) throw new Error('Admin password required');
63
+ if (!this.adminPassword) throw new Error('Admin password não fornecida');
29
64
  body.adminPassword = this.adminPassword;
30
65
  }
31
66
 
67
+ const headers = { 'Content-Type': 'application/json' };
68
+
32
69
  if (options.method === 'GET') {
33
70
  const query = new URLSearchParams(body).toString();
34
71
  url += `?${query}`;
@@ -37,39 +74,58 @@ class RedDBClient {
37
74
  options.body = JSON.stringify(body);
38
75
  }
39
76
 
40
- const res = await fetch(url, {
41
- ...options,
42
- headers
43
- });
77
+ for (let attempt = 0; attempt <= this.retries; attempt++) {
78
+ try {
79
+ this._log('Request:', options.method, url);
80
+
81
+ const res = await this._fetchWithTimeout(url, {
82
+ ...options,
83
+ headers
84
+ });
44
85
 
45
- return this._safeJson(res);
86
+ const data = await this._safeJson(res);
87
+
88
+ // 🔥 tratamento de erro da API
89
+ if (!res.ok || data.error) {
90
+ throw new Error(data.error || `Erro HTTP ${res.status}`);
91
+ }
92
+
93
+ return data;
94
+ } catch (err) {
95
+ this._log(`Erro (tentativa ${attempt + 1}):`, err.message);
96
+
97
+ if (attempt === this.retries) {
98
+ throw new Error(`Falha após ${this.retries + 1} tentativas: ${err.message}`);
99
+ }
100
+ }
101
+ }
46
102
  }
47
103
 
48
104
  async set(key, value, document = 'users.json') {
49
105
  return this._request('/set', {
50
106
  method: 'POST',
51
- body: JSON.stringify({ key, value, document })
107
+ body: { key, value, document }
52
108
  }, true);
53
109
  }
54
110
 
55
111
  async delete(key, document = 'users.json') {
56
112
  return this._request('/delete', {
57
113
  method: 'POST',
58
- body: JSON.stringify({ key, document })
114
+ body: { key, document }
59
115
  }, true);
60
116
  }
61
117
 
62
118
  async get(key, document = 'users.json') {
63
119
  return this._request(`/get/${encodeURIComponent(key)}`, {
64
120
  method: 'GET',
65
- body: JSON.stringify({ document })
121
+ body: { document }
66
122
  });
67
123
  }
68
124
 
69
125
  async listKeys(document = 'users.json') {
70
126
  return this._request('/listKeys', {
71
127
  method: 'GET',
72
- body: JSON.stringify({ document })
128
+ body: { document }
73
129
  });
74
130
  }
75
131
 
@@ -81,7 +137,7 @@ class RedDBClient {
81
137
 
82
138
  async listAdminKeys() {
83
139
  return this._request('/admin/keys', {
84
- method: 'GET'
140
+ method: 'POST'
85
141
  }, true);
86
142
  }
87
143
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reddb-sdk",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "SDK Node.js para RedDB Cluster",
5
5
  "main": "lib/RedDBClient.js",
6
6
  "keywords": [