@qikdev/sdk 0.2.3 → 0.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qikdev/sdk",
3
- "version": "0.2.3",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Promise based Javascript SDK",
6
6
  "main": "./dist/main.js",
@@ -492,8 +492,28 @@ var QikAccess = function (QikCore) {
492
492
 
493
493
  //////////////////////////////////
494
494
 
495
+ //The user should be able to list any scopes that they have
496
+ //permission to do things in.
497
+ if (ANY_ACTION == "listany" || OWN_ACTION == "listown") {
498
+ if (type === "scope") {
499
+ var itemID = QikCore.utils.id(item);
500
+ return !!user.permissions[itemID];
501
+ }
502
+ }
503
+
504
+ //////////////////////////////////
505
+
495
506
  var itemScopes = QikCore.utils.ids(item.meta.scopes || []);
496
507
 
508
+ //Scopes don't have meta.scopes, instead use the scope's
509
+ //path (ancestors) plus the scope's own ID
510
+ if (type === "scope") {
511
+ itemScopes = [
512
+ ...QikCore.utils.ids(item.path || []),
513
+ QikCore.utils.id(item),
514
+ ];
515
+ }
516
+
497
517
  //////////////////////////////////
498
518
 
499
519
  var actionAnyScopesHash;
@@ -2,22 +2,7 @@ import axios from "axios";
2
2
  import qs from "qs";
3
3
  import { version } from "../version.js";
4
4
 
5
- import {
6
- cacheAdapterEnhancer,
7
- throttleAdapterEnhancer,
8
- Cache,
9
- } from "axios-extensions";
10
-
11
- function isString(value) {
12
- const type = typeof value;
13
- return (
14
- type === "string" ||
15
- (type === "object" &&
16
- value != null &&
17
- !Array.isArray(value) &&
18
- getTag(value) == "[object String]")
19
- );
20
- }
5
+
21
6
 
22
7
  /**
23
8
  * Creates a new instance of Axios, with automatic authentication and token refreshing functionality.
@@ -192,71 +177,6 @@ var QikAPI = function (qik) {
192
177
 
193
178
  //////////////////////////////////////////////////////////////////////////////
194
179
 
195
- /**
196
- *
197
- * Make a GET request to the API
198
- * @alias api.get
199
- * @param {Object} endpoint The endpoint to request
200
- * @param {Object} options The options to pass to axios for making the request
201
- * @example
202
- *
203
- * const result = await sdk.api.get('/user');
204
- */
205
- var f = function () {};
206
-
207
- /**
208
- *
209
- *
210
- * @alias api.post
211
- * @description Make a POST request to the API
212
- * @param {Object} endpoint The endpoint to request
213
- * @param {Object} body The post body to send with the request
214
- * @param {Object} options The options to pass to axios for making the request
215
- * @example
216
- *
217
- * const result = await sdk.api.post('/login', {username:'', password:''});
218
- */
219
- var f = function () {};
220
-
221
- /**
222
- *
223
- * Make a PUT request to the API
224
- * @alias api.put
225
- * @param {Object} endpoint The endpoint to request
226
- * @param {Object} body The post body to send with the request
227
- * @param {Object} options The options to pass to axios for making the request
228
- * @example
229
- *
230
- * const result = await sdk.api.put('/content/61eca4746971e75c1fc670cf', {title:'A new title'});
231
- */
232
- var f = function () {};
233
-
234
- /**
235
- *
236
- * Make a PATCH request to the API
237
- * @alias api.patch
238
- * @param {Object} endpoint The endpoint to request
239
- * @param {Object} body The post body to send with the request
240
- * @param {Object} options The options to pass to axios for making the request
241
- * @example
242
- *
243
- * const result = await sdk.api.patch('/content/61eca4746971e75c1fc670cf', {title:'A new title'});
244
- */
245
- var f = function () {};
246
-
247
- /**
248
- *
249
- * Make a DELETE request to the API
250
- * @alias api.delete
251
- * @param {Object} endpoint The endpoint to request
252
- * @param {Object} body The post body to send with the request
253
- * @param {Object} options The options to pass to axios for making the request
254
- * @example
255
- *
256
- * const result = await sdk.api.delete('/content/61eca4746971e75c1fc670cf');
257
- */
258
- var f = function () {};
259
-
260
180
  function createNewAxios(adapter) {
261
181
  var instance = axios.create({
262
182
  paramsSerializer: (params) =>
@@ -370,8 +290,6 @@ var QikAPI = function (qik) {
370
290
  //Not found
371
291
  break;
372
292
  default:
373
- //Some other error, likely a problem connecting to the server
374
- // console.log('qik.api > connection error', status, err);
375
293
  break;
376
294
  }
377
295
 
@@ -387,20 +305,9 @@ var QikAPI = function (qik) {
387
305
  /////////////////////////////////////////////////////
388
306
 
389
307
  function retrieveIDs(data) {
390
- var dataString;
391
-
392
- if (_isString(data)) {
393
- dataString = data;
394
- } else {
395
- dataString = JSON.stringify(data);
396
- }
397
-
398
- //Find all mongo ids included in the object
399
- var myregexp = /[0-9a-fA-F]{24}/g;
400
- var matches = dataString.match(myregexp);
401
-
402
- //Make sure the matches are unique
403
- return [...new Set(matches)];
308
+ const text = typeof data === "string" ? data : JSON.stringify(data);
309
+ const matches = text.match(/\b[0-9a-f]{24}\b/gi);
310
+ return matches ? [...new Set(matches)] : [];
404
311
  }
405
312
 
406
313
  ///////////////////////////////////////
@@ -276,19 +276,19 @@ var QikAuth = function(qik) {
276
276
 
277
277
  if (!credentials) {
278
278
  return reject({
279
- message: 'Missing credentials!',
279
+ message: 'Login requires an email and password',
280
280
  })
281
281
  }
282
282
 
283
283
  if (!credentials.email || !credentials.email.length) {
284
284
  return reject({
285
- message: 'Username was not provided',
285
+ message: 'An email address is required to log in',
286
286
  })
287
287
  }
288
288
 
289
289
  if (!credentials.password || !credentials.password.length) {
290
290
  return reject({
291
- message: 'Password was not provided',
291
+ message: 'A password is required to log in',
292
292
  })
293
293
  }
294
294
 
@@ -362,44 +362,44 @@ var QikAuth = function(qik) {
362
362
 
363
363
  if (!credentials) {
364
364
  return reject({
365
- message: 'No details provided',
365
+ message: 'Signup details are required',
366
366
  })
367
367
  }
368
368
 
369
369
  if (!credentials.firstName || !credentials.firstName.length) {
370
370
  return reject({
371
- message: 'First Name was not provided',
371
+ message: 'Please provide a first name',
372
372
  })
373
373
  }
374
374
 
375
375
  if (!credentials.lastName || !credentials.lastName.length) {
376
376
  return reject({
377
- message: 'Last Name was not provided',
377
+ message: 'Please provide a last name',
378
378
  })
379
379
  }
380
380
 
381
381
  if (!credentials.email || !credentials.email.length) {
382
382
  return reject({
383
- message: 'Email/Username was not provided',
383
+ message: 'An email address is required to sign up',
384
384
  })
385
385
  }
386
386
 
387
387
 
388
388
  if (!credentials.password || !credentials.password.length) {
389
389
  return reject({
390
- message: 'Password was not provided',
390
+ message: 'A password is required to sign up',
391
391
  })
392
392
  }
393
393
 
394
394
  if (!credentials.confirmPassword || !credentials.confirmPassword.length) {
395
395
  return reject({
396
- message: 'Confirm Password was not provided',
396
+ message: 'Please confirm your password',
397
397
  })
398
398
  }
399
399
 
400
400
  if (credentials.confirmPassword != credentials.password) {
401
401
  return reject({
402
- message: 'Your passwords do not match',
402
+ message: 'Password and confirmation do not match',
403
403
  })
404
404
  }
405
405
 
@@ -568,13 +568,13 @@ var QikAuth = function(qik) {
568
568
 
569
569
  if (!details) {
570
570
  return Promise.reject({
571
- message: 'No details were provided for password reset request',
571
+ message: 'Please provide your account details to reset your password',
572
572
  })
573
573
  }
574
574
 
575
575
  if (!details.email || !details.email.length) {
576
576
  return Promise.reject({
577
- message: 'Email is required but was not provided',
577
+ message: 'An email address is required for password reset',
578
578
  })
579
579
  }
580
580
 
@@ -738,8 +738,6 @@ var QikAuth = function(qik) {
738
738
 
739
739
  ///////////////////////////////////////////////////
740
740
 
741
- var retryCount = 0;
742
-
743
741
  /**
744
742
  * @alias auth.sync
745
743
  * @description A useful function to sync the current user session with the server.
@@ -756,7 +754,6 @@ var QikAuth = function(qik) {
756
754
  if (res.data) {
757
755
  const currentUser = storageAdapter.getUser();
758
756
  if (currentUser) {
759
- // Update the session data within the current user object
760
757
  const updatedUser = { ...currentUser };
761
758
  if (updatedUser.session) {
762
759
  Object.assign(updatedUser.session, res.data);
@@ -765,28 +762,17 @@ var QikAuth = function(qik) {
765
762
  }
766
763
  service.set(updatedUser);
767
764
  } else {
768
- // No current user, set the response data as new user
769
765
  service.set(res.data);
770
766
  }
771
767
  } else {
772
768
  service.set(null);
773
769
  }
774
770
 
775
- retryCount = 0;
776
771
  dispatch();
777
772
  })
778
773
  .catch(function(err) {
779
-
780
- // if (retryCount > 2) {
781
774
  service.set(null);
782
- retryCount = 0;
783
775
  dispatch();
784
- // } else {
785
-
786
- // retryCount++;
787
- // service.sync();
788
- // }
789
-
790
776
  });
791
777
  }
792
778
 
@@ -23,13 +23,11 @@ var QikCache = {
23
23
  */
24
24
  reset() {
25
25
  Object.entries(caches).forEach(([key, cache]) => {
26
- // console.log(`Reset ${key} cache`, cache);
27
26
  if(cache.clear) {
28
27
  cache.clear()
29
28
  } else if(cache.reset) {
30
29
  cache.reset()
31
30
  }
32
-
33
31
  })
34
32
  },
35
33
 
@@ -48,10 +46,7 @@ var QikCache = {
48
46
  return caches[key];
49
47
  }
50
48
  caches[key] = new Cache(options)
51
-
52
- // console.log('Created new cache', key);
53
49
  return caches[key];
54
-
55
50
  }
56
51
  }
57
52
 
@@ -1,5 +1,3 @@
1
- // if (process.browser) {
2
-
3
1
  import QikAPI from './qik.api.js';
4
2
  import QikAuth from './qik.auth.js';
5
3
  import QikUtils from './qik.utils.js';
@@ -87,8 +85,6 @@ export default function(options) {
87
85
  ///////////////////////////////////////
88
86
 
89
87
  const core = Object.assign(options, {
90
- //Other options
91
- // domain:'',
92
88
  version,
93
89
  global:{},
94
90
  })
@@ -1012,79 +1012,37 @@ service.getTypeFromID = function (id) {
1012
1012
  * sdk.utils.currencySymbol('usd');
1013
1013
  *
1014
1014
  */
1015
- service.currencySymbol = function (currency) {
1016
- //Ensure lowercase currency
1017
- currency = String(currency).toLowerCase();
1015
+ const CURRENCY_SYMBOLS = { gbp: "\u00A3", eur: "\u20AC" };
1018
1016
 
1019
- switch (String(currency).toLowerCase()) {
1020
- case "gbp":
1021
- return "£";
1022
- break;
1023
- case "eur":
1024
- return "€";
1025
- break;
1026
- default:
1027
- return "$";
1028
- break;
1029
- }
1017
+ service.currencySymbol = function (currency) {
1018
+ return CURRENCY_SYMBOLS[String(currency).toLowerCase()] || "$";
1030
1019
  };
1031
1020
 
1032
- service.getAvailableCurrencies = function (DefaultCountryID) {
1033
- var array = [];
1034
-
1035
- array.push({
1036
- name: `USD (${service.currencySymbol("usd")})`,
1037
- value: "usd",
1038
- countryCode: { US: true },
1039
- });
1040
-
1041
- array.push({
1042
- name: `GBP (${service.currencySymbol("gbp")})`,
1043
- value: "gbp",
1044
- countryCode: { GB: true, UK: true },
1045
- });
1046
-
1047
- array.push({
1048
- name: `CAD (${service.currencySymbol("cad")})`,
1049
- value: "cad",
1050
- countryCode: { CA: true },
1051
- });
1052
-
1053
- array.push({
1054
- name: `AUD (${service.currencySymbol("aud")})`,
1055
- value: "aud",
1056
- countryCode: { AU: true },
1057
- });
1058
-
1059
- array.push({
1060
- name: `NZD (${service.currencySymbol("nzd")})`,
1061
- value: "nzd",
1062
- countryCode: { NZ: true },
1063
- });
1064
-
1065
- array.push({
1066
- name: `SGD (${service.currencySymbol("sgd")})`,
1067
- value: "sgd",
1068
- countryCode: { SG: true },
1069
- });
1070
-
1071
- if (DefaultCountryID) {
1072
- var findMatch = array.findIndex(function (currency) {
1073
- return currency.countryCode[DefaultCountryID];
1074
- });
1075
-
1076
- const moveArrayItem = (array, fromIndex, toIndex) => {
1077
- const arr = [...array];
1078
- arr.splice(toIndex, 0, ...arr.splice(fromIndex, 1));
1079
- return arr;
1080
- };
1081
-
1082
- if (findMatch != -1) {
1083
- array = moveArrayItem(array, findMatch, 0);
1021
+ const SUPPORTED_CURRENCIES = [
1022
+ { code: "usd", countries: ["US"] },
1023
+ { code: "gbp", countries: ["GB", "UK"] },
1024
+ { code: "cad", countries: ["CA"] },
1025
+ { code: "aud", countries: ["AU"] },
1026
+ { code: "nzd", countries: ["NZ"] },
1027
+ { code: "sgd", countries: ["SG"] },
1028
+ ];
1029
+
1030
+ service.getAvailableCurrencies = function (defaultCountryID) {
1031
+ let currencies = SUPPORTED_CURRENCIES.map(({ code, countries }) => ({
1032
+ name: `${code.toUpperCase()} (${service.currencySymbol(code)})`,
1033
+ value: code,
1034
+ countryCode: Object.fromEntries(countries.map((c) => [c, true])),
1035
+ }));
1036
+
1037
+ if (defaultCountryID) {
1038
+ const idx = currencies.findIndex((c) => c.countryCode[defaultCountryID]);
1039
+ if (idx > 0) {
1040
+ const [match] = currencies.splice(idx, 1);
1041
+ currencies.unshift(match);
1084
1042
  }
1085
1043
  }
1086
1044
 
1087
- return array;
1045
+ return currencies;
1088
1046
  };
1089
1047
 
1090
1048
  ///////////////////////////////////////////////////////////////////////////////
@@ -1392,34 +1350,18 @@ service.errorMessage = function (err) {
1392
1350
  err = err[0];
1393
1351
  }
1394
1352
 
1395
- ////////////////////////////////////
1396
-
1397
- var candidates = ["response.data.message", "response.data", "message"];
1398
-
1399
- var message;
1400
-
1401
- candidates.forEach(function (path) {
1402
- if (message) {
1403
- return;
1404
- }
1405
-
1406
- var m = _get(err, path);
1407
- if (m) {
1408
- message = m;
1409
- }
1410
- });
1353
+ // Walk through the error object to find the most useful message
1354
+ let message =
1355
+ err?.response?.data?.message ||
1356
+ (typeof err?.response?.data === "string" ? err.response.data : null) ||
1357
+ err?.message ||
1358
+ null;
1411
1359
 
1412
1360
  if (Array.isArray(message)) {
1413
1361
  message = message[0];
1414
1362
  }
1415
1363
 
1416
- ////////////////////////////////////
1417
-
1418
- message = message || JSON.stringify(err);
1419
-
1420
- ////////////////////////////////////
1421
-
1422
- return message;
1364
+ return message || JSON.stringify(err);
1423
1365
  };
1424
1366
 
1425
1367
  ////////////////////////////////////
@@ -1433,19 +1375,14 @@ service.errorMessage = function (err) {
1433
1375
  * sdk.utils.guid()
1434
1376
  */
1435
1377
  service.guid = function () {
1436
- var u =
1437
- new Date().getTime().toString(16) +
1438
- Math.random().toString(16).substring(2) +
1439
- "0".repeat(16);
1440
- return (
1441
- u.substr(0, 8) +
1442
- "-" +
1443
- u.substr(8, 4) +
1444
- "-4000-8" +
1445
- u.substr(12, 3) +
1446
- "-" +
1447
- u.substr(15, 12)
1448
- );
1378
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
1379
+ return crypto.randomUUID();
1380
+ }
1381
+ // Fallback for environments without crypto.randomUUID
1382
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
1383
+ const r = (Math.random() * 16) | 0;
1384
+ return (c === "x" ? r : (r & 0x3) | 0x8).toString(16);
1385
+ });
1449
1386
  };
1450
1387
 
1451
1388
  ////////////////////////////////////
@@ -1479,87 +1416,59 @@ export default service;
1479
1416
 
1480
1417
  /////////////////////////////////////////////
1481
1418
 
1482
- //Export the event dispatcher
1419
+ /**
1420
+ * A lightweight event emitter that can be attached to any service object
1421
+ * to provide pub/sub event capabilities. Can be called with or without `new`.
1422
+ */
1483
1423
  export function EventDispatcher() {
1484
- var listeners = {};
1485
-
1486
- /////////////////////////////////////////////
1487
-
1488
- var dispatcher = {};
1489
-
1490
- /////////////////////////////////////////////
1491
-
1492
- //Remove all listeners
1493
- dispatcher.removeAllListeners = function () {
1494
- listeners = {};
1495
- };
1496
-
1497
- /////////////////////////////////////////////
1498
-
1499
- dispatcher.dispatch = function (event, details) {
1500
- if (listeners[event]) {
1501
- //For each listener
1502
- listeners[event].forEach(function (callback) {
1503
- return callback(details);
1504
- });
1505
- }
1506
- };
1507
-
1508
- /////////////////////////////////////////////
1509
-
1510
- dispatcher.addEventListener = function (event, callback) {
1511
- if (!listeners[event]) {
1512
- listeners[event] = [];
1513
- }
1514
-
1515
- const type = typeof callback;
1516
- if (type !== "function") {
1517
- throw new Error(
1518
- `addEventListener() requires a function but ${type} was added`,
1519
- );
1520
- } else {
1521
- if (listeners[event].indexOf(callback) == -1) {
1522
- //Add to the listeners
1523
- listeners[event].push(callback);
1524
- } else {
1525
- //A
1526
- //lready listening
1424
+ const handlers = new Map();
1425
+
1426
+ const emitter = {
1427
+ dispatch(event, details) {
1428
+ const fns = handlers.get(event);
1429
+ if (fns) {
1430
+ for (const fn of fns) {
1431
+ fn(details);
1432
+ }
1527
1433
  }
1528
- }
1529
- };
1530
-
1531
- /////////////////////////////////////////////
1532
-
1533
- dispatcher.removeEventListener = function (event, callback) {
1534
- if (!listeners[event]) {
1535
- listeners[event] = [];
1536
- }
1537
-
1538
- //Get the index of the listener
1539
- var index = listeners[event].indexOf(callback);
1434
+ },
1540
1435
 
1541
- if (index != -1) {
1542
- //Remove from the listeners
1543
- listeners[event].splice(index, 1);
1544
- }
1545
- };
1436
+ addEventListener(event, callback) {
1437
+ if (typeof callback !== "function") {
1438
+ throw new TypeError(
1439
+ `Expected a function for addEventListener, received ${typeof callback}`,
1440
+ );
1441
+ }
1546
1442
 
1547
- /////////////////////////////////////////////
1443
+ if (!handlers.has(event)) {
1444
+ handlers.set(event, new Set());
1445
+ }
1548
1446
 
1549
- //Wrap the event listener functionality
1550
- dispatcher.bootstrap = function (service) {
1551
- if (!service) {
1552
- // console.log('No service to bootstrap to')
1553
- return;
1554
- }
1447
+ handlers.get(event).add(callback);
1448
+ },
1555
1449
 
1556
- service.dispatch = dispatcher.dispatch;
1557
- service.addEventListener = dispatcher.addEventListener;
1558
- service.removeEventListener = dispatcher.removeEventListener;
1559
- service.removeAllListeners = dispatcher.removeAllListeners;
1450
+ removeEventListener(event, callback) {
1451
+ const fns = handlers.get(event);
1452
+ if (fns) {
1453
+ fns.delete(callback);
1454
+ if (fns.size === 0) {
1455
+ handlers.delete(event);
1456
+ }
1457
+ }
1458
+ },
1459
+
1460
+ removeAllListeners() {
1461
+ handlers.clear();
1462
+ },
1463
+
1464
+ bootstrap(target) {
1465
+ if (!target) return;
1466
+ target.dispatch = emitter.dispatch;
1467
+ target.addEventListener = emitter.addEventListener;
1468
+ target.removeEventListener = emitter.removeEventListener;
1469
+ target.removeAllListeners = emitter.removeAllListeners;
1470
+ },
1560
1471
  };
1561
1472
 
1562
- /////////////////////////////////////////////
1563
-
1564
- return dispatcher;
1473
+ return emitter;
1565
1474
  }
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export const version = "0.2.3";
1
+ export const version = "0.4.0";