dataflux 1.1.2 → 1.2.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 +92 -18
- package/dist/Model.js +45 -0
- package/dist/StoreObject.js +33 -0
- package/dist/modelHooksUtils.js +37 -12
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ export default store;
|
|
|
48
48
|
|
|
49
49
|
The store can be initialized with [various options](#configuration). You need only one store for the entire application, that's why you should declare it in its own file and import it in multiple places.
|
|
50
50
|
|
|
51
|
-
The creation of a model requires at least a name and
|
|
51
|
+
The creation of a model requires at least a name and a url. GET, POST, PUT, and DELETE operations are going to be performed against the same url. [Models can be created with considerably more advanced options.](#models-creation)
|
|
52
52
|
|
|
53
53
|
A JS object is automatically created for each item returned by the API, for each model. The object has the same properties of the JSON item plus some high-level method (see [objects methods](#objects-methods)).
|
|
54
54
|
**All the objects are indexed in the store.**
|
|
@@ -219,39 +219,78 @@ A model can be simply created with:
|
|
|
219
219
|
const book = new Model("book", `https://rest.example.net/api/v1/books`);
|
|
220
220
|
```
|
|
221
221
|
|
|
222
|
-
However,
|
|
222
|
+
However, sometimes you may want to define a more complex interaction with the API. In such cases you can pass options to perform more elaborated model's initializations.
|
|
223
|
+
|
|
224
|
+
```js
|
|
225
|
+
const book = new Model("book", options);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
All the possible options for a model creation are (they are all optional):
|
|
229
|
+
|
|
230
|
+
| Name | Description | Default |
|
|
231
|
+
|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------|
|
|
232
|
+
| retrieve | Describes the operation to retrieve the collection of objects from the REST API. It can be an operation object or a function. See [operations](#operations). | `{method: "get"}` |
|
|
233
|
+
| insert | Describes the operation to insert a new object in the collection. It can be an operation object or a function. See [operations](#operations). | `{method: "post"}` |
|
|
234
|
+
| update | Describes the operation to update objects of the collection. It can be an operation object or a function. See [operations](#operations). | `{method: "put"}` |
|
|
235
|
+
| delete | Describes the operation to remove objects from the collection. It can be an operation object or a function. See [operations](#operations). | `{method: "delete"}` |
|
|
236
|
+
| fields | An array of strings defining which attributes the retrieved objects should have. Essentially, it allows you to contemporarily specify the [X-Fields header](https://flask-restplus.readthedocs.io/en/stable/mask.html) and the [fields GET parameter](https://developers.google.com/slides/api/guides/performance#partial). This reduces transfer size and memory usage. E.g., if you have a collection of books, of which you are interested only in the name, you can define `fields: ["name"]`. In combination with `load` it allows for partial lazy load of the objects. | All the fields |
|
|
237
|
+
| headers | A dictionary of headers for the HTTP request. E.g., `{"Authorization": "bearer XXXX"}`. | No headers |
|
|
238
|
+
| load | A function that allows to enrich the objects on demand. E.g., you can use `fields` to download only the titles of a collection of books, and `load` to load completely the object. See [object enrichment](#object-enrichment). |
|
|
239
|
+
| axios | It allows to specify an axios instance to be used for the queries. If not specified, a new one will be used. | A new axios instance |
|
|
223
240
|
|
|
224
|
-
|
|
241
|
+
|
|
242
|
+
### Operations
|
|
243
|
+
As described in the table above, there are four possible operations: **retrieve, insert, update,** and **delete**. An operation can be defined as an operation object or a function.
|
|
244
|
+
|
|
245
|
+
#### Operation object
|
|
246
|
+
|
|
247
|
+
An operation object is an object like follows:
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"method": "get",
|
|
252
|
+
"url": "https://api.example.com",
|
|
253
|
+
"headers": {"Authorization": "bearer XXXX"}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Usage example:
|
|
225
258
|
|
|
226
259
|
```js
|
|
227
260
|
const options = {
|
|
261
|
+
|
|
228
262
|
retrieve: {
|
|
229
263
|
method: "get",
|
|
230
|
-
url: "https://rest.example.net/api/v1/books"
|
|
264
|
+
url: "https://rest.example.net/api/v1/books",
|
|
265
|
+
headers: {} // Headers can be define per operation or globally
|
|
231
266
|
},
|
|
267
|
+
|
|
232
268
|
insert: {
|
|
233
269
|
method: "post",
|
|
234
270
|
url: "https://rest.example.net/api/v1/books"
|
|
235
271
|
},
|
|
272
|
+
|
|
236
273
|
update: {
|
|
237
274
|
method: "put",
|
|
238
275
|
url: "https://rest.example.net/api/v1/books"
|
|
239
276
|
},
|
|
277
|
+
|
|
240
278
|
delete: {
|
|
241
279
|
method: "delete",
|
|
242
280
|
url: "https://rest.example.net/api/v1/books"
|
|
243
|
-
}
|
|
281
|
+
},
|
|
282
|
+
|
|
283
|
+
headers: {"Authorization": "bearer XXXX"} // Globally defined headers
|
|
244
284
|
};
|
|
245
285
|
|
|
246
286
|
const book = new Model("book", options);
|
|
247
287
|
```
|
|
248
|
-
You don't
|
|
288
|
+
You don't need to specify all the attributes for each operation, only the ones you want to variate from the defaults (see table above). If a url is not specified for an operation, the url defined for the `GET` operation is used.
|
|
249
289
|
|
|
250
|
-
For example, if you want to perform both inserts and updates with `PUT
|
|
290
|
+
For example, if you are ok with the default behaviour except you want to perform both inserts and updates with `PUT` (instead of post/put), you can do:
|
|
251
291
|
```js
|
|
252
292
|
const options = {
|
|
253
293
|
retrieve: {
|
|
254
|
-
method: "get",
|
|
255
294
|
url: "https://rest.example.net/api/v1/books"
|
|
256
295
|
},
|
|
257
296
|
insert: {
|
|
@@ -262,7 +301,9 @@ const options = {
|
|
|
262
301
|
const book = new Model("book", options);
|
|
263
302
|
```
|
|
264
303
|
|
|
265
|
-
|
|
304
|
+
#### Operation function
|
|
305
|
+
|
|
306
|
+
To be even more flexible, you can pass functions and handle yourself the operations. An operation function must return a promise, the promise must return an array of JSON objects when these are ready.
|
|
266
307
|
|
|
267
308
|
|
|
268
309
|
```js
|
|
@@ -276,7 +317,7 @@ const options = {
|
|
|
276
317
|
insert: (data) => {
|
|
277
318
|
// 1) recieve the data from the store
|
|
278
319
|
// 2) transform the data however you like
|
|
279
|
-
// 3) send data to server
|
|
320
|
+
// 3) send data to server and resolve empty
|
|
280
321
|
return Promise.resolve();
|
|
281
322
|
}
|
|
282
323
|
};
|
|
@@ -284,16 +325,49 @@ const options = {
|
|
|
284
325
|
const book = new Model("book", options);
|
|
285
326
|
```
|
|
286
327
|
|
|
287
|
-
|
|
328
|
+
#### Object enrichment
|
|
329
|
+
|
|
330
|
+
DataFlux objects can have a `load()` method which enables you to load extra attributes of an object.
|
|
331
|
+
|
|
332
|
+
Example of usage of `load()`:
|
|
333
|
+
|
|
334
|
+
```js
|
|
335
|
+
console.log(book);
|
|
336
|
+
// {title: "The little prince"}
|
|
337
|
+
|
|
338
|
+
book.load();
|
|
339
|
+
// The book object will be updated and it will contain
|
|
340
|
+
// {id: 23, title: "The little prince", price: 9.99, year: 1943}
|
|
341
|
+
//
|
|
342
|
+
// If you are using React, book.load() will automatically update your state
|
|
343
|
+
```
|
|
344
|
+
|
|
288
345
|
|
|
289
|
-
| Name | Description |
|
|
290
|
-
|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
291
|
-
| retrieve | Describes the operation to retrieve a collection of objects from a REST API. It can be an object containing `method` and `url` or a function. See examples above. |
|
|
292
|
-
| insert | Describes the operation to insert a new object in the collection. It can be an object containing `method` and `url` or a function. See examples above. |
|
|
293
|
-
| update | Describes the operation to update objects of the collection. It can be an object containing `method` and `url` or a function. See examples above. |
|
|
294
|
-
| delete | Describes the operation to remove objects from the collection. It can be an object containing `method` and `url` or a function. See examples above. |
|
|
295
|
-
| axios | It allows to specify an axios instance to be used for the queries. If not specified, a new one will be used. |
|
|
296
346
|
|
|
347
|
+
To enable such a method, you have to define the `load` option during model creation. The load option accepts a function that returns the complete object of a url. The function receives in input the current JSON object.
|
|
348
|
+
|
|
349
|
+
Example of creation of a model with `load` support:
|
|
350
|
+
```js
|
|
351
|
+
const book = new Model("book", {
|
|
352
|
+
retrieve: {
|
|
353
|
+
url: "https://rest.example.net/api/v1/books/"
|
|
354
|
+
},
|
|
355
|
+
fields: ["title"], // By default the books will contain only the title
|
|
356
|
+
load: (object) => { // "object" contains the current object to be enriched
|
|
357
|
+
|
|
358
|
+
// Return the url where to retrieve the object
|
|
359
|
+
return "https://rest.example.net/api/v1/books/" + object.id;
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
Alternatively, the `load` function can return directly the enriched object.
|
|
364
|
+
```js
|
|
365
|
+
const book = new Model("book", {
|
|
366
|
+
load: (object) => {
|
|
367
|
+
return axios({...}).then(raw => raw.data);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
```
|
|
297
371
|
|
|
298
372
|
### Model relations
|
|
299
373
|
|
package/dist/Model.js
CHANGED
|
@@ -69,6 +69,8 @@ var _batchSize = /*#__PURE__*/new WeakMap();
|
|
|
69
69
|
|
|
70
70
|
var _axios = /*#__PURE__*/new WeakMap();
|
|
71
71
|
|
|
72
|
+
var _loadFunction = /*#__PURE__*/new WeakMap();
|
|
73
|
+
|
|
72
74
|
var _addRelationByField = /*#__PURE__*/new WeakMap();
|
|
73
75
|
|
|
74
76
|
var _addRelationByFilter = /*#__PURE__*/new WeakMap();
|
|
@@ -140,6 +142,11 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
140
142
|
value: void 0
|
|
141
143
|
});
|
|
142
144
|
|
|
145
|
+
_classPrivateFieldInitSpec(this, _loadFunction, {
|
|
146
|
+
writable: true,
|
|
147
|
+
value: void 0
|
|
148
|
+
});
|
|
149
|
+
|
|
143
150
|
_defineProperty(this, "getStore", function () {
|
|
144
151
|
return _classPrivateFieldGet(_this, _store);
|
|
145
152
|
});
|
|
@@ -152,6 +159,38 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
152
159
|
}
|
|
153
160
|
});
|
|
154
161
|
|
|
162
|
+
_defineProperty(this, "load", function (obj) {
|
|
163
|
+
return new Promise(function (resolve, reject) {
|
|
164
|
+
var applyData = function applyData(data) {
|
|
165
|
+
for (var att in data) {
|
|
166
|
+
if (att !== "id" || obj.id === undefined || att === "id" && obj.id === data.id) {
|
|
167
|
+
obj[att] = data[att];
|
|
168
|
+
} else {
|
|
169
|
+
return Promise.reject("The loading function cannot change the id of the object.");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
if (_classPrivateFieldGet(_this, _loadFunction)) {
|
|
175
|
+
var res = _classPrivateFieldGet(_this, _loadFunction).call(_this, obj.toJson());
|
|
176
|
+
|
|
177
|
+
if (typeof res === "string") {
|
|
178
|
+
_classPrivateFieldGet(_this, _axios).call(_this, {
|
|
179
|
+
method: "get",
|
|
180
|
+
url: res,
|
|
181
|
+
responseType: "json"
|
|
182
|
+
}).then(function (data) {
|
|
183
|
+
return applyData(data.data);
|
|
184
|
+
}).then(resolve);
|
|
185
|
+
} else {
|
|
186
|
+
res.then(applyData).then(resolve);
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
reject("You must define a loading function in the model to enable load().");
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
155
194
|
_defineProperty(this, "addRelation", function (model, param2, param3) {
|
|
156
195
|
if (model) {
|
|
157
196
|
_this.getStore().validateModel(model);
|
|
@@ -285,10 +324,16 @@ var Model = /*#__PURE__*/_createClass(function Model(name) {
|
|
|
285
324
|
|
|
286
325
|
_classPrivateFieldSet(this, _axios, options.axios || _axios2["default"]);
|
|
287
326
|
|
|
327
|
+
_classPrivateFieldSet(this, _loadFunction, options.load || null);
|
|
328
|
+
|
|
288
329
|
if (!name || !options) {
|
|
289
330
|
throw new Error("A Model requires at least a name and a hook");
|
|
290
331
|
}
|
|
291
332
|
|
|
333
|
+
if (_classPrivateFieldGet(this, _loadFunction) && typeof _classPrivateFieldGet(this, _loadFunction) !== "function") {
|
|
334
|
+
throw new Error("The load option must be a function");
|
|
335
|
+
}
|
|
336
|
+
|
|
292
337
|
var _ref = _typeof(options) === "object" ? (0, _modelHooksUtils.getHooksFromOptions)(options) : (0, _modelHooksUtils.getHooksFromUrl)(options),
|
|
293
338
|
_ref2 = _slicedToArray(_ref, 4),
|
|
294
339
|
retrieveHook = _ref2[0],
|
package/dist/StoreObject.js
CHANGED
|
@@ -19,11 +19,44 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
|
19
19
|
|
|
20
20
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
21
21
|
|
|
22
|
+
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
|
|
23
|
+
|
|
24
|
+
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
|
|
25
|
+
|
|
26
|
+
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; }
|
|
27
|
+
|
|
28
|
+
function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } }
|
|
29
|
+
|
|
30
|
+
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
|
|
31
|
+
|
|
32
|
+
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
|
|
33
|
+
|
|
34
|
+
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
|
|
35
|
+
|
|
36
|
+
var _loaded = /*#__PURE__*/new WeakMap();
|
|
37
|
+
|
|
22
38
|
var Obj = /*#__PURE__*/_createClass(function Obj(values, model) {
|
|
23
39
|
var _this = this;
|
|
24
40
|
|
|
25
41
|
_classCallCheck(this, Obj);
|
|
26
42
|
|
|
43
|
+
_classPrivateFieldInitSpec(this, _loaded, {
|
|
44
|
+
writable: true,
|
|
45
|
+
value: false
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
_defineProperty(this, "load", function () {
|
|
49
|
+
if (_classPrivateFieldGet(_this, _loaded)) {
|
|
50
|
+
return Promise.resolve(_this);
|
|
51
|
+
} else {
|
|
52
|
+
return _this.getModel().load(_this).then(function () {
|
|
53
|
+
_classPrivateFieldSet(_this, _loaded, true);
|
|
54
|
+
|
|
55
|
+
return _this;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
27
60
|
_defineProperty(this, "getFingerprint", function () {
|
|
28
61
|
return (0, _fingerprint["default"])(_this.toJson());
|
|
29
62
|
});
|
package/dist/modelHooksUtils.js
CHANGED
|
@@ -5,23 +5,46 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.getHooksFromUrl = exports.getHooksFromOptions = exports.executeHook = void 0;
|
|
7
7
|
|
|
8
|
+
var _brembo = _interopRequireDefault(require("brembo"));
|
|
9
|
+
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
11
|
+
|
|
8
12
|
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
|
|
9
13
|
|
|
10
|
-
var getDataStringHook = function getDataStringHook(
|
|
11
|
-
var
|
|
12
|
-
var
|
|
13
|
-
var
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
method: method,
|
|
14
|
+
var getDataStringHook = function getDataStringHook(hook) {
|
|
15
|
+
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
16
|
+
var axios = arguments.length > 2 ? arguments[2] : undefined;
|
|
17
|
+
var options = {
|
|
18
|
+
url: hook.url,
|
|
19
|
+
method: hook.method || "get",
|
|
17
20
|
data: data,
|
|
18
21
|
reponseType: 'json'
|
|
19
|
-
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
if (hook.headers) {
|
|
25
|
+
options.headers = hook.headers;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (hook.fields) {
|
|
29
|
+
setFields(options, hook);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return axios(options).then(function (data) {
|
|
20
33
|
return data.data;
|
|
21
34
|
});
|
|
22
35
|
};
|
|
23
36
|
|
|
24
|
-
var
|
|
37
|
+
var setFields = function setFields(options, hook) {
|
|
38
|
+
options.headers = options.headers || {};
|
|
39
|
+
options.headers['X-Fields'] = hook.fields;
|
|
40
|
+
options.url = _brembo["default"].build(options.url, {
|
|
41
|
+
params: {
|
|
42
|
+
fields: hook.fields.join(",")
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
var createHookItem = function createHookItem(optionItem, defaultMethod, defaultUrl, options) {
|
|
25
48
|
switch (_typeof(optionItem)) {
|
|
26
49
|
case "undefined":
|
|
27
50
|
if (!defaultUrl) {
|
|
@@ -44,7 +67,9 @@ var createHookItem = function createHookItem(optionItem, defaultMethod, defaultU
|
|
|
44
67
|
case "object":
|
|
45
68
|
return {
|
|
46
69
|
method: optionItem.method || defaultMethod,
|
|
47
|
-
url: optionItem.url || defaultUrl
|
|
70
|
+
url: optionItem.url || defaultUrl,
|
|
71
|
+
fields: options.fields || [],
|
|
72
|
+
headers: optionItem.headers || options.headers || {}
|
|
48
73
|
};
|
|
49
74
|
|
|
50
75
|
default:
|
|
@@ -54,7 +79,7 @@ var createHookItem = function createHookItem(optionItem, defaultMethod, defaultU
|
|
|
54
79
|
|
|
55
80
|
var getHooksFromOptions = function getHooksFromOptions(options) {
|
|
56
81
|
var defaultUrl = typeof options.retrieve === "function" ? null : options.retrieve.url;
|
|
57
|
-
return [createHookItem(options.retrieve, "get", defaultUrl), createHookItem(options.insert, "post", defaultUrl), createHookItem(options.update, "put", defaultUrl), createHookItem(options["delete"], "delete", defaultUrl)];
|
|
82
|
+
return [createHookItem(options.retrieve, "get", defaultUrl, options), createHookItem(options.insert, "post", defaultUrl, options), createHookItem(options.update, "put", defaultUrl, options), createHookItem(options["delete"], "delete", defaultUrl, options)];
|
|
58
83
|
};
|
|
59
84
|
|
|
60
85
|
exports.getHooksFromOptions = getHooksFromOptions;
|
|
@@ -82,7 +107,7 @@ var executeHook = function executeHook(type, hook, data, axios) {
|
|
|
82
107
|
|
|
83
108
|
switch (hookType) {
|
|
84
109
|
case "object":
|
|
85
|
-
return getDataStringHook(hook
|
|
110
|
+
return getDataStringHook(hook, data, axios);
|
|
86
111
|
|
|
87
112
|
case "function":
|
|
88
113
|
return hook(data);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dataflux",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "DataFlux, automatically interfaces with your REST APIs to create a 2-way-synced local data store. Transparently manages data propagation in the React state.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": "dist/index.js",
|
|
@@ -78,13 +78,13 @@
|
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@babel/cli": "^7.16.8",
|
|
81
|
-
"@babel/core": "^7.16.
|
|
81
|
+
"@babel/core": "^7.16.12",
|
|
82
82
|
"@babel/node": "^7.16.8",
|
|
83
83
|
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
|
84
84
|
"@babel/plugin-proposal-object-rest-spread": "^7.16.7",
|
|
85
85
|
"@babel/plugin-transform-async-to-generator": "^7.16.8",
|
|
86
86
|
"@babel/plugin-transform-runtime": "^7.16.10",
|
|
87
|
-
"@babel/preset-env": "^7.16.
|
|
87
|
+
"@babel/preset-env": "^7.16.11",
|
|
88
88
|
"@babel/preset-react": "^7.16.7",
|
|
89
89
|
"dotenv-cli": "^4.1.1",
|
|
90
90
|
"release-it": "^14.12.3"
|
|
@@ -92,6 +92,7 @@
|
|
|
92
92
|
"dependencies": {
|
|
93
93
|
"axios": "^0.25.0",
|
|
94
94
|
"batch-promises": "^0.0.3",
|
|
95
|
+
"brembo": "^2.0.6",
|
|
95
96
|
"crc-32": "^1.2.0",
|
|
96
97
|
"uuid": "^8.3.2"
|
|
97
98
|
},
|