cozy-client 46.8.0 → 46.9.1

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.
@@ -1245,6 +1245,10 @@ var CozyClient = /*#__PURE__*/function () {
1245
1245
  * `getQueryFromState` or directly using `<Query />`. `<Query />` automatically
1246
1246
  * executes its query when mounted if no fetch policy has been indicated.
1247
1247
  *
1248
+ * If the query is called under the fetch policy's delay, then the query
1249
+ * is not executed and nothing is returned. If you need a result anyway,
1250
+ * please use `fetchQueryAndGetFromState` instead
1251
+ *
1248
1252
  * @param {QueryDefinition} queryDefinition - Definition that will be executed
1249
1253
  * @param {import("./types").QueryOptions} [options] - Options
1250
1254
  * @returns {Promise<import("./types").QueryResult>}
@@ -2543,6 +2547,79 @@ var CozyClient = /*#__PURE__*/function () {
2543
2547
  value: function setAppMetadata(newAppMetadata) {
2544
2548
  this.appMetadata = _objectSpread(_objectSpread({}, this.appMetadata), newAppMetadata);
2545
2549
  }
2550
+ /**
2551
+ * Query the cozy-app settings corresponding to the given slug and
2552
+ * extract the value corresponding to the given `key`
2553
+ *
2554
+ * @template {string} T
2555
+ *
2556
+ * @param {string} slug - the cozy-app's slug containing the setting (can be 'instance' for global settings)
2557
+ * @param {T[]} keys - The names of the settings to retrieve
2558
+ * @returns {Promise<Record<T, any>>} - The value of the requested setting
2559
+ */
2560
+
2561
+ }, {
2562
+ key: "getSettings",
2563
+ value: function () {
2564
+ var _getSettings2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee19(slug, keys) {
2565
+ return _regenerator.default.wrap(function _callee19$(_context19) {
2566
+ while (1) {
2567
+ switch (_context19.prev = _context19.next) {
2568
+ case 0:
2569
+ return _context19.abrupt("return", (0, _helpers2.getSettings)(this, slug, keys));
2570
+
2571
+ case 1:
2572
+ case "end":
2573
+ return _context19.stop();
2574
+ }
2575
+ }
2576
+ }, _callee19, this);
2577
+ }));
2578
+
2579
+ function getSettings(_x17, _x18) {
2580
+ return _getSettings2.apply(this, arguments);
2581
+ }
2582
+
2583
+ return getSettings;
2584
+ }()
2585
+ /**
2586
+ * Save the given value into the corresponding cozy-app setting
2587
+ *
2588
+ * This methods will first query the cozy-app's settings before injecting the new value and then
2589
+ * save the new resulting settings into database
2590
+ *
2591
+ * @template {string} T
2592
+ *
2593
+ * @param {string} slug - the cozy-app's slug containing the setting (can be 'instance' for global settings)
2594
+ * @param {Record<string, any> | ((oldValue) => Record<T, any>)} itemsOrSetter - The new values of the settings to save. It can be a raw dictionnary, or a callback that should return a new dictionnary
2595
+ * @param {T[]=} setterKeys - The new values of the settings to save. It can be a raw dictionnary, or a callback that should return a new dictionnary
2596
+ * @returns {Promise<any>} - The result of the `client.save()` call
2597
+ */
2598
+
2599
+ }, {
2600
+ key: "saveAfterFetchSettings",
2601
+ value: function () {
2602
+ var _saveAfterFetchSettings2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee20(slug, itemsOrSetter, setterKeys) {
2603
+ return _regenerator.default.wrap(function _callee20$(_context20) {
2604
+ while (1) {
2605
+ switch (_context20.prev = _context20.next) {
2606
+ case 0:
2607
+ return _context20.abrupt("return", (0, _helpers2.saveAfterFetchSettings)(this, slug, itemsOrSetter, setterKeys));
2608
+
2609
+ case 1:
2610
+ case "end":
2611
+ return _context20.stop();
2612
+ }
2613
+ }
2614
+ }, _callee20, this);
2615
+ }));
2616
+
2617
+ function saveAfterFetchSettings(_x19, _x20, _x21) {
2618
+ return _saveAfterFetchSettings2.apply(this, arguments);
2619
+ }
2620
+
2621
+ return saveAfterFetchSettings;
2622
+ }()
2546
2623
  }], [{
2547
2624
  key: "fromOldClient",
2548
2625
  value: function fromOldClient(oldClient, options) {
@@ -2565,22 +2642,22 @@ var CozyClient = /*#__PURE__*/function () {
2565
2642
  }, {
2566
2643
  key: "fromOldOAuthClient",
2567
2644
  value: function () {
2568
- var _fromOldOAuthClient = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee19(oldClient, options) {
2645
+ var _fromOldOAuthClient = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee21(oldClient, options) {
2569
2646
  var credentials, oauthOptions, client;
2570
- return _regenerator.default.wrap(function _callee19$(_context19) {
2647
+ return _regenerator.default.wrap(function _callee21$(_context21) {
2571
2648
  while (1) {
2572
- switch (_context19.prev = _context19.next) {
2649
+ switch (_context21.prev = _context21.next) {
2573
2650
  case 0:
2574
2651
  if (!oldClient._oauth) {
2575
- _context19.next = 12;
2652
+ _context21.next = 12;
2576
2653
  break;
2577
2654
  }
2578
2655
 
2579
- _context19.next = 3;
2656
+ _context21.next = 3;
2580
2657
  return oldClient.authorize();
2581
2658
 
2582
2659
  case 3:
2583
- credentials = _context19.sent;
2660
+ credentials = _context21.sent;
2584
2661
  oauthOptions = {
2585
2662
  oauth: credentials.client,
2586
2663
  token: credentials.token,
@@ -2591,28 +2668,28 @@ var CozyClient = /*#__PURE__*/function () {
2591
2668
  }, oauthOptions), options));
2592
2669
 
2593
2670
  if (!client.loginPromise) {
2594
- _context19.next = 9;
2671
+ _context21.next = 9;
2595
2672
  break;
2596
2673
  }
2597
2674
 
2598
- _context19.next = 9;
2675
+ _context21.next = 9;
2599
2676
  return client.loginPromise;
2600
2677
 
2601
2678
  case 9:
2602
- return _context19.abrupt("return", client);
2679
+ return _context21.abrupt("return", client);
2603
2680
 
2604
2681
  case 12:
2605
2682
  throw new Error('Cannot instantiate a new client: old client is not an OAuth client. CozyClient.fromOldClient might be more suitable.');
2606
2683
 
2607
2684
  case 13:
2608
2685
  case "end":
2609
- return _context19.stop();
2686
+ return _context21.stop();
2610
2687
  }
2611
2688
  }
2612
- }, _callee19);
2689
+ }, _callee21);
2613
2690
  }));
2614
2691
 
2615
- function fromOldOAuthClient(_x17, _x18) {
2692
+ function fromOldOAuthClient(_x22, _x23) {
2616
2693
  return _fromOldOAuthClient.apply(this, arguments);
2617
2694
  }
2618
2695
 
@@ -2705,7 +2782,7 @@ var CozyClient = /*#__PURE__*/function () {
2705
2782
  CozyClient.hooks = CozyClient.hooks || {};
2706
2783
  CozyClient.fetchPolicies = _policies.default; //COZY_CLIENT_VERSION_PACKAGE in replaced by babel. See babel config
2707
2784
 
2708
- CozyClient.version = "46.8.0";
2785
+ CozyClient.version = "46.9.1";
2709
2786
 
2710
2787
  _microee.default.mixin(CozyClient);
2711
2788
 
@@ -38,7 +38,8 @@ var client = function client(implementations) {
38
38
  makeObservableQuery: jest.fn(),
39
39
  requestQuery: jest.fn(),
40
40
  all: jest.fn(),
41
- setStore: jest.fn()
41
+ setStore: jest.fn(),
42
+ fetchQueryAndGetFromState: jest.fn()
42
43
  };
43
44
  mockImplementations(base, implementations);
44
45
  return base;
@@ -63,7 +63,39 @@ Object.defineProperty(exports, "dehydrate", {
63
63
  return _dehydrateHelper.dehydrate;
64
64
  }
65
65
  });
66
+ Object.defineProperty(exports, "editSettings", {
67
+ enumerable: true,
68
+ get: function get() {
69
+ return _settings.editSettings;
70
+ }
71
+ });
72
+ Object.defineProperty(exports, "getQuery", {
73
+ enumerable: true,
74
+ get: function get() {
75
+ return _settings.getQuery;
76
+ }
77
+ });
78
+ Object.defineProperty(exports, "getSettings", {
79
+ enumerable: true,
80
+ get: function get() {
81
+ return _settings.getSettings;
82
+ }
83
+ });
84
+ Object.defineProperty(exports, "normalizeSettings", {
85
+ enumerable: true,
86
+ get: function get() {
87
+ return _settings.normalizeSettings;
88
+ }
89
+ });
90
+ Object.defineProperty(exports, "saveAfterFetchSettings", {
91
+ enumerable: true,
92
+ get: function get() {
93
+ return _settings.saveAfterFetchSettings;
94
+ }
95
+ });
66
96
 
67
97
  var _urlHelper = require("./urlHelper");
68
98
 
69
- var _dehydrateHelper = require("./dehydrateHelper");
99
+ var _dehydrateHelper = require("./dehydrateHelper");
100
+
101
+ var _settings = require("./settings");
@@ -0,0 +1,311 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.getQuery = exports.extractKeys = exports.editSettings = exports.normalizeSettings = exports.saveAfterFetchSettings = exports.getSettings = void 0;
9
+
10
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
11
+
12
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
13
+
14
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
15
+
16
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
17
+
18
+ var _CozyClient = _interopRequireDefault(require("../CozyClient"));
19
+
20
+ var _policies = _interopRequireDefault(require("../policies"));
21
+
22
+ var _dsl = require("../queries/dsl");
23
+
24
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
25
+
26
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
27
+
28
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
29
+
30
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
31
+
32
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
33
+
34
+ var defaultFetchPolicy = _policies.default.olderThan(60 * 60 * 1000);
35
+ /**
36
+ * Query the cozy-app settings corresponding to the given slug and
37
+ * extract the values corresponding to the given `keys`
38
+ *
39
+ * @template {string} T
40
+ *
41
+ * @param {CozyClient} client - Cozy client instance
42
+ * @param {string} slug - the cozy-app's slug containing the setting (can be 'instance' for global settings)
43
+ * @param {T[]} keys - The names of the settings to retrieve
44
+ * @returns {Promise<Record<T, any>>} - The values of the requested settings
45
+ */
46
+
47
+
48
+ var getSettings = /*#__PURE__*/function () {
49
+ var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(client, slug, keys) {
50
+ var query, currentSettingsResult, currentSettings;
51
+ return _regenerator.default.wrap(function _callee$(_context) {
52
+ while (1) {
53
+ switch (_context.prev = _context.next) {
54
+ case 0:
55
+ query = getQuery(slug);
56
+ _context.next = 3;
57
+ return client.fetchQueryAndGetFromState({
58
+ definition: query.definition,
59
+ options: query.options
60
+ });
61
+
62
+ case 3:
63
+ currentSettingsResult = _context.sent;
64
+ currentSettings = normalizeSettings(currentSettingsResult.data); // @ts-ignore
65
+
66
+ return _context.abrupt("return", extractKeys(currentSettings, keys));
67
+
68
+ case 6:
69
+ case "end":
70
+ return _context.stop();
71
+ }
72
+ }
73
+ }, _callee);
74
+ }));
75
+
76
+ return function getSettings(_x, _x2, _x3) {
77
+ return _ref.apply(this, arguments);
78
+ };
79
+ }();
80
+ /**
81
+ * Save the given value into the corresponding cozy-app setting
82
+ *
83
+ * This methods will first query the cozy-app's settings before injecting the new value and then
84
+ * save the new resulting settings into database
85
+ *
86
+ * @template {string} T
87
+ *
88
+ * @param {CozyClient} client - Cozy client instance
89
+ * @param {string} slug - the cozy-app's slug containing the setting (special cases are: 'instance' for global settings and 'bitwarden' for cozy-pass)
90
+ * @param {Record<string, any> | ((oldValue) => Record<T, any>)} itemsOrSetter - The new values of the settings to save. It can be a raw dictionnary, or a callback that should return a new dictionnary
91
+ * @param {T[]=} setterKeys - The new values of the settings to save. It can be a raw dictionnary, or a callback that should return a new dictionnary
92
+ * @returns {Promise<any>} - The result of the `client.save()` call
93
+ */
94
+
95
+
96
+ exports.getSettings = getSettings;
97
+
98
+ var saveAfterFetchSettings = /*#__PURE__*/function () {
99
+ var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(client, slug, itemsOrSetter, setterKeys) {
100
+ var query, currentSettingsResult, currentSettings, items, currentItems, _currentItems, newSettings;
101
+
102
+ return _regenerator.default.wrap(function _callee2$(_context2) {
103
+ while (1) {
104
+ switch (_context2.prev = _context2.next) {
105
+ case 0:
106
+ query = getQuery(slug);
107
+ _context2.next = 3;
108
+ return client.fetchQueryAndGetFromState({
109
+ definition: query.definition,
110
+ options: query.options
111
+ });
112
+
113
+ case 3:
114
+ currentSettingsResult = _context2.sent;
115
+ currentSettings = normalizeSettings(currentSettingsResult.data);
116
+ items = undefined;
117
+
118
+ if (typeof itemsOrSetter === 'function') {
119
+ currentItems = extractKeys(currentSettings, setterKeys);
120
+ items = itemsOrSetter(currentItems);
121
+ } else {
122
+ _currentItems = extractKeys(currentSettings, Object.keys(itemsOrSetter));
123
+ items = _objectSpread(_objectSpread({}, _currentItems), itemsOrSetter);
124
+ }
125
+
126
+ newSettings = editSettings(slug, currentSettings, items);
127
+ _context2.next = 10;
128
+ return client.save(newSettings);
129
+
130
+ case 10:
131
+ return _context2.abrupt("return", _context2.sent);
132
+
133
+ case 11:
134
+ case "end":
135
+ return _context2.stop();
136
+ }
137
+ }
138
+ }, _callee2);
139
+ }));
140
+
141
+ return function saveAfterFetchSettings(_x4, _x5, _x6, _x7) {
142
+ return _ref2.apply(this, arguments);
143
+ };
144
+ }();
145
+ /**
146
+ * Convert a result from a `client.query()` or a `useQuery()` that can be
147
+ * an object or an array of objects into a single object
148
+ *
149
+ * @param {Array | Object} data - Result from a client.query or a useQuery
150
+ * @returns {Object} A single object containing the setting data
151
+ */
152
+
153
+
154
+ exports.saveAfterFetchSettings = saveAfterFetchSettings;
155
+
156
+ var normalizeSettings = function normalizeSettings(data) {
157
+ var settingsData = Array.isArray(data) ? data[0] : data;
158
+ return settingsData || {};
159
+ };
160
+ /**
161
+ * Edit the given settings by injecting `value` into the `key` entry
162
+ * This methods takes care of the kind of settings that is edited as there are
163
+ * some exceptions in settings formats (i.e. `io.cozy.settings.instance`)
164
+ *
165
+ * @param {string} slug - the cozy-app's slug containing the setting (can be 'instance' for global settings)
166
+ * @param {Object} currentSettings - the Setting object (ideally from a `client.query()` or a `useQuery()` and normalized using `normalizeSettings`)
167
+ * @param {Record<string, unknown>} items - The new values for the settings
168
+ * @returns {Object} a new Setting object containing the new value
169
+ */
170
+
171
+
172
+ exports.normalizeSettings = normalizeSettings;
173
+
174
+ var editSettings = function editSettings(slug, currentSettings, items) {
175
+ var type = getDoctype(slug);
176
+ var newSettings = slug === 'instance' ? mergeInstance(currentSettings, items) : mergeSettings(currentSettings, type, items);
177
+ return newSettings;
178
+ };
179
+
180
+ exports.editSettings = editSettings;
181
+
182
+ var mergeInstance = function mergeInstance(currentSettings, items) {
183
+ var newSettings = _objectSpread(_objectSpread({
184
+ _id: currentSettings._id,
185
+ _type: currentSettings._type,
186
+ _rev: currentSettings.meta.rev
187
+ }, currentSettings), {}, {
188
+ attributes: _objectSpread({}, currentSettings.attributes)
189
+ });
190
+
191
+ for (var _i = 0, _Object$entries = Object.entries(items); _i < _Object$entries.length; _i++) {
192
+ var _Object$entries$_i = (0, _slicedToArray2.default)(_Object$entries[_i], 2),
193
+ key = _Object$entries$_i[0],
194
+ value = _Object$entries$_i[1];
195
+
196
+ newSettings[key] = value;
197
+ newSettings.attributes[key] = value;
198
+ }
199
+
200
+ return newSettings;
201
+ };
202
+
203
+ var mergeSettings = function mergeSettings(currentSettings, type, items) {
204
+ var newSettings = _objectSpread({
205
+ _type: type
206
+ }, currentSettings);
207
+
208
+ for (var _i2 = 0, _Object$entries2 = Object.entries(items); _i2 < _Object$entries2.length; _i2++) {
209
+ var _Object$entries2$_i = (0, _slicedToArray2.default)(_Object$entries2[_i2], 2),
210
+ key = _Object$entries2$_i[0],
211
+ value = _Object$entries2$_i[1];
212
+
213
+ newSettings[key] = value;
214
+ }
215
+
216
+ return newSettings;
217
+ };
218
+ /**
219
+ * Extract values from given settings for requested keys
220
+ *
221
+ * @template {string} T
222
+ *
223
+ * @param {Record<T, any>} settings - the Setting object (ideally from a `client.query()` or a `useQuery()` and normalized using `normalizeSettings`)
224
+ * @param {T[]} keys - The names of the settings to extract
225
+ * @returns {Record<T, any>} - Dictionnary containing the values for the requested keys
226
+ */
227
+
228
+
229
+ var extractKeys = function extractKeys(settings, keys) {
230
+ var result = {};
231
+
232
+ var _iterator = _createForOfIteratorHelper(keys),
233
+ _step;
234
+
235
+ try {
236
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
237
+ var key = _step.value;
238
+ // @ts-ignore
239
+ result[key] = settings[key];
240
+ } // @ts-ignore
241
+
242
+ } catch (err) {
243
+ _iterator.e(err);
244
+ } finally {
245
+ _iterator.f();
246
+ }
247
+
248
+ return result;
249
+ };
250
+ /**
251
+ * Create a Query that can be used to fetch the cozy-app settings for the given slug
252
+ *
253
+ * @param {string} slug - the cozy-app's slug containing the setting (special cases are: 'instance' for global settings and 'passwords' for bitwarden settings)
254
+ * @returns {import('../types').Query} - the Query that can be used to fetch the cozy-app settings
255
+ */
256
+
257
+
258
+ exports.extractKeys = extractKeys;
259
+
260
+ var getQuery = function getQuery(slug) {
261
+ if (slug === 'instance') {
262
+ return getNestedSettings(slug);
263
+ }
264
+
265
+ if (slug === 'passwords') {
266
+ return getNestedSettings('bitwarden');
267
+ }
268
+
269
+ return getRootSettings(slug);
270
+ };
271
+
272
+ exports.getQuery = getQuery;
273
+
274
+ var getRootSettings = function getRootSettings(slug) {
275
+ var settingsDoctype = getDoctype(slug);
276
+ var query = {
277
+ definition: (0, _dsl.Q)(settingsDoctype).limitBy(1),
278
+ options: {
279
+ as: settingsDoctype,
280
+ fetchPolicy: defaultFetchPolicy,
281
+ singleDocData: true
282
+ }
283
+ };
284
+ return query;
285
+ };
286
+
287
+ var getNestedSettings = function getNestedSettings(slug) {
288
+ var doctype = "io.cozy.settings";
289
+ var subDoctype = getDoctype(slug);
290
+ var query = {
291
+ definition: (0, _dsl.Q)(doctype).getById(subDoctype),
292
+ options: {
293
+ as: "".concat(doctype, "/").concat(subDoctype),
294
+ fetchPolicy: defaultFetchPolicy,
295
+ singleDocData: true
296
+ }
297
+ };
298
+ return query;
299
+ };
300
+
301
+ var getDoctype = function getDoctype(slug) {
302
+ if (['instance', 'bitwarden'].includes(slug)) {
303
+ return "io.cozy.settings.".concat(slug);
304
+ }
305
+
306
+ if (slug === 'passwords') {
307
+ return 'io.cozy.settings.bitwarden';
308
+ }
309
+
310
+ return "io.cozy.".concat(slug, ".settings");
311
+ };
@@ -0,0 +1,493 @@
1
+ import {
2
+ editSettings,
3
+ getSettings,
4
+ normalizeSettings,
5
+ saveAfterFetchSettings
6
+ } from './settings'
7
+ import { Q } from '../queries/dsl'
8
+
9
+ import * as mocks from '../__tests__/mocks'
10
+
11
+ describe('settings', () => {
12
+ describe('getSettings', () => {
13
+ it('should get settings for cozy-home', async () => {
14
+ const client = mocks.client()
15
+
16
+ client.fetchQueryAndGetFromState.mockResolvedValue({
17
+ data: [
18
+ {
19
+ some_key: 'some_value'
20
+ }
21
+ ]
22
+ })
23
+
24
+ // @ts-ignore
25
+ const result = await getSettings(client, 'home', ['some_key'])
26
+
27
+ const query = {
28
+ definition: Q('io.cozy.home.settings').limitBy(1),
29
+ options: {
30
+ as: 'io.cozy.home.settings',
31
+ fetchPolicy: expect.anything(),
32
+ singleDocData: true
33
+ }
34
+ }
35
+ expect(client.fetchQueryAndGetFromState).toHaveBeenCalledWith({
36
+ definition: query.definition,
37
+ options: query.options
38
+ })
39
+ expect(result.some_key).toEqual('some_value')
40
+ })
41
+
42
+ it('should get settings for mespapiers', async () => {
43
+ const client = mocks.client()
44
+
45
+ client.fetchQueryAndGetFromState.mockResolvedValue({
46
+ data: [
47
+ {
48
+ some_mespapiers_key: 'some_mespapiers_value'
49
+ }
50
+ ]
51
+ })
52
+
53
+ const result = await getSettings(
54
+ // @ts-ignore
55
+ client,
56
+ 'mespapiers',
57
+ ['some_mespapiers_key']
58
+ )
59
+
60
+ const query = {
61
+ definition: Q('io.cozy.mespapiers.settings').limitBy(1),
62
+ options: {
63
+ as: 'io.cozy.mespapiers.settings',
64
+ fetchPolicy: expect.anything(),
65
+ singleDocData: true
66
+ }
67
+ }
68
+ expect(client.fetchQueryAndGetFromState).toHaveBeenCalledWith({
69
+ definition: query.definition,
70
+ options: query.options
71
+ })
72
+ expect(result.some_mespapiers_key).toEqual('some_mespapiers_value')
73
+ })
74
+
75
+ it('should get settings for instance', async () => {
76
+ const client = mocks.client()
77
+
78
+ client.fetchQueryAndGetFromState.mockResolvedValue({
79
+ data: [
80
+ {
81
+ some_global_key: 'some_global_value'
82
+ }
83
+ ]
84
+ })
85
+
86
+ // @ts-ignore
87
+ const result = await getSettings(client, 'instance', ['some_global_key'])
88
+
89
+ const query = {
90
+ definition: Q('io.cozy.settings').getById('io.cozy.settings.instance'),
91
+ options: {
92
+ as: 'io.cozy.settings/io.cozy.settings.instance',
93
+ fetchPolicy: expect.anything(),
94
+ singleDocData: true
95
+ }
96
+ }
97
+ expect(client.fetchQueryAndGetFromState).toHaveBeenCalledWith({
98
+ definition: query.definition,
99
+ options: query.options
100
+ })
101
+ expect(result.some_global_key).toEqual('some_global_value')
102
+ })
103
+
104
+ it('should get settings for passwords', async () => {
105
+ const client = mocks.client()
106
+
107
+ client.fetchQueryAndGetFromState.mockResolvedValue({
108
+ data: [
109
+ {
110
+ some_pass_key: 'some_pass_value'
111
+ }
112
+ ]
113
+ })
114
+
115
+ // @ts-ignore
116
+ const result = await getSettings(client, 'passwords', ['some_pass_key'])
117
+
118
+ const query = {
119
+ definition: Q('io.cozy.settings').getById('io.cozy.settings.bitwarden'),
120
+ options: {
121
+ as: 'io.cozy.settings/io.cozy.settings.bitwarden',
122
+ fetchPolicy: expect.anything(),
123
+ singleDocData: true
124
+ }
125
+ }
126
+ expect(client.fetchQueryAndGetFromState).toHaveBeenCalledWith({
127
+ definition: query.definition,
128
+ options: query.options
129
+ })
130
+ expect(result.some_pass_key).toEqual('some_pass_value')
131
+ })
132
+
133
+ it('should return undefined if no setting is found in database', async () => {
134
+ const client = mocks.client()
135
+
136
+ client.fetchQueryAndGetFromState.mockResolvedValue({
137
+ data: [
138
+ {
139
+ some_other_key: 'some_other_value'
140
+ }
141
+ ]
142
+ })
143
+
144
+ // @ts-ignore
145
+ const result = await getSettings(client, 'home', ['some_key'])
146
+
147
+ expect(result.some_key).toBeUndefined()
148
+ })
149
+
150
+ it('should get settings for multiple keys', async () => {
151
+ const client = mocks.client()
152
+
153
+ client.fetchQueryAndGetFromState.mockResolvedValue({
154
+ data: [
155
+ {
156
+ some_key_1: 'some_value_1',
157
+ some_key_2: 'some_value_2',
158
+ some_key_3: 'some_value_3'
159
+ }
160
+ ]
161
+ })
162
+
163
+ // @ts-ignore
164
+ const result = await getSettings(client, 'home', [
165
+ 'some_key_1',
166
+ 'some_key_2'
167
+ ])
168
+
169
+ const query = {
170
+ definition: Q('io.cozy.home.settings').limitBy(1),
171
+ options: {
172
+ as: 'io.cozy.home.settings',
173
+ fetchPolicy: expect.anything(),
174
+ singleDocData: true
175
+ }
176
+ }
177
+ expect(client.fetchQueryAndGetFromState).toHaveBeenCalledWith({
178
+ definition: query.definition,
179
+ options: query.options
180
+ })
181
+ expect(result.some_key_1).toEqual('some_value_1')
182
+ expect(result.some_key_2).toEqual('some_value_2')
183
+ // @ts-ignore
184
+ expect(result.some_key_3).toBeUndefined()
185
+ })
186
+ })
187
+
188
+ describe('saveAfterFetchSettings', () => {
189
+ it('should set settings for instance', async () => {
190
+ const client = mocks.client()
191
+
192
+ client.fetchQueryAndGetFromState.mockResolvedValue({
193
+ data: [
194
+ {
195
+ id: 'io.cozy.settings.instance',
196
+ _id: 'io.cozy.settings.instance',
197
+ _type: 'io.cozy.settings',
198
+ type: 'io.cozy.settings',
199
+ attributes: {
200
+ some_setting: 'some_setting_value',
201
+ some_instance_key: 'some_instance_value'
202
+ },
203
+ meta: {
204
+ rev: 'SOME_UNIQ_REV_NUMBER'
205
+ },
206
+ some_setting: 'some_setting_value',
207
+ some_instance_key: 'some_instance_value'
208
+ }
209
+ ]
210
+ })
211
+
212
+ await saveAfterFetchSettings(
213
+ // @ts-ignore
214
+ client,
215
+ 'instance',
216
+ {
217
+ some_instance_key: 'some_new_instance_value'
218
+ }
219
+ )
220
+
221
+ const query = {
222
+ definition: Q('io.cozy.settings').getById('io.cozy.settings.instance'),
223
+ options: {
224
+ as: 'io.cozy.settings/io.cozy.settings.instance',
225
+ fetchPolicy: expect.anything(),
226
+ singleDocData: true
227
+ }
228
+ }
229
+ expect(client.fetchQueryAndGetFromState).toHaveBeenCalledWith({
230
+ definition: query.definition,
231
+ options: query.options
232
+ })
233
+ expect(client.save).toHaveBeenCalledWith({
234
+ id: 'io.cozy.settings.instance',
235
+ _id: 'io.cozy.settings.instance',
236
+ _type: 'io.cozy.settings',
237
+ type: 'io.cozy.settings',
238
+ _rev: 'SOME_UNIQ_REV_NUMBER',
239
+ attributes: {
240
+ some_setting: 'some_setting_value',
241
+ some_instance_key: 'some_new_instance_value'
242
+ },
243
+ some_setting: 'some_setting_value',
244
+ some_instance_key: 'some_new_instance_value',
245
+ meta: {
246
+ rev: 'SOME_UNIQ_REV_NUMBER'
247
+ }
248
+ })
249
+ })
250
+
251
+ it('should set settings for passwords', async () => {
252
+ const client = mocks.client()
253
+
254
+ client.fetchQueryAndGetFromState.mockResolvedValue({
255
+ data: [
256
+ {
257
+ _type: 'io.cozy.passwords.settings',
258
+ some_pass_key: 'some_pass_value'
259
+ }
260
+ ]
261
+ })
262
+
263
+ await saveAfterFetchSettings(
264
+ // @ts-ignore
265
+ client,
266
+ 'passwords',
267
+ { some_pass_key: 'some_new_pass_value' }
268
+ )
269
+
270
+ const query = {
271
+ definition: Q('io.cozy.settings').getById('io.cozy.settings.bitwarden'),
272
+ options: {
273
+ as: 'io.cozy.settings/io.cozy.settings.bitwarden',
274
+ fetchPolicy: expect.anything(),
275
+ singleDocData: true
276
+ }
277
+ }
278
+ expect(client.fetchQueryAndGetFromState).toHaveBeenCalledWith({
279
+ definition: query.definition,
280
+ options: query.options
281
+ })
282
+ expect(client.save).toHaveBeenCalledWith({
283
+ _type: 'io.cozy.passwords.settings',
284
+ some_pass_key: 'some_new_pass_value'
285
+ })
286
+ })
287
+
288
+ it('should set settings for passwords even if key does not exist', async () => {
289
+ const client = mocks.client()
290
+
291
+ client.fetchQueryAndGetFromState.mockResolvedValue({
292
+ data: [
293
+ {
294
+ _type: 'io.cozy.passwords.settings',
295
+ some_existing_pass_key: 'some_pass_value'
296
+ }
297
+ ]
298
+ })
299
+
300
+ await saveAfterFetchSettings(
301
+ // @ts-ignore
302
+ client,
303
+ 'passwords',
304
+ { some_new_pass_key: 'some_new_pass_value' }
305
+ )
306
+
307
+ const query = {
308
+ definition: Q('io.cozy.settings').getById('io.cozy.settings.bitwarden'),
309
+ options: {
310
+ as: 'io.cozy.settings/io.cozy.settings.bitwarden',
311
+ fetchPolicy: expect.anything(),
312
+ singleDocData: true
313
+ }
314
+ }
315
+ expect(client.fetchQueryAndGetFromState).toHaveBeenCalledWith({
316
+ definition: query.definition,
317
+ options: query.options
318
+ })
319
+ expect(client.save).toHaveBeenCalledWith({
320
+ _type: 'io.cozy.passwords.settings',
321
+ some_existing_pass_key: 'some_pass_value',
322
+ some_new_pass_key: 'some_new_pass_value'
323
+ })
324
+ })
325
+
326
+ it('should set settings for passwords using method', async () => {
327
+ const client = mocks.client()
328
+
329
+ client.fetchQueryAndGetFromState.mockResolvedValue({
330
+ data: [
331
+ {
332
+ _type: 'io.cozy.passwords.settings',
333
+ some_pass_key: 1
334
+ }
335
+ ]
336
+ })
337
+
338
+ await saveAfterFetchSettings(
339
+ // @ts-ignore
340
+ client,
341
+ 'passwords',
342
+ currentValue => ({
343
+ ...currentValue,
344
+ some_pass_key: currentValue.some_pass_key + 1
345
+ }),
346
+ ['some_pass_key']
347
+ )
348
+
349
+ const query = {
350
+ definition: Q('io.cozy.settings').getById('io.cozy.settings.bitwarden'),
351
+ options: {
352
+ as: 'io.cozy.settings/io.cozy.settings.bitwarden',
353
+ fetchPolicy: expect.anything(),
354
+ singleDocData: true
355
+ }
356
+ }
357
+ expect(client.fetchQueryAndGetFromState).toHaveBeenCalledWith({
358
+ definition: query.definition,
359
+ options: query.options
360
+ })
361
+ expect(client.save).toHaveBeenCalledWith({
362
+ _type: 'io.cozy.passwords.settings',
363
+ some_pass_key: 2
364
+ })
365
+ })
366
+ })
367
+
368
+ describe('normalizeSettings', () => {
369
+ it('should normalize data array into object', () => {
370
+ const result = normalizeSettings([
371
+ {
372
+ id: 'SOME_DOCUMENT_ID',
373
+ _id: 'SOME_DOCUMENT_ID',
374
+ _type: 'io.cozy.home.settings',
375
+ _rev: 'SOME_DOCUMENT_REV',
376
+ cozyMetadata: {
377
+ createdAt: '2024-04-03T15:00:48.961Z',
378
+ metadataVersion: 1,
379
+ updatedAt: '2024-04-03T15:00:48.961Z',
380
+ updatedByApps: []
381
+ },
382
+ some_attribue: true
383
+ }
384
+ ])
385
+
386
+ expect(result).toStrictEqual({
387
+ id: 'SOME_DOCUMENT_ID',
388
+ _id: 'SOME_DOCUMENT_ID',
389
+ _type: 'io.cozy.home.settings',
390
+ _rev: 'SOME_DOCUMENT_REV',
391
+ cozyMetadata: {
392
+ createdAt: '2024-04-03T15:00:48.961Z',
393
+ metadataVersion: 1,
394
+ updatedAt: '2024-04-03T15:00:48.961Z',
395
+ updatedByApps: []
396
+ },
397
+ some_attribue: true
398
+ })
399
+ })
400
+
401
+ it('should normalize data object into object', () => {
402
+ const result = normalizeSettings({
403
+ id: 'io.cozy.settings.instance',
404
+ _id: 'io.cozy.settings.instance',
405
+ _type: 'io.cozy.settings',
406
+ type: 'io.cozy.settings',
407
+ attributes: {
408
+ some_attributes: 'some_value'
409
+ },
410
+ meta: {
411
+ rev: '2-8803d6fda4bd3216e3fbeb0a181979d5'
412
+ },
413
+ links: {
414
+ self: '/settings/instance'
415
+ },
416
+ some_attributes: 'some_value'
417
+ })
418
+
419
+ expect(result).toStrictEqual({
420
+ id: 'io.cozy.settings.instance',
421
+ _id: 'io.cozy.settings.instance',
422
+ _type: 'io.cozy.settings',
423
+ type: 'io.cozy.settings',
424
+ attributes: {
425
+ some_attributes: 'some_value'
426
+ },
427
+ meta: {
428
+ rev: '2-8803d6fda4bd3216e3fbeb0a181979d5'
429
+ },
430
+ links: {
431
+ self: '/settings/instance'
432
+ },
433
+ some_attributes: 'some_value'
434
+ })
435
+ })
436
+ })
437
+ describe('editSettings', () => {
438
+ it('should inject value into settings', () => {
439
+ const result = editSettings(
440
+ 'passwords',
441
+ {
442
+ _type: 'io.cozy.passwords.settings',
443
+ some_pass_key: 'some_pass_value'
444
+ },
445
+ { some_pass_key: 'some_new_pass_value' }
446
+ )
447
+
448
+ expect(result).toStrictEqual({
449
+ _type: 'io.cozy.passwords.settings',
450
+ some_pass_key: 'some_new_pass_value'
451
+ })
452
+ })
453
+
454
+ it('should inject _rev value and edit attributes for instance settings', () => {
455
+ const result = editSettings(
456
+ 'instance',
457
+ {
458
+ id: 'io.cozy.settings.instance',
459
+ _id: 'io.cozy.settings.instance',
460
+ _type: 'io.cozy.settings',
461
+ type: 'io.cozy.settings',
462
+ attributes: {
463
+ some_setting: 'some_setting_value',
464
+ some_instance_key: 'some_instance_value'
465
+ },
466
+ meta: {
467
+ rev: 'SOME_UNIQ_REV_NUMBER'
468
+ },
469
+ some_setting: 'some_setting_value',
470
+ some_instance_key: 'some_instance_value'
471
+ },
472
+ { some_instance_key: 'some_new_instance_value' }
473
+ )
474
+
475
+ expect(result).toStrictEqual({
476
+ id: 'io.cozy.settings.instance',
477
+ _id: 'io.cozy.settings.instance',
478
+ _type: 'io.cozy.settings',
479
+ type: 'io.cozy.settings',
480
+ _rev: 'SOME_UNIQ_REV_NUMBER',
481
+ attributes: {
482
+ some_setting: 'some_setting_value',
483
+ some_instance_key: 'some_new_instance_value'
484
+ },
485
+ some_setting: 'some_setting_value',
486
+ some_instance_key: 'some_new_instance_value',
487
+ meta: {
488
+ rev: 'SOME_UNIQ_REV_NUMBER'
489
+ }
490
+ })
491
+ })
492
+ })
493
+ })
@@ -67,6 +67,12 @@ Object.defineProperty(exports, "useInstanceInfo", {
67
67
  return _useInstanceInfo.useInstanceInfo;
68
68
  }
69
69
  });
70
+ Object.defineProperty(exports, "useSettings", {
71
+ enumerable: true,
72
+ get: function get() {
73
+ return _useSetting.useSettings;
74
+ }
75
+ });
70
76
 
71
77
  var _useAppLinkWithStoreFallback = _interopRequireDefault(require("./useAppLinkWithStoreFallback"));
72
78
 
@@ -84,4 +90,6 @@ var _useQueryAll = _interopRequireDefault(require("./useQueryAll"));
84
90
 
85
91
  var _useMutation = require("./useMutation");
86
92
 
87
- var _useInstanceInfo = require("./useInstanceInfo");
93
+ var _useInstanceInfo = require("./useInstanceInfo");
94
+
95
+ var _useSetting = require("./useSetting");
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.useSettings = void 0;
9
+
10
+ var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
11
+
12
+ var _react = require("react");
13
+
14
+ var _helpers = require("../helpers");
15
+
16
+ var _useMutation2 = require("./useMutation");
17
+
18
+ var _useQuery2 = _interopRequireDefault(require("./useQuery"));
19
+
20
+ var _utils = require("../utils");
21
+
22
+ var _settings = require("../helpers/settings");
23
+
24
+ /**
25
+ * Query the cozy-app settings corresponding to the given slug and
26
+ * return:
27
+ * - the values corresponding to the given `keys`
28
+ * - the `save()` method that can be used to edit the setting's value
29
+ * - the query that manages the state during the fetching of the setting
30
+ * - the mutation that manages the state during the saving of the setting
31
+ *
32
+ * @template {string} T
33
+ *
34
+ * @param {string} slug - the cozy-app's slug containing the setting (special cases are: 'instance' for global settings and 'passwords' for bitwarden settings)
35
+ * @param {T[]} keys - The name of the setting to retrieve
36
+ * @returns {import("../types").UseSettingsReturnValue<T>}
37
+ */
38
+ var useSettings = function useSettings(slug, keys) {
39
+ var query = (0, _helpers.getQuery)(slug);
40
+
41
+ var _useQuery = (0, _useQuery2.default)(query.definition, query.options),
42
+ settingsData = _useQuery.data,
43
+ settingsQuery = (0, _objectWithoutProperties2.default)(_useQuery, ["data"]);
44
+
45
+ var _useMutation = (0, _useMutation2.useMutation)(),
46
+ mutate = _useMutation.mutate,
47
+ mutation = (0, _objectWithoutProperties2.default)(_useMutation, ["mutate"]);
48
+
49
+ var save = (0, _react.useCallback)(function (items) {
50
+ var settings = (0, _helpers.normalizeSettings)(settingsData);
51
+ var newSettings = (0, _helpers.editSettings)(slug, settings, items);
52
+ return mutate(newSettings);
53
+ }, [mutate, settingsData, slug]);
54
+ var settings = (0, _helpers.normalizeSettings)(settingsData);
55
+ var settingValue = (0, _utils.hasQueryBeenLoaded)(settingsQuery) ? (0, _settings.extractKeys)(settings, keys) : undefined;
56
+ return {
57
+ query: settingsQuery,
58
+ values: settingValue,
59
+ save: save,
60
+ mutation: mutation
61
+ };
62
+ };
63
+
64
+ exports.useSettings = useSettings;
package/dist/types.js CHANGED
@@ -250,7 +250,7 @@ var _dsl = require("./queries/dsl");
250
250
  */
251
251
 
252
252
  /**
253
- * @typedef {object} QueryState
253
+ * @typedef {object} QueryStateWithoutData
254
254
  * @property {string} id
255
255
  * @property {QueryDefinition} definition
256
256
  * @property {QueryFetchStatus} fetchStatus
@@ -262,12 +262,20 @@ var _dsl = require("./queries/dsl");
262
262
  * @property {boolean} hasMore
263
263
  * @property {number} count
264
264
  * @property {number} fetchedPagesCount
265
- * @property {object|Array} data
266
265
  * @property {string} bookmark
267
266
  * @property {object} [execution_stats]
268
267
  * @property {QueryOptions} [options]
269
268
  */
270
269
 
270
+ /**
271
+ * @typedef {object} QueryStateData
272
+ * @property {object|Array} data
273
+ */
274
+
275
+ /**
276
+ * @typedef {QueryStateWithoutData & QueryStateData} QueryState
277
+ */
278
+
271
279
  /**
272
280
  * @typedef {object} AutoUpdateOptions
273
281
  * @param {boolean} update - Should documents be updated in the query (default: true)
@@ -290,6 +298,12 @@ var _dsl = require("./queries/dsl");
290
298
  * compatibility but will be set to true in the future.
291
299
  */
292
300
 
301
+ /**
302
+ * @typedef {object} Query
303
+ * @property {QueryDefinition} definition
304
+ * @property {QueryOptions} options
305
+ */
306
+
293
307
  /**
294
308
  * @typedef {object} FetchMoreAble
295
309
  * @property {Function} fetchMore
@@ -305,13 +319,39 @@ var _dsl = require("./queries/dsl");
305
319
  */
306
320
 
307
321
  /**
308
- * @typedef {object} UseMutationReturnValue
309
- * @property {Function} mutate - Function to save the document
322
+ * @typedef {object} UseMutationWithoutMutate
310
323
  * @property {QueryFetchStatus} mutationStatus - Status of the current mutation
311
324
  * @property {object} [error] - Error if the mutation failed
312
325
  * @property {object} [data] - Data return after the mutation
313
326
  */
314
327
 
328
+ /**
329
+ * @typedef {object} UseMutationMutate
330
+ * @property {Function} mutate - Function to save the document
331
+ */
332
+
333
+ /**
334
+ * @typedef {UseMutationWithoutMutate & UseMutationMutate} UseMutationReturnValue
335
+ */
336
+
337
+ /**
338
+ * Update the setting with corresponding value and save it.
339
+ *
340
+ * @template {string} T
341
+ *
342
+ * @callback SaveSettingsFunction
343
+ * @param {Partial<Record<T, any>>} items - The new setting's value
344
+ */
345
+
346
+ /**
347
+ * @template {string} T
348
+ * @typedef {object} UseSettingsReturnValue
349
+ * @property {Record<T, any> | undefined} values - The setting's value
350
+ * @property {SaveSettingsFunction<T>} save - Function to edit the setting
351
+ * @property {QueryStateWithoutData} query - Function to edit the setting
352
+ * @property {UseMutationWithoutMutate} mutation - Status of the current mutation
353
+ */
354
+
315
355
  /**
316
356
  * A reference to a document
317
357
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-client",
3
- "version": "46.8.0",
3
+ "version": "46.9.1",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.node.js",
6
6
  "browser": "dist/index.js",
@@ -75,5 +75,5 @@
75
75
  "react-native-ios11-devicecheck": "https://github.com/cozy/react-native-devicecheck#app-attest-v0.1"
76
76
  },
77
77
  "sideEffects": false,
78
- "gitHead": "adc2786ac0ebde0b64aff738930aef5ab67423a2"
78
+ "gitHead": "24ff9fa1c4abd0573c1f49fce91155732e657d46"
79
79
  }
@@ -414,6 +414,10 @@ declare class CozyClient {
414
414
  * `getQueryFromState` or directly using `<Query />`. `<Query />` automatically
415
415
  * executes its query when mounted if no fetch policy has been indicated.
416
416
  *
417
+ * If the query is called under the fetch policy's delay, then the query
418
+ * is not executed and nothing is returned. If you need a result anyway,
419
+ * please use `fetchQueryAndGetFromState` instead
420
+ *
417
421
  * @param {QueryDefinition} queryDefinition - Definition that will be executed
418
422
  * @param {import("./types").QueryOptions} [options] - Options
419
423
  * @returns {Promise<import("./types").QueryResult>}
@@ -713,6 +717,31 @@ declare class CozyClient {
713
717
  * @param {import("./types").AppMetadata} newAppMetadata AppMetadata to update
714
718
  */
715
719
  setAppMetadata(newAppMetadata: import("./types").AppMetadata): void;
720
+ /**
721
+ * Query the cozy-app settings corresponding to the given slug and
722
+ * extract the value corresponding to the given `key`
723
+ *
724
+ * @template {string} T
725
+ *
726
+ * @param {string} slug - the cozy-app's slug containing the setting (can be 'instance' for global settings)
727
+ * @param {T[]} keys - The names of the settings to retrieve
728
+ * @returns {Promise<Record<T, any>>} - The value of the requested setting
729
+ */
730
+ getSettings<T extends string>(slug: string, keys: T[]): Promise<Record<T, any>>;
731
+ /**
732
+ * Save the given value into the corresponding cozy-app setting
733
+ *
734
+ * This methods will first query the cozy-app's settings before injecting the new value and then
735
+ * save the new resulting settings into database
736
+ *
737
+ * @template {string} T
738
+ *
739
+ * @param {string} slug - the cozy-app's slug containing the setting (can be 'instance' for global settings)
740
+ * @param {Record<string, any> | ((oldValue) => Record<T, any>)} itemsOrSetter - The new values of the settings to save. It can be a raw dictionnary, or a callback that should return a new dictionnary
741
+ * @param {T[]=} setterKeys - The new values of the settings to save. It can be a raw dictionnary, or a callback that should return a new dictionnary
742
+ * @returns {Promise<any>} - The result of the `client.save()` call
743
+ */
744
+ saveAfterFetchSettings<T_2 extends string>(slug: string, itemsOrSetter: Record<string, any> | ((oldValue: any) => Record<T_2, any>), setterKeys?: T_2[]): Promise<any>;
716
745
  }
717
746
  declare namespace CozyClient {
718
747
  export const hooks: {};
@@ -8,6 +8,7 @@ export function client(implementations: any): {
8
8
  requestQuery: jest.Mock<any, any>;
9
9
  all: jest.Mock<any, any>;
10
10
  setStore: jest.Mock<any, any>;
11
+ fetchQueryAndGetFromState: jest.Mock<any, any>;
11
12
  };
12
13
  export function observableQuery(implementations: any): {
13
14
  currentResult: jest.Mock<any, any>;
@@ -1,2 +1,3 @@
1
1
  export { dehydrate } from "./dehydrateHelper";
2
2
  export { deconstructCozyWebLinkWithSlug, deconstructRedirectLink, generateWebLink, ensureFirstSlash, rootCozyUrl, InvalidRedirectLinkError, InvalidCozyUrlError, InvalidProtocolError, BlockedCozyError } from "./urlHelper";
3
+ export { editSettings, getQuery, getSettings, normalizeSettings, saveAfterFetchSettings } from "./settings";
@@ -0,0 +1,7 @@
1
+ export function getSettings<T extends string>(client: CozyClient, slug: string, keys: T[]): Promise<Record<T, any>>;
2
+ export function saveAfterFetchSettings<T extends string>(client: CozyClient, slug: string, itemsOrSetter: Record<string, any> | ((oldValue: any) => Record<T, any>), setterKeys?: T[]): Promise<any>;
3
+ export function normalizeSettings(data: any[] | any): any;
4
+ export function editSettings(slug: string, currentSettings: any, items: Record<string, unknown>): any;
5
+ export function extractKeys<T extends string>(settings: Record<T, any>, keys: T[]): Record<T, any>;
6
+ export function getQuery(slug: string): import('../types').Query;
7
+ import CozyClient from "../CozyClient";
@@ -6,4 +6,5 @@ export { default as useAppsInMaintenance } from "./useAppsInMaintenance";
6
6
  export { default as useQueryAll } from "./useQueryAll";
7
7
  export { useMutation } from "./useMutation";
8
8
  export { useInstanceInfo } from "./useInstanceInfo";
9
+ export { useSettings } from "./useSetting";
9
10
  export { default as useQuery, useQueries } from "./useQuery";
@@ -0,0 +1 @@
1
+ export function useSettings<T extends string>(slug: string, keys: T[]): import("../types").UseSettingsReturnValue<T>;
package/types/types.d.ts CHANGED
@@ -481,7 +481,7 @@ export type IndexedDocuments = {
481
481
  export type DocumentsStateSlice = {
482
482
  [x: string]: Record<string, CozyClientDocument>;
483
483
  };
484
- export type QueryState = {
484
+ export type QueryStateWithoutData = {
485
485
  id: string;
486
486
  definition: QueryDefinition;
487
487
  fetchStatus: QueryFetchStatus;
@@ -493,11 +493,14 @@ export type QueryState = {
493
493
  hasMore: boolean;
494
494
  count: number;
495
495
  fetchedPagesCount: number;
496
- data: object | any[];
497
496
  bookmark: string;
498
497
  execution_stats?: object;
499
498
  options?: QueryOptions;
500
499
  };
500
+ export type QueryStateData = {
501
+ data: object | any[];
502
+ };
503
+ export type QueryState = QueryStateWithoutData & QueryStateData;
501
504
  export type AutoUpdateOptions = any;
502
505
  export type QueryOptions = {
503
506
  /**
@@ -539,18 +542,18 @@ export type QueryOptions = {
539
542
  */
540
543
  singleDocData?: boolean;
541
544
  };
545
+ export type Query = {
546
+ definition: QueryDefinition;
547
+ options: QueryOptions;
548
+ };
542
549
  export type FetchMoreAble = {
543
550
  fetchMore: Function;
544
551
  };
545
552
  export type FetchAble = {
546
553
  fetch: Function;
547
554
  };
548
- export type UseQueryReturnValue = QueryState & FetchMoreAble & FetchAble;
549
- export type UseMutationReturnValue = {
550
- /**
551
- * - Function to save the document
552
- */
553
- mutate: Function;
555
+ export type UseQueryReturnValue = QueryStateWithoutData & QueryStateData & FetchMoreAble & FetchAble;
556
+ export type UseMutationWithoutMutate = {
554
557
  /**
555
558
  * - Status of the current mutation
556
559
  */
@@ -564,6 +567,35 @@ export type UseMutationReturnValue = {
564
567
  */
565
568
  data?: object;
566
569
  };
570
+ export type UseMutationMutate = {
571
+ /**
572
+ * - Function to save the document
573
+ */
574
+ mutate: Function;
575
+ };
576
+ export type UseMutationReturnValue = UseMutationWithoutMutate & UseMutationMutate;
577
+ /**
578
+ * Update the setting with corresponding value and save it.
579
+ */
580
+ export type SaveSettingsFunction<T extends string> = (items: Partial<Record<T, any>>) => any;
581
+ export type UseSettingsReturnValue<T extends string> = {
582
+ /**
583
+ * - The setting's value
584
+ */
585
+ values: Record<T, any>;
586
+ /**
587
+ * - Function to edit the setting
588
+ */
589
+ save: SaveSettingsFunction<T>;
590
+ /**
591
+ * - Function to edit the setting
592
+ */
593
+ query: QueryStateWithoutData;
594
+ /**
595
+ * - Status of the current mutation
596
+ */
597
+ mutation: UseMutationWithoutMutate;
598
+ };
567
599
  /**
568
600
  * A reference to a document
569
601
  */