iobroker.rest-api 2.0.2 → 3.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 +49 -8
- package/admin/i18n/{de/translations.json → de.json} +22 -22
- package/admin/i18n/{en/translations.json → en.json} +22 -23
- package/admin/i18n/{es/translations.json → es.json} +22 -23
- package/admin/i18n/{fr/translations.json → fr.json} +22 -23
- package/admin/i18n/{it/translations.json → it.json} +22 -23
- package/admin/i18n/{nl/translations.json → nl.json} +22 -23
- package/admin/i18n/{pl/translations.json → pl.json} +22 -23
- package/admin/i18n/{pt/translations.json → pt.json} +22 -23
- package/admin/i18n/{ru/translations.json → ru.json} +22 -23
- package/admin/i18n/uk.json +32 -0
- package/admin/i18n/{zh-cn/translations.json → zh-cn.json} +22 -23
- package/admin/jsonConfig.json +178 -180
- package/admin/rest-api.svg +8 -0
- package/dist/lib/api/controllers/common.js +129 -0
- package/dist/lib/api/controllers/common.js.map +1 -0
- package/dist/lib/api/controllers/enum.js +58 -0
- package/dist/lib/api/controllers/enum.js.map +1 -0
- package/dist/lib/api/controllers/file.js +104 -0
- package/dist/lib/api/controllers/file.js.map +1 -0
- package/dist/lib/api/controllers/history.js +262 -0
- package/dist/lib/api/controllers/history.js.map +1 -0
- package/dist/lib/api/controllers/object.js +346 -0
- package/dist/lib/api/controllers/object.js.map +1 -0
- package/dist/lib/api/controllers/sendTo.js +118 -0
- package/dist/lib/api/controllers/sendTo.js.map +1 -0
- package/dist/lib/api/controllers/state.js +545 -0
- package/dist/lib/api/controllers/state.js.map +1 -0
- package/dist/lib/api/swagger/swagger.yaml +2551 -0
- package/{lib → dist/lib}/common.js +8 -10
- package/dist/lib/common.js.map +1 -0
- package/dist/lib/rest-api.js +1216 -0
- package/dist/lib/rest-api.js.map +1 -0
- package/dist/main.js +159 -0
- package/dist/main.js.map +1 -0
- package/examples/demoBrowserClient.html +95 -82
- package/examples/demoNodeClient.js +8 -7
- package/examples/longPolling.js +46 -45
- package/io-package.json +43 -34
- package/package.json +36 -24
- package/lib/api/controllers/common.js +0 -150
- package/lib/api/controllers/enum.js +0 -44
- package/lib/api/controllers/file.js +0 -74
- package/lib/api/controllers/history.js +0 -239
- package/lib/api/controllers/object.js +0 -273
- package/lib/api/controllers/sendTo.js +0 -123
- package/lib/api/controllers/state.js +0 -565
- package/lib/api/swagger/swagger.yaml +0 -2624
- package/lib/rest-api.js +0 -1123
- package/main.js +0 -173
- /package/{lib → dist/lib}/config/default.yaml +0 -0
package/examples/longPolling.js
CHANGED
|
@@ -25,7 +25,7 @@ class LongPolling {
|
|
|
25
25
|
this.subscriptions = {
|
|
26
26
|
objects: {},
|
|
27
27
|
states: {},
|
|
28
|
-
patterns: {}
|
|
28
|
+
patterns: {},
|
|
29
29
|
};
|
|
30
30
|
this.sid = Date.now() + '_' + Math.round(Math.random() * 10000);
|
|
31
31
|
if (this.options.autoConnect) {
|
|
@@ -41,27 +41,30 @@ class LongPolling {
|
|
|
41
41
|
setTimeout(() => {
|
|
42
42
|
Object.keys(this.subscriptions.objects).forEach(id =>
|
|
43
43
|
fetch(`${IOBROKER_SWAGGER}v1/object/${id}/subscribe?sid=${this.sid}&method=polling`, {
|
|
44
|
-
headers: this._getAuthorization()
|
|
44
|
+
headers: this._getAuthorization(),
|
|
45
45
|
})
|
|
46
46
|
.then(response => response.json())
|
|
47
|
-
.catch(error => console.error('Cannot resubscribe: ' + error))
|
|
47
|
+
.catch(error => console.error('Cannot resubscribe: ' + error)),
|
|
48
|
+
);
|
|
48
49
|
|
|
49
50
|
Object.keys(this.subscriptions.states).forEach(id =>
|
|
50
51
|
fetch(`${IOBROKER_SWAGGER}v1/state/${id}/subscribe?sid=${this.sid}&method=polling`, {
|
|
51
|
-
headers: this._getAuthorization()
|
|
52
|
+
headers: this._getAuthorization(),
|
|
52
53
|
})
|
|
53
54
|
.then(response => response.json())
|
|
54
|
-
.catch(error => console.error('Cannot resubscribe: ' + error))
|
|
55
|
+
.catch(error => console.error('Cannot resubscribe: ' + error)),
|
|
56
|
+
);
|
|
55
57
|
|
|
56
58
|
Object.keys(this.subscriptions.patterns).forEach(pattern =>
|
|
57
59
|
fetch(`${IOBROKER_SWAGGER}v1/states/subscribe?sid=${this.sid}&method=polling`, {
|
|
58
60
|
method: 'POST',
|
|
59
61
|
cache: 'no-cache',
|
|
60
62
|
headers: this._getAuthorization('application/json'),
|
|
61
|
-
body: JSON.stringify({method: 'polling', pattern})
|
|
63
|
+
body: JSON.stringify({ method: 'polling', pattern }),
|
|
62
64
|
})
|
|
63
65
|
.then(response => response.json())
|
|
64
|
-
.catch(error => console.log('Error: ' + error))
|
|
66
|
+
.catch(error => console.log('Error: ' + error)),
|
|
67
|
+
);
|
|
65
68
|
|
|
66
69
|
this.options.onConnection && this.options.onConnection(this.isConnected);
|
|
67
70
|
}, 0);
|
|
@@ -74,14 +77,14 @@ class LongPolling {
|
|
|
74
77
|
_getAuthorization(contentType) {
|
|
75
78
|
if (this.options.user) {
|
|
76
79
|
const headers = {
|
|
77
|
-
Authorization: 'Basic ' + btoa(this.options.user + ':' + this.options.password)
|
|
80
|
+
Authorization: 'Basic ' + btoa(this.options.user + ':' + this.options.password),
|
|
78
81
|
};
|
|
79
82
|
if (contentType) {
|
|
80
|
-
headers['Content-Type'] =
|
|
83
|
+
headers['Content-Type'] = 'application/json';
|
|
81
84
|
}
|
|
82
85
|
return headers;
|
|
83
86
|
} else if (contentType) {
|
|
84
|
-
return {'Content-Type': 'application/json'};
|
|
87
|
+
return { 'Content-Type': 'application/json' };
|
|
85
88
|
} else {
|
|
86
89
|
return undefined;
|
|
87
90
|
}
|
|
@@ -93,13 +96,16 @@ class LongPolling {
|
|
|
93
96
|
// in real the re-connect interval will be added the timeout for fetch which depends on browser.
|
|
94
97
|
this.options.onConnectionAttempt && this.options.onConnectionAttempt(this.options.reconnectInterval);
|
|
95
98
|
}
|
|
96
|
-
const controller = new AbortController()
|
|
99
|
+
const controller = new AbortController();
|
|
97
100
|
let timeoutId = setTimeout(() => controller.abort(), this.options.pollingInterval + 1000);
|
|
98
101
|
|
|
99
|
-
fetch(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
fetch(
|
|
103
|
+
`${this.host}v1/polling?sid=${this.sid}${isStart ? `&connect&timeout=${this.options.pollingInterval}` : ''}`,
|
|
104
|
+
{
|
|
105
|
+
signal: controller.signal,
|
|
106
|
+
headers: this._getAuthorization(),
|
|
107
|
+
},
|
|
108
|
+
)
|
|
103
109
|
.then(response => {
|
|
104
110
|
timeoutId && clearTimeout(timeoutId);
|
|
105
111
|
timeoutId = null;
|
|
@@ -147,7 +153,7 @@ class LongPolling {
|
|
|
147
153
|
console.log('Cannot call handler: ' + error);
|
|
148
154
|
}
|
|
149
155
|
});
|
|
150
|
-
})
|
|
156
|
+
});
|
|
151
157
|
}
|
|
152
158
|
} else if (data.id && data.obj) {
|
|
153
159
|
if (this.subscriptions.objects[data.id]) {
|
|
@@ -159,7 +165,7 @@ class LongPolling {
|
|
|
159
165
|
console.log('Cannot call handler: ' + error);
|
|
160
166
|
}
|
|
161
167
|
});
|
|
162
|
-
})
|
|
168
|
+
});
|
|
163
169
|
}
|
|
164
170
|
} else if (data.id) {
|
|
165
171
|
// state and object where deleted
|
|
@@ -172,7 +178,7 @@ class LongPolling {
|
|
|
172
178
|
console.log('Cannot call handler: ' + error);
|
|
173
179
|
}
|
|
174
180
|
});
|
|
175
|
-
})
|
|
181
|
+
});
|
|
176
182
|
} else if (this.subscriptions.state[data.id]) {
|
|
177
183
|
setTimeout(() => {
|
|
178
184
|
this.subscriptions.state[data.id].forEach(cb => {
|
|
@@ -182,7 +188,7 @@ class LongPolling {
|
|
|
182
188
|
console.log('Cannot call handler: ' + error);
|
|
183
189
|
}
|
|
184
190
|
});
|
|
185
|
-
})
|
|
191
|
+
});
|
|
186
192
|
}
|
|
187
193
|
}
|
|
188
194
|
}
|
|
@@ -202,26 +208,26 @@ class LongPolling {
|
|
|
202
208
|
this._sendConnectedEvent(false);
|
|
203
209
|
|
|
204
210
|
if (!this.terminate) {
|
|
205
|
-
this.connecTimeout =
|
|
206
|
-
this.connecTimeout
|
|
207
|
-
|
|
208
|
-
|
|
211
|
+
this.connecTimeout =
|
|
212
|
+
this.connecTimeout ||
|
|
213
|
+
setTimeout(() => {
|
|
214
|
+
this.connecTimeout = null;
|
|
215
|
+
this._longPolling(true);
|
|
216
|
+
}, this.options.reconnectInterval);
|
|
209
217
|
}
|
|
210
218
|
});
|
|
211
219
|
}
|
|
212
220
|
|
|
213
221
|
getState(id) {
|
|
214
222
|
return fetch(`${IOBROKER_SWAGGER}v1/state/${id}`, {
|
|
215
|
-
headers: this._getAuthorization()
|
|
216
|
-
})
|
|
217
|
-
.then(response => response.json())
|
|
223
|
+
headers: this._getAuthorization(),
|
|
224
|
+
}).then(response => response.json());
|
|
218
225
|
}
|
|
219
226
|
|
|
220
227
|
getObject(id) {
|
|
221
228
|
return fetch(`${IOBROKER_SWAGGER}v1/object/${id}`, {
|
|
222
|
-
headers: this._getAuthorization()
|
|
223
|
-
})
|
|
224
|
-
.then(response => response.json())
|
|
229
|
+
headers: this._getAuthorization(),
|
|
230
|
+
}).then(response => response.json());
|
|
225
231
|
}
|
|
226
232
|
|
|
227
233
|
subscribeState(id, cb) {
|
|
@@ -229,9 +235,8 @@ class LongPolling {
|
|
|
229
235
|
this.subscriptions.states[id] = [];
|
|
230
236
|
this.subscriptions.states[id].push(cb);
|
|
231
237
|
return fetch(`${IOBROKER_SWAGGER}v1/state/${id}/subscribe?sid=${this.sid}&method=polling`, {
|
|
232
|
-
headers: this._getAuthorization()
|
|
233
|
-
})
|
|
234
|
-
.then(response => response.json());
|
|
238
|
+
headers: this._getAuthorization(),
|
|
239
|
+
}).then(response => response.json());
|
|
235
240
|
} else {
|
|
236
241
|
this.subscriptions.states[id].push(cb);
|
|
237
242
|
return Promise.resolve();
|
|
@@ -246,7 +251,7 @@ class LongPolling {
|
|
|
246
251
|
method: 'POST',
|
|
247
252
|
cache: 'no-cache',
|
|
248
253
|
headers: this._getAuthorization('application/json'),
|
|
249
|
-
body: JSON.stringify({method: 'polling', pattern})
|
|
254
|
+
body: JSON.stringify({ method: 'polling', pattern }),
|
|
250
255
|
})
|
|
251
256
|
.then(response => response.json())
|
|
252
257
|
.catch(error => console.log('Error: ' + error));
|
|
@@ -275,9 +280,8 @@ class LongPolling {
|
|
|
275
280
|
method: 'POST',
|
|
276
281
|
cache: 'no-cache',
|
|
277
282
|
headers: this._getAuthorization('application/json'),
|
|
278
|
-
body: JSON.stringify({method: 'polling', pattern})
|
|
279
|
-
})
|
|
280
|
-
.then(response => response.json());
|
|
283
|
+
body: JSON.stringify({ method: 'polling', pattern }),
|
|
284
|
+
}).then(response => response.json());
|
|
281
285
|
}
|
|
282
286
|
} else {
|
|
283
287
|
return Promise.resolve();
|
|
@@ -300,9 +304,8 @@ class LongPolling {
|
|
|
300
304
|
delete this.subscriptions.states[id];
|
|
301
305
|
}
|
|
302
306
|
return fetch(`${IOBROKER_SWAGGER}v1/state/${id}/unsubscribe?sid=${this.sid}&method=polling`, {
|
|
303
|
-
headers: this._getAuthorization()
|
|
304
|
-
})
|
|
305
|
-
.then(response => response.json());
|
|
307
|
+
headers: this._getAuthorization(),
|
|
308
|
+
}).then(response => response.json());
|
|
306
309
|
}
|
|
307
310
|
} else {
|
|
308
311
|
return Promise.resolve();
|
|
@@ -314,9 +317,8 @@ class LongPolling {
|
|
|
314
317
|
this.subscriptions.objects[id] = [];
|
|
315
318
|
this.subscriptions.objects[id].push(cb);
|
|
316
319
|
return fetch(`${IOBROKER_SWAGGER}v1/object/${id}/subscribe?sid=${this.sid}&method=polling`, {
|
|
317
|
-
headers: this._getAuthorization()
|
|
318
|
-
})
|
|
319
|
-
.then(response => response.json());
|
|
320
|
+
headers: this._getAuthorization(),
|
|
321
|
+
}).then(response => response.json());
|
|
320
322
|
} else {
|
|
321
323
|
this.subscriptions.objects[id].push(cb);
|
|
322
324
|
return Promise.resolve();
|
|
@@ -339,9 +341,8 @@ class LongPolling {
|
|
|
339
341
|
delete this.subscriptions.objects[id];
|
|
340
342
|
}
|
|
341
343
|
return fetch(`${IOBROKER_SWAGGER}v1/object/${id}/unsubscribe?sid=${this.sid}&method=polling`, {
|
|
342
|
-
headers: this._getAuthorization()
|
|
343
|
-
})
|
|
344
|
-
.then(response => response.json());
|
|
344
|
+
headers: this._getAuthorization(),
|
|
345
|
+
}).then(response => response.json());
|
|
345
346
|
}
|
|
346
347
|
} else {
|
|
347
348
|
return Promise.resolve();
|
package/io-package.json
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "rest-api",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "3.0.0",
|
|
5
5
|
"news": {
|
|
6
|
-
"
|
|
6
|
+
"3.0.0": {
|
|
7
|
+
"en": "Rewritten in TypeScript\nRemoved binary states",
|
|
8
|
+
"de": "Neu geschrieben in TypeScript\nEntfernte binäre Zustände",
|
|
9
|
+
"ru": "Переписано в TypeScript\nУдаленные бинарные состояния",
|
|
10
|
+
"pt": "Reescrito em TypeScript\nEstados binários removidos",
|
|
11
|
+
"nl": "Herschreven in TypeScript\nBinaire toestanden verwijderd",
|
|
12
|
+
"fr": "Réécrit dans TypeScript\nÉtats binaires supprimés",
|
|
13
|
+
"it": "Rescritto in TypeScript\nStati binari rimossi",
|
|
14
|
+
"es": "Reescrito en TipoScript\nEstados binarios eliminados",
|
|
15
|
+
"pl": "Przepisane w TypeScript\nUsunięte stany binarne",
|
|
16
|
+
"uk": "Записатися в TypeScript\nВилучені бінарні штати",
|
|
17
|
+
"zh-cn": "在类型脚本中重写\n删除二进制状态"
|
|
18
|
+
},
|
|
19
|
+
"2.0.3": {
|
|
7
20
|
"en": "Changed response for the endpoint get states to the dictionary in swagger",
|
|
8
21
|
"de": "Geänderte Antwort für den Endpunkt erhalten Zustände zum Wörterbuch in Swagger",
|
|
9
22
|
"ru": "Измененный ответ для конечной точки получить состояния в словарь в swagger",
|
|
@@ -29,19 +42,6 @@
|
|
|
29
42
|
"uk": "сайт: www.iobroker.com й\nВиправлені запити історії\nМінімальний необхідний вузол.js версія 16",
|
|
30
43
|
"zh-cn": "移植到 xqio 经纪人/网络服务器 `\n固定历史请求\n最低要求的节点.js版本为16"
|
|
31
44
|
},
|
|
32
|
-
"2.0.0": {
|
|
33
|
-
"en": "Fixed history requests\nMinimum required node.js version is 16",
|
|
34
|
-
"de": "Geschichtsanfragen behoben\nMinimum erforderlich node.js Version ist 16",
|
|
35
|
-
"ru": "Исправленные просьбы об истории\nМинимальная требуемая версия node.js - 16",
|
|
36
|
-
"pt": "Pedidos de histórico fixo\nA versão mínima necessária do node.js é 16",
|
|
37
|
-
"nl": "Vaste historische verzoeken\nMinimum vereiste node.js versie is 16",
|
|
38
|
-
"fr": "Demande d'historique fixe\nLa version minimum requise node.js est 16",
|
|
39
|
-
"it": "Risolte richieste di storia\nVersione minima richiesta node.js è 16",
|
|
40
|
-
"es": "Solicitudes de historia fija\nLa versión mínima requerida node.js es 16",
|
|
41
|
-
"pl": "Poprawione żądania dotyczące historii\nMinimalna wymagana node.js wersja jest 16",
|
|
42
|
-
"uk": "Виправлені запити історії\nМінімальний необхідний вузол.js версія 16",
|
|
43
|
-
"zh-cn": "固定历史请求\n最低要求的节点.js版本为16"
|
|
44
|
-
},
|
|
45
45
|
"1.1.0": {
|
|
46
46
|
"en": "Converting of the setState values to the according type\nImplemented file operations",
|
|
47
47
|
"de": "Umrechnung der setState-Werte in den entsprechenden Typ\nImplementierung von Dateioperationen",
|
|
@@ -78,24 +78,22 @@
|
|
|
78
78
|
"it": "Controllare se la porta è occupata solo su interfaccia definita",
|
|
79
79
|
"es": "Compruebe si el puerto está ocupado sólo en la interfaz definida",
|
|
80
80
|
"pl": "Jeśli port jest zajęty tylko na określonym interfejsie",
|
|
81
|
+
"uk": "Перевірте, чи порт зайнятий лише на визначеному інтерфейсі",
|
|
81
82
|
"zh-cn": "如果港口只在界定的界线上被占有,则该港口将被扣押。"
|
|
82
|
-
},
|
|
83
|
-
"1.0.2": {
|
|
84
|
-
"en": "Implemented binary read/write operations",
|
|
85
|
-
"de": "Implementierung binärer Schreib-/Lesevorgänge",
|
|
86
|
-
"ru": "Внедренные бинарные чтения / записи операции",
|
|
87
|
-
"pt": "Operações de leitura/escrita binárias implementadas",
|
|
88
|
-
"nl": "Geïmplementeerde binaire las/schrijf operaties",
|
|
89
|
-
"fr": "Opérations de lecture/écriture binaires mises en œuvre",
|
|
90
|
-
"it": "Operazioni di lettura/scrittura binarie implementate",
|
|
91
|
-
"es": "Operaciones de lectura y escritura binarias aplicadas",
|
|
92
|
-
"pl": "Poprawianie binarnego odczytu/pisania operacji",
|
|
93
|
-
"zh-cn": "执行本文的文字/仪式作业"
|
|
94
83
|
}
|
|
95
84
|
},
|
|
96
|
-
"title": "REST API",
|
|
97
85
|
"titleLang": {
|
|
98
|
-
"en": "REST API"
|
|
86
|
+
"en": "REST API",
|
|
87
|
+
"de": "REST API",
|
|
88
|
+
"ru": "REST API",
|
|
89
|
+
"pt": "REST API",
|
|
90
|
+
"nl": "REST API",
|
|
91
|
+
"fr": "REST API",
|
|
92
|
+
"it": "REST API",
|
|
93
|
+
"es": "REST API",
|
|
94
|
+
"pl": "REST API",
|
|
95
|
+
"uk": "REST API",
|
|
96
|
+
"zh-cn": "REST API"
|
|
99
97
|
},
|
|
100
98
|
"desc": {
|
|
101
99
|
"en": "This adapter allows to read and write ioBroker objects and state with web RESTful API and Swagger UI",
|
|
@@ -107,6 +105,7 @@
|
|
|
107
105
|
"it": "Questo adattatore consente di leggere e scrivere oggetti ioBroker e lo stato con l'API RESTful Web e l'interfaccia utente di Swagger",
|
|
108
106
|
"es": "Este adaptador permite leer y escribir objetos y estados ioBroker con la API RESTful web y la interfaz de usuario Swagger",
|
|
109
107
|
"pl": "Ten adapter pozwala na odczyt i zapis obiektów ioBroker oraz ich stan za pomocą web RESTful API i Swagger UI",
|
|
108
|
+
"uk": "Цей адаптер дозволяє читати та записувати об'єкти ioBroker та стан з веб RESTful API та Swagger UI",
|
|
110
109
|
"zh-cn": "该适配器允许使用Web RESTful API和Swagger UI读写ioBroker对象和状态"
|
|
111
110
|
},
|
|
112
111
|
"authors": [
|
|
@@ -117,9 +116,8 @@
|
|
|
117
116
|
"connectionType": "local",
|
|
118
117
|
"dataSource": "push",
|
|
119
118
|
"loglevel": "info",
|
|
120
|
-
"icon": "rest-api.
|
|
119
|
+
"icon": "rest-api.svg",
|
|
121
120
|
"compact": true,
|
|
122
|
-
"materialize": true,
|
|
123
121
|
"webExtension": "lib/rest-api.js",
|
|
124
122
|
"readme": "https://github.com/ioBroker/ioBroker.rest-api/blob/master/README.md",
|
|
125
123
|
"keywords": [
|
|
@@ -130,10 +128,15 @@
|
|
|
130
128
|
"communication"
|
|
131
129
|
],
|
|
132
130
|
"enabled": true,
|
|
133
|
-
"extIcon": "https://raw.githubusercontent.com/ioBroker/ioBroker.rest-api/master/admin/rest-api.
|
|
131
|
+
"extIcon": "https://raw.githubusercontent.com/ioBroker/ioBroker.rest-api/master/admin/rest-api.svg",
|
|
134
132
|
"type": "communication",
|
|
135
133
|
"stopBeforeUpdate": true,
|
|
136
|
-
"
|
|
134
|
+
"localLinks": {
|
|
135
|
+
"_default": {
|
|
136
|
+
"link": "%protocol%://%ip%:%port%/",
|
|
137
|
+
"intro": true
|
|
138
|
+
}
|
|
139
|
+
},
|
|
137
140
|
"adminUI": {
|
|
138
141
|
"config": "json"
|
|
139
142
|
},
|
|
@@ -142,9 +145,14 @@
|
|
|
142
145
|
"license": "Apache-2.0"
|
|
143
146
|
},
|
|
144
147
|
"tier": 3,
|
|
148
|
+
"globalDependencies": [
|
|
149
|
+
{
|
|
150
|
+
"admin": ">=7.4.10"
|
|
151
|
+
}
|
|
152
|
+
],
|
|
145
153
|
"dependencies": [
|
|
146
154
|
{
|
|
147
|
-
"js-controller": ">=
|
|
155
|
+
"js-controller": ">=5.0.19"
|
|
148
156
|
}
|
|
149
157
|
],
|
|
150
158
|
"plugins": {
|
|
@@ -162,6 +170,7 @@
|
|
|
162
170
|
"certPrivate": "",
|
|
163
171
|
"certChained": "",
|
|
164
172
|
"defaultUser": "admin",
|
|
173
|
+
"ttl": 3600,
|
|
165
174
|
"onlyAllowWhenUserIsOwner": false,
|
|
166
175
|
"webInstance": "",
|
|
167
176
|
"leEnabled": false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.rest-api",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "RESTful interface for ioBroker with GUI.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "bluefox",
|
|
@@ -15,60 +15,72 @@
|
|
|
15
15
|
"web"
|
|
16
16
|
],
|
|
17
17
|
"engines": {
|
|
18
|
-
"node": ">=
|
|
18
|
+
"node": ">=18"
|
|
19
19
|
},
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
22
|
"url": "https://github.com/ioBroker/ioBroker.rest-api"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@iobroker/adapter-core": "^3.
|
|
26
|
-
"@iobroker/socket-classes": "^
|
|
27
|
-
"@iobroker/webserver": "^1.
|
|
28
|
-
"
|
|
29
|
-
"
|
|
25
|
+
"@iobroker/adapter-core": "^3.2.3",
|
|
26
|
+
"@iobroker/socket-classes": "^2.2.16",
|
|
27
|
+
"@iobroker/webserver": "^1.2.7",
|
|
28
|
+
"@iobroker/ws-server": "^4.3.7",
|
|
29
|
+
"@iobroker/js-controller-common-db": "^7.0.7",
|
|
30
|
+
"axios": "^1.9.0",
|
|
31
|
+
"body-parser": "^2.2.0",
|
|
32
|
+
"cookie-parser": "^1.4.7",
|
|
30
33
|
"cors": "^2.8.5",
|
|
31
|
-
"express": "^4.
|
|
32
|
-
"multer": "^1.4.5-lts.
|
|
34
|
+
"express": "^4.21.2",
|
|
35
|
+
"multer": "^1.4.5-lts.2",
|
|
33
36
|
"swagger-node-runner-fork": "^0.8.0",
|
|
34
37
|
"swagger-ui-express": "^5.0.1",
|
|
35
38
|
"yamljs": "^0.3.0"
|
|
36
39
|
},
|
|
37
40
|
"devDependencies": {
|
|
38
|
-
"@alcalzone/release-script": "^3.
|
|
41
|
+
"@alcalzone/release-script": "^3.8.0",
|
|
39
42
|
"@alcalzone/release-script-plugin-iobroker": "^3.7.2",
|
|
40
43
|
"@alcalzone/release-script-plugin-license": "^3.7.0",
|
|
41
|
-
"@iobroker/adapter-dev": "^1.
|
|
42
|
-
"@iobroker/
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
44
|
+
"@iobroker/adapter-dev": "^1.4.0",
|
|
45
|
+
"@iobroker/eslint-config": "^2.0.1",
|
|
46
|
+
"@iobroker/testing": "^5.0.4",
|
|
47
|
+
"@iobroker/types": "^7.0.7",
|
|
48
|
+
"@types/body-parser": "^1.19.5",
|
|
49
|
+
"@types/cookie-parser": "^1.4.8",
|
|
50
|
+
"@types/cors": "^2.8.17",
|
|
51
|
+
"@types/express": "^4.17.21",
|
|
52
|
+
"@types/multer": "^1.4.12",
|
|
53
|
+
"@types/node": "^22.15.2",
|
|
54
|
+
"@types/swagger-node-runner": "^0.6.6",
|
|
55
|
+
"@types/swagger-ui-express": "^4.1.8",
|
|
56
|
+
"@types/yamljs": "^0.2.34",
|
|
57
|
+
"typescript": "^5.8.3"
|
|
49
58
|
},
|
|
50
59
|
"bugs": {
|
|
51
60
|
"url": "https://github.com/ioBroker/ioBroker.rest-api/issues"
|
|
52
61
|
},
|
|
53
|
-
"main": "main.js",
|
|
62
|
+
"main": "dist/main.js",
|
|
54
63
|
"files": [
|
|
55
64
|
"admin/",
|
|
56
65
|
"img/",
|
|
57
|
-
"
|
|
66
|
+
"dist/",
|
|
58
67
|
"examples/",
|
|
59
68
|
"LICENSE",
|
|
60
|
-
"main.js",
|
|
61
69
|
"io-package.json"
|
|
62
70
|
],
|
|
63
71
|
"scripts": {
|
|
64
|
-
"build": "
|
|
65
|
-
"
|
|
72
|
+
"build": "npm run build:ts && node tasks --copy-yaml",
|
|
73
|
+
"build:all": "npm run build:ts && node tasks",
|
|
74
|
+
"build:ts": "tsc -p tsconfig.build.json",
|
|
75
|
+
"test": "mocha --exit",
|
|
66
76
|
"release": "release-script",
|
|
67
77
|
"release-patch": "release-script patch --yes --no-update-lockfile",
|
|
68
78
|
"release-minor": "release-script minor --yes --no-update-lockfile",
|
|
69
79
|
"release-major": "release-script major --yes --no-update-lockfile",
|
|
70
80
|
"translate": "translate-adapter",
|
|
71
|
-
"update-packages": "
|
|
81
|
+
"update-packages": "npx -y npm-check-updates --upgrade",
|
|
82
|
+
"npm": "npm i",
|
|
83
|
+
"lint": "eslint -c eslint.config.mjs"
|
|
72
84
|
},
|
|
73
85
|
"license": "Apache-2.0"
|
|
74
86
|
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
const ERROR_PERMISSION = 'permissionError';
|
|
2
|
-
|
|
3
|
-
function checkPermissions(adapter, user, requiredRights, callback) {
|
|
4
|
-
adapter.calculatePermissions(user, requiredRights, acl => {
|
|
5
|
-
if (user !== 'system.user.admin') {
|
|
6
|
-
// type: file, object, state, other
|
|
7
|
-
// operation: create, read, write, list, delete, sendto, execute, sendto
|
|
8
|
-
if (requiredRights && requiredRights[0] && acl) {
|
|
9
|
-
// If permission required
|
|
10
|
-
if (requiredRights[0].type) {
|
|
11
|
-
if (acl[requiredRights[0].type] &&
|
|
12
|
-
acl[requiredRights[0].type][requiredRights[0].operation]) {
|
|
13
|
-
return callback(null);
|
|
14
|
-
}
|
|
15
|
-
} else {
|
|
16
|
-
return callback(null);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
adapter.log.warn(`No permission for "${user}" to call ${JSON.stringify(requiredRights)}`);
|
|
21
|
-
|
|
22
|
-
callback(ERROR_PERMISSION);
|
|
23
|
-
} else {
|
|
24
|
-
return callback(null);
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function findState(adapter, idOrName, user, type, callback) {
|
|
30
|
-
if (typeof type === 'function') {
|
|
31
|
-
callback = type;
|
|
32
|
-
type = null;
|
|
33
|
-
}
|
|
34
|
-
adapter.findForeignObject(idOrName, type, {user, checked: true, limitToOwnerRights: adapter.config.onlyAllowWhenUserIsOwner}, callback);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function getState(adapter, idOrName, user, type, callback) {
|
|
38
|
-
if (typeof type === 'function') {
|
|
39
|
-
callback = type;
|
|
40
|
-
type = null;
|
|
41
|
-
}
|
|
42
|
-
findState(adapter, idOrName, user, type, (err, id, originId) => {
|
|
43
|
-
if (err && (!err.message || !err.message.includes('permissionError'))) {
|
|
44
|
-
callback && callback(err, undefined, null, originId);
|
|
45
|
-
} else {
|
|
46
|
-
if (err && err.message.includes('permissionError')) {
|
|
47
|
-
// assume it is ID
|
|
48
|
-
id = idOrName;
|
|
49
|
-
}
|
|
50
|
-
if (id) {
|
|
51
|
-
adapter.getForeignState(id, {user, limitToOwnerRights: adapter.config.onlyAllowWhenUserIsOwner}, (err, state) => {
|
|
52
|
-
if (err || !state) {
|
|
53
|
-
state = undefined;
|
|
54
|
-
}
|
|
55
|
-
callback && callback (err, state, id, originId);
|
|
56
|
-
});
|
|
57
|
-
} else {
|
|
58
|
-
callback && callback(null, undefined, null, originId);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function getBinaryState(adapter, idOrName, user, type, callback) {
|
|
65
|
-
if (typeof type === 'function') {
|
|
66
|
-
callback = type;
|
|
67
|
-
type = null;
|
|
68
|
-
}
|
|
69
|
-
findState(adapter, idOrName, user, type, (err, id, originId) => {
|
|
70
|
-
if (err && (!err.message || !err.message.includes('permissionError'))) {
|
|
71
|
-
callback && callback(err, undefined, null, originId);
|
|
72
|
-
} else {
|
|
73
|
-
if (err && err.message.includes('permissionError')) {
|
|
74
|
-
// assume it is ID
|
|
75
|
-
id = idOrName;
|
|
76
|
-
}
|
|
77
|
-
if (id) {
|
|
78
|
-
if (adapter.getForeignBinaryState) {
|
|
79
|
-
adapter.getForeignBinaryState(id, {user, limitToOwnerRights: adapter.config.onlyAllowWhenUserIsOwner}, (err, binary) => {
|
|
80
|
-
if (err) {
|
|
81
|
-
binary = undefined;
|
|
82
|
-
}
|
|
83
|
-
callback && callback (err, binary, id, originId);
|
|
84
|
-
});
|
|
85
|
-
} else {
|
|
86
|
-
adapter.getBinaryState(id, {user, limitToOwnerRights: adapter.config.onlyAllowWhenUserIsOwner}, (err, binary) => {
|
|
87
|
-
if (err) {
|
|
88
|
-
binary = undefined;
|
|
89
|
-
}
|
|
90
|
-
callback && callback (err, binary, id, originId);
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
} else {
|
|
94
|
-
callback && callback(null, undefined, null, originId);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function parseUrl(url, swagger, webExtensionPrefix) {
|
|
101
|
-
// "/v1/object/adapter.system.admin.0.alive"
|
|
102
|
-
const parts = url.split('?')[0].split('/');
|
|
103
|
-
if (parts[1] === webExtensionPrefix) {
|
|
104
|
-
parts.shift(); // /
|
|
105
|
-
parts.shift(); // remove swagger
|
|
106
|
-
parts.shift(); // remove v1
|
|
107
|
-
parts.shift(); // remove objects or states
|
|
108
|
-
} else {
|
|
109
|
-
parts.shift(); // /
|
|
110
|
-
parts.shift(); // remove v1
|
|
111
|
-
parts.shift(); // remove objects or states
|
|
112
|
-
}
|
|
113
|
-
const result = {};
|
|
114
|
-
if (swagger && swagger.operation && swagger.operation.parameters) {
|
|
115
|
-
let i = 0;
|
|
116
|
-
swagger.operation.parameters.forEach(param => {
|
|
117
|
-
if (param.in === 'path') {
|
|
118
|
-
result[param.name] = parts[i] !== undefined ? decodeURIComponent(parts[i]) : '';
|
|
119
|
-
i++;
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
} else {
|
|
123
|
-
parts.forEach((param, i) =>
|
|
124
|
-
result['arg' + i] = decodeURIComponent(param));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return result;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function errorResponse(req, res, error, response) {
|
|
131
|
-
error = error.toString();
|
|
132
|
-
if (error === 'Error: permissionError') {
|
|
133
|
-
error = 'permissionError';
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
req._adapter.log.warn(`Warning by "${req.url}": ${error}`);
|
|
137
|
-
|
|
138
|
-
res
|
|
139
|
-
.status(error.toString().includes('permissionError') ? 403 : 500)
|
|
140
|
-
.json(Object.assign(response || {}, {error: error}));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
module.exports = {
|
|
144
|
-
checkPermissions,
|
|
145
|
-
findState,
|
|
146
|
-
getState,
|
|
147
|
-
getBinaryState,
|
|
148
|
-
parseUrl,
|
|
149
|
-
errorResponse,
|
|
150
|
-
};
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const commonLib = require('./common.js');
|
|
3
|
-
|
|
4
|
-
module.exports = {
|
|
5
|
-
readMainEnums: function (req, res) {
|
|
6
|
-
commonLib.checkPermissions(req._adapter, req._user, [{type: 'object', operation: 'read'}], async error => {
|
|
7
|
-
if (error) {
|
|
8
|
-
commonLib.errorResponse(req, res, error);
|
|
9
|
-
} else {
|
|
10
|
-
// check if instance is alive
|
|
11
|
-
try {
|
|
12
|
-
const enums = await req._adapter.getEnumsAsync('', {user: req._user, limitToOwnerRights: req._adapter.config.onlyAllowWhenUserIsOwner});
|
|
13
|
-
res.json(enums);
|
|
14
|
-
} catch (error) {
|
|
15
|
-
req._adapter.log.warn(`Cannot read enums: ${error}`);
|
|
16
|
-
commonLib.errorResponse(req, res, error);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
},
|
|
21
|
-
readEnums: function (req, res) {
|
|
22
|
-
commonLib.checkPermissions(req._adapter, req._user, [{type: 'object', operation: 'read'}], async error => {
|
|
23
|
-
if (error) {
|
|
24
|
-
commonLib.errorResponse(req, res, error);
|
|
25
|
-
} else {
|
|
26
|
-
const params = commonLib.parseUrl(req.url, req.swagger, req._adapter.WEB_EXTENSION_PREFIX);
|
|
27
|
-
// check if instance is alive
|
|
28
|
-
try {
|
|
29
|
-
const enums = await req._adapter.getEnumAsync(params.enumId, {user: req._user, limitToOwnerRights: req._adapter.config.onlyAllowWhenUserIsOwner});
|
|
30
|
-
if (enums && enums.result) {
|
|
31
|
-
res.json(Object.keys(enums.result).filter(id => id.split('.').length > 2).map(id => ({
|
|
32
|
-
_id: id,
|
|
33
|
-
common: enums.result[id].common
|
|
34
|
-
})));
|
|
35
|
-
} else {
|
|
36
|
-
res.json([]);
|
|
37
|
-
}
|
|
38
|
-
} catch (error) {
|
|
39
|
-
commonLib.errorResponse(req, res, error);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
},
|
|
44
|
-
};
|