@qikdev/sdk 0.1.169 → 0.1.180

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/.gitlab-ci.yml +24 -0
  2. package/dist/main.js +1 -1
  3. package/jsdoc.conf +10 -0
  4. package/package.json +5 -24
  5. package/public/docs/access.html +3826 -0
  6. package/public/docs/api.html +1356 -0
  7. package/public/docs/auth.html +2180 -0
  8. package/public/docs/cache.html +351 -0
  9. package/public/docs/content.html +2560 -0
  10. package/public/docs/files.html +779 -0
  11. package/public/docs/filter.html +1355 -0
  12. package/public/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  13. package/public/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  14. package/public/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  15. package/public/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  16. package/public/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  17. package/public/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  18. package/public/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  19. package/public/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  20. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  21. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  22. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  23. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  24. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  25. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  26. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  27. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  28. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  29. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  30. package/public/docs/index.html +96 -0
  31. package/public/docs/qik.access.js.html +790 -0
  32. package/public/docs/qik.api.js.html +511 -0
  33. package/public/docs/qik.auth.js.html +1006 -0
  34. package/public/docs/qik.cache.js.html +131 -0
  35. package/public/docs/qik.content.js.html +918 -0
  36. package/public/docs/qik.core.js.html +301 -0
  37. package/public/docs/qik.files.js.html +219 -0
  38. package/public/docs/qik.filter.js.html +611 -0
  39. package/public/docs/qik.socket.js.html +416 -0
  40. package/public/docs/qik.system.js.html +117 -0
  41. package/public/docs/qik.utils.js.html +1467 -0
  42. package/public/docs/scripts/collapse.js +20 -0
  43. package/public/docs/scripts/linenumber.js +25 -0
  44. package/public/docs/scripts/nav.js +12 -0
  45. package/public/docs/scripts/polyfill.js +4 -0
  46. package/public/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  47. package/public/docs/scripts/prettify/lang-css.js +2 -0
  48. package/public/docs/scripts/prettify/prettify.js +28 -0
  49. package/public/docs/scripts/search.js +83 -0
  50. package/public/docs/socket.html +810 -0
  51. package/public/docs/styles/jsdoc.css +765 -0
  52. package/public/docs/styles/prettify.css +79 -0
  53. package/public/docs/system.html +197 -0
  54. package/src/api/qik.access.js +790 -0
  55. package/src/api/qik.api.js +431 -0
  56. package/src/api/qik.auth.js +938 -0
  57. package/src/api/qik.cache.js +63 -0
  58. package/src/api/qik.content.js +858 -0
  59. package/src/api/qik.core.js +246 -0
  60. package/src/api/qik.files.js +150 -0
  61. package/src/api/qik.filter.js +543 -0
  62. package/src/api/qik.geo.js +895 -0
  63. package/src/api/qik.socket.js +348 -0
  64. package/src/api/qik.system.js +49 -0
  65. package/src/api/qik.utils.js +1410 -0
  66. package/src/index.js +20 -0
  67. package/src/version.js +1 -0
  68. package/test/index.spec.js +41 -0
  69. package/test/mocha.opts +0 -0
  70. package/dist/sdk.js +0 -2
  71. package/dist/sdk.js.LICENSE.txt +0 -8
@@ -0,0 +1,1410 @@
1
+ import _get from 'lodash/get.js';
2
+ import _isDate from 'lodash/isDate.js';
3
+ import _startsWith from 'lodash/startsWith.js';
4
+ import _isObject from 'lodash/isObject.js';
5
+ import _camelCase from 'lodash/camelCase.js';
6
+ import axios from 'axios';
7
+ import { isBrowser, isNode } from 'browser-or-node';
8
+
9
+
10
+
11
+ ///////////////////////////////////////////////////////////////////////////////
12
+
13
+ const service = {};
14
+
15
+ ////////////////////////////////////
16
+
17
+ const loadedExternalScripts = {}
18
+
19
+
20
+ /**
21
+ * A function that dynamically include an external javascript resource
22
+ * ensuring that it will only be included once
23
+ * @alias utils.loadExternalScript
24
+ * @param {String} url The url of the external script
25
+ * @return {Promise} A promise that will be resolved once the script has been loaded
26
+ * @example
27
+ *
28
+ * await sdk.utils.loadExternalScript('https://cdn.javascript.com/external/script.js');
29
+ */
30
+
31
+
32
+ service.loadExternalScript = function(url) {
33
+
34
+ // If we already have a promise
35
+ if (loadedExternalScripts[url]) {
36
+ // return the existing promise
37
+ return loadedExternalScripts[url];
38
+ }
39
+
40
+
41
+ // Create a new promise
42
+ const promise = loadedExternalScripts[url] = new Promise(createNewScript);
43
+
44
+ function createNewScript(resolve, reject) {
45
+
46
+ if (!document) {
47
+ delete loadedExternalScripts[url];
48
+ return reject('document is undefined')
49
+ }
50
+
51
+ //////////////////////////////////////
52
+
53
+ var script = document.createElement('script');
54
+ script.type = 'text/javascript';
55
+ script.async = true;
56
+ script.onload = function() {
57
+ console.log('Loaded external script', url);
58
+ return resolve(url);
59
+ };
60
+ script.src = url;
61
+
62
+ // Inject it into the document's <head> tag
63
+ document.head.appendChild(script);
64
+
65
+ }
66
+
67
+ return promise;
68
+ }
69
+
70
+
71
+ const loadedExternalStyles = {}
72
+
73
+
74
+ /**
75
+ * A function that dynamically include an external css resource
76
+ * ensuring that it will only be included once
77
+ * @alias utils.loadExternalStyle
78
+ * @param {String} url The url of the external css
79
+ * @return {Promise} A promise that will be resolved once the css has been loaded
80
+ * @example
81
+ *
82
+ * await sdk.utils.loadExternalStyle('https://cdn.css.com/external/style.css');
83
+ */
84
+ service.loadExternalStyle = function(url) {
85
+
86
+ const promise = new Promise(createNewScript);
87
+
88
+ function createNewScript(resolve, reject) {
89
+
90
+ if (!document) {
91
+ return reject('document is undefined')
92
+ }
93
+
94
+ if (loadedExternalStyles[url]) {
95
+ return resolve(url);
96
+ }
97
+
98
+ // Avoid duplicate scripts
99
+ loadedExternalStyles[url] = true;
100
+
101
+ //////////////////////////////////////
102
+
103
+ var script = document.createElement('link');
104
+ script.setAttribute('rel', 'stylesheet')
105
+ script.setAttribute('type', 'text/css')
106
+ script.setAttribute('href', url)
107
+ script.onload = function() {
108
+ console.log('Loaded external stylesheet', url);
109
+ return resolve(url);
110
+ };
111
+
112
+ // Inject it into the document's <head> tag
113
+ document.head.appendChild(script);
114
+
115
+ }
116
+
117
+ return promise;
118
+ }
119
+
120
+
121
+ ///////////////////////////////////////////////////////////////////////////////
122
+
123
+ service.exists = function(value) {
124
+ var isUndefinedOrNull;
125
+
126
+ ////////////////////////
127
+
128
+ if (Array.isArray(value)) {
129
+ return true;
130
+ }
131
+
132
+ ////////////////////////
133
+
134
+ if (value === 0) {
135
+ return true;
136
+ }
137
+
138
+ ////////////////////////
139
+
140
+ switch (typeof value) {
141
+ case 'undefined':
142
+ case 'null':
143
+ isUndefinedOrNull = true;
144
+ break;
145
+ default:
146
+ var string = String(value).toLowerCase();
147
+ switch (string) {
148
+ case '':
149
+ case 'undefined':
150
+ case 'null':
151
+ isUndefinedOrNull = true;
152
+ break;
153
+ }
154
+ break;
155
+ }
156
+
157
+ return !!!isUndefinedOrNull;
158
+ }
159
+
160
+ //////////////////////////////////
161
+
162
+ service.parseDate = function(input) {
163
+
164
+ if (!input) {
165
+ return;
166
+ }
167
+
168
+ if (_isDate(input)) {
169
+ return input;
170
+ }
171
+
172
+ //Attempt to create a date
173
+ var d = new Date(input);
174
+ var isValid = d instanceof Date && !isNaN(d);
175
+
176
+ if (isValid) {
177
+ return d;
178
+ }
179
+
180
+ return;
181
+ }
182
+
183
+ service.parseURL = function(string) {
184
+
185
+ if (!string) {
186
+ return false;
187
+ }
188
+
189
+ const relative = _startsWith(string, '/');
190
+ if (relative) {
191
+ return string;
192
+ }
193
+
194
+ if (_startsWith(string, '://')) {
195
+ return string;
196
+ }
197
+
198
+ if (_startsWith(string, 'mailto:')) {
199
+ return string;
200
+ }
201
+
202
+ if (_startsWith(string, 'tel:')) {
203
+ return string;
204
+ }
205
+
206
+ if (_startsWith(string, 'sms:')) {
207
+ return string;
208
+ }
209
+
210
+ //////////////////////////////////
211
+ //If someone entered an email by accident
212
+ var email = service.parseEmail(string);
213
+ //Convert it to a mailto link
214
+ if (email && email === string) {
215
+ return `mailto:${email}`
216
+ }
217
+
218
+ //////////////////////////////////
219
+
220
+ const withHttp = string => !/^https?:\/\//i.test(string) ? `http://${string}` : string;
221
+ string = withHttp(string);
222
+ //TODO: test this more.
223
+ string = string.replace(/\s/g, '');
224
+
225
+
226
+
227
+
228
+
229
+
230
+ var valid = RegExp('(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+@]*)*(\\?[;&a-z\\d%_.~+=-@]*)?(\\#[-a-z\\d_@]*)?$', 'i').test(string);
231
+
232
+ if (!valid) {
233
+ return false;
234
+ }
235
+
236
+
237
+
238
+ ///////////////////////////
239
+
240
+ return withHttp(string)
241
+ }
242
+
243
+
244
+ ///////////////////////////////////////////////
245
+
246
+ service.parseNumber = function(input, decimalPoints) {
247
+ if (!input) {
248
+ return 0;
249
+ }
250
+
251
+ input = Number(input);
252
+ if (isNaN(input)) {
253
+ return 0;
254
+ }
255
+
256
+ if (decimalPoints) {
257
+ var str = input.toFixed(decimalPoints);
258
+ input = service.parseNumber(str);
259
+ }
260
+
261
+ return input;
262
+ }
263
+
264
+
265
+ service.isValidEmailAddress = function(email) {
266
+
267
+ var tester = /^[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/;
268
+
269
+ if (!email) return false;
270
+
271
+ var emailParts = email.split('@');
272
+
273
+ if (emailParts.length !== 2) return false
274
+
275
+ var account = emailParts[0];
276
+ var address = emailParts[1];
277
+
278
+ if (account.length > 64) return false
279
+
280
+ else if (address.length > 255) return false
281
+
282
+ var domainParts = address.split('.');
283
+ if (domainParts.some(function(part) {
284
+ return part.length > 63;
285
+ })) return false;
286
+
287
+
288
+ if (!tester.test(email)) return false;
289
+
290
+ return true;
291
+ }
292
+
293
+
294
+ service.parseEmail = function(input) {
295
+
296
+ if (!input) {
297
+ return false;
298
+ }
299
+
300
+ var lowercase = String(input).toLowerCase();
301
+ var valid = service.isValidEmailAddress(lowercase);
302
+
303
+ if (!valid) {
304
+ return false;
305
+ } else {
306
+ return lowercase;
307
+ }
308
+ }
309
+
310
+ //////////////////////////////////
311
+
312
+ service.parseInt = function(input) {
313
+ if (!input) {
314
+ return 0;
315
+ }
316
+
317
+ input = parseInt(input);
318
+ if (isNaN(input)) {
319
+ return 0;
320
+ }
321
+
322
+ return input;
323
+ }
324
+
325
+
326
+
327
+ service.cleanValue = function(data, type, options) {
328
+
329
+ if (!options) {
330
+ options = {};
331
+ }
332
+
333
+ ////////////////////////
334
+
335
+ var noInputValue = service.exists(data);
336
+ if (options.strict && noInputValue && type != 'boolean') {
337
+ return data;
338
+ }
339
+
340
+ ////////////////////////
341
+
342
+ switch (type) {
343
+ case 'reference':
344
+ return service.id(data, true);
345
+ break;
346
+ case 'boolean':
347
+ return service.parseBoolean(data);
348
+ break;
349
+ case 'url':
350
+ return service.parseURL(data);
351
+ break;
352
+ case 'key':
353
+ return service.machineName(data);
354
+ break;
355
+ case 'email':
356
+ return service.parseEmail(data);
357
+ break;
358
+ case 'date':
359
+ var parsed = service.parseDate(data, options);
360
+
361
+ if (parsed === undefined) {
362
+ return;
363
+ } else {
364
+ return parsed;
365
+ }
366
+ break;
367
+ case 'number':
368
+ case 'decimal':
369
+ case 'float':
370
+ var val = service.parseNumber(data);
371
+ if (String(val) == String(Number(data))) {
372
+ return val;
373
+ }
374
+ return;
375
+ break;
376
+ case 'integer':
377
+ var val = service.parseInt(data);
378
+ if (String(val) == String(parseInt(data))) {
379
+ return val;
380
+ }
381
+ return;
382
+ break;
383
+ case 'group':
384
+ return data;
385
+ break;
386
+ case 'object':
387
+ if (_isObject(data) && !Array.isArray(data)) {
388
+ return data
389
+ }
390
+
391
+ return;
392
+ break;
393
+ case 'string':
394
+ if (service.exists(data)) {
395
+ var stringed = String(data);
396
+ if (stringed == '[object Object]') {
397
+ return;
398
+ }
399
+
400
+ return stringed
401
+ } else {
402
+ return;
403
+ }
404
+
405
+ // if(!data) {
406
+ // return '';
407
+ // }
408
+
409
+ // if(Array.isArray(data)) {
410
+ // return JSON.stringify(data);
411
+ // }
412
+
413
+ // if(Object.isObject(data)) {
414
+ // return JSON.stringify(data);
415
+ // }
416
+
417
+ // return String(data);
418
+
419
+ // break;
420
+ default:
421
+ return String(data)
422
+ break;
423
+ }
424
+ }
425
+
426
+
427
+
428
+ service.isValidValue = function(value, dataType, strict) {
429
+
430
+ var isValue = service.exists(value);
431
+ var valueIsNumber = (typeof value == 'number')
432
+
433
+ ////////////////////////
434
+
435
+ var isValidEntry = false;
436
+
437
+ if (!isValue) {
438
+ return false;
439
+ }
440
+
441
+ ////////////////////////
442
+
443
+ switch (dataType) {
444
+
445
+ case 'url':
446
+ if (strict) {
447
+ isValidEntry = _startsWith(value, '/') || _startsWith(value, '://') || _startsWith(value, 'http://') || _startsWith(value, 'https://');
448
+ } else {
449
+ isValidEntry = String(value) === service.parseURL(value);
450
+ }
451
+ break;
452
+ case 'key':
453
+ isValidEntry = String(value) === service.machineName(value);
454
+ break;
455
+ case 'date':
456
+
457
+ //If we are being strict
458
+ if (strict) {
459
+ //And the input is not a javascript date object
460
+ if (typeof value != 'object' || !_isDate(value)) {
461
+ return false;
462
+ }
463
+ }
464
+
465
+ ///////////////////////////////
466
+ var parsed = service.parseDate(value);
467
+ return parsed !== undefined;
468
+ break;
469
+ case 'email':
470
+
471
+ if (strict) {
472
+ isValidEntry = value === service.parseEmail(value);
473
+ } else {
474
+ isValidEntry = String(value).toLowerCase() === service.parseEmail(value);
475
+ }
476
+
477
+ break;
478
+ case 'number':
479
+ case 'decimal':
480
+ case 'float':
481
+ if (strict) {
482
+ isValidEntry = valueIsNumber && (Number(value) === service.parseNumber(value));
483
+ } else {
484
+ isValidEntry = Number(value) === service.parseNumber(value);
485
+ }
486
+ break;
487
+ case 'integer':
488
+ if (strict) {
489
+ isValidEntry = valueIsNumber && (Number(value) === service.parseInt(value));
490
+ } else {
491
+ isValidEntry = Number(value) === service.parseInt(value);
492
+ }
493
+ break;
494
+ case 'boolean':
495
+
496
+ var parsed = service.parseBoolean(value);
497
+
498
+ //Only accept true booleans
499
+ if (strict) {
500
+ if (value === true || value === false) {
501
+ isValidEntry = value === parsed;
502
+ }
503
+ } else {
504
+ isValidEntry = parsed === true || parsed === false;
505
+ }
506
+ break;
507
+ case 'reference':
508
+ if (strict) {
509
+ isValidEntry = String(value) === service.id(value);
510
+ } else {
511
+ isValidEntry = !!service.id(value);
512
+ }
513
+ break;
514
+ case 'string':
515
+ var checkString = String(value);
516
+ if (strict) {
517
+ if (typeof value != 'string') {
518
+ return false;
519
+ }
520
+ }
521
+
522
+ if (checkString == '[object Object]') {
523
+ return false;
524
+ }
525
+
526
+ isValidEntry = true;
527
+ break;
528
+ // case 'group':
529
+ // isValidEntry = _isObject(value);
530
+ // break;
531
+ case 'object':
532
+
533
+
534
+ isValidEntry = _isObject(value) && !Array.isArray(value);
535
+ break;
536
+ case 'array':
537
+ isValidEntry = Array.isArray(value);
538
+ break;
539
+ }
540
+
541
+ ////////////////////////
542
+
543
+ return isValidEntry
544
+ }
545
+
546
+ service.parseBoolean = function(value) {
547
+ switch (String(value).toLowerCase()) {
548
+ case 'true':
549
+ case 'y':
550
+ case 'yes':
551
+ case '1':
552
+ case 't':
553
+ value = true;
554
+ break;
555
+ case 'false':
556
+ case 'n':
557
+ case 'no':
558
+ case '0':
559
+ case 'f':
560
+ case 'undefined':
561
+ case 'null':
562
+ case '':
563
+ case '-1':
564
+ value = false;
565
+ break;
566
+ }
567
+
568
+ return !!value;
569
+ }
570
+
571
+
572
+
573
+
574
+ ///////////////////////////////////////////////////////////////////////////////
575
+
576
+ service.clone = function(input) {
577
+ return JSON.parse(JSON.stringify(input));
578
+ }
579
+
580
+ ///////////////////////////////////////////////////////////////////////////////
581
+
582
+ service.mapFields = function(fields, options) {
583
+
584
+ if (!options) {
585
+ options = {};
586
+ }
587
+
588
+ //////////////////////////////
589
+
590
+ var output = [];
591
+ var trail = [];
592
+ var titles = [];
593
+ var currentDepth = 1;
594
+ var depthLimit = options.depth;
595
+ var delimiter = options.arrayDelimeter || '[]';
596
+
597
+
598
+ //Loop through each field
599
+ fields.forEach(mapField);
600
+
601
+ //////////////////////////////
602
+
603
+ //Recursively map the fields
604
+ function mapField(field, i) {
605
+ var fieldKey = field.key;
606
+ var isGroup = field.type == 'group';
607
+ var singleValue = (field.minimum === field.maximum) && field.minimum === 1;
608
+ var asObject = field.asObject; // || (isGroup && singleValue);
609
+ var isLayout = isGroup && !asObject;
610
+
611
+ //////////////////////////////////
612
+
613
+ // Whether to clone the field or use the existing reference
614
+ var mapped = options.original ? field : service.clone(field);
615
+
616
+ mapped.trail = trail.slice();
617
+ mapped.trail.push(fieldKey)
618
+
619
+ mapped.path = mapped.trail.join('.');
620
+ mapped.titles = titles.slice();
621
+ mapped.titles.push(field.title || '')
622
+
623
+
624
+ const isNotLayoutOrIsAllowed = (!isLayout || options.includeLayout);
625
+
626
+ //If its an actual element or we've asked to include
627
+ //layout only elements
628
+ if (isNotLayoutOrIsAllowed) {
629
+ //Add it to the mix
630
+ output.push(mapped);
631
+ }
632
+
633
+ //////////////////////////////////
634
+
635
+ //Now see if there are child fields and should we go further
636
+ var limitHit = depthLimit && (currentDepth >= depthLimit);
637
+
638
+ //If there are child fields for this field
639
+ if (field.fields && field.fields.length) {
640
+ //If it's just a group with no extra key
641
+ if (isLayout) {
642
+ //Loop through fields as if they are at the same depth
643
+ field.fields.forEach(mapField)
644
+ } else {
645
+
646
+ //We don't need to traverse any further
647
+ //because we hit the limit
648
+ if (limitHit) {
649
+ return;
650
+ }
651
+
652
+ //Move down a level and add to the object
653
+ //Include the key in the path trail
654
+ currentDepth++;
655
+
656
+ let injectKey = fieldKey;
657
+ if (options.includeArrayDelimeter) {
658
+ if (!singleValue) {
659
+ injectKey = `${fieldKey}${delimiter}`
660
+ }
661
+ }
662
+ trail.push(injectKey)
663
+ titles.push(field.title);
664
+
665
+ //Loop through each field
666
+ field.fields.forEach(mapField)
667
+
668
+ //Move back up a level before we go to the next field
669
+ currentDepth--;
670
+ trail.pop();
671
+ titles.pop();
672
+ }
673
+
674
+ }
675
+
676
+ }
677
+
678
+ return output;
679
+ }
680
+
681
+ ///////////////////////////////////////////////////////////////////////////////
682
+
683
+ /**
684
+ * A helpful function that can take a keyed object literal and map it to url query string parameters
685
+ * @alias utils.mapParameters
686
+ * @param {Object} parameters The object you want to transalte
687
+ * @return {String} The query string
688
+ * @example
689
+ * //Returns &this=that&hello=world
690
+ * sdk.utils.mapParameters({"this":"that", "hello":"world"})
691
+ */
692
+ service.mapParameters = function(parameters) {
693
+
694
+ parameters = parameters || {}
695
+
696
+ var array = [];
697
+
698
+ Object.entries(parameters)
699
+ .forEach(function([key, value]) {
700
+
701
+ if (value === undefined || value === null || value == false) {
702
+ return;
703
+ }
704
+
705
+ if (Array.isArray(value)) {
706
+ value.forEach(function(v) {
707
+ array.push(`${key}=${encodeURIComponent(v)}`);
708
+ })
709
+ } else {
710
+ array.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
711
+ }
712
+
713
+ })
714
+
715
+ return array.join('&');
716
+
717
+ }
718
+
719
+ ///////////////////////////////////////////////////////////////////////////////
720
+
721
+ /**
722
+ * A function that will take an integer and a currency string and return a formatted numeric amount rounded to 2 decimal places
723
+ * @alias utils.formatCurrency
724
+ * @param {Integer} value The amount in cents
725
+ * @param {String} currency The currency to format
726
+ * @return {String} The formatted value
727
+ * @example
728
+ *
729
+ * //Returns £10.00
730
+ * sdk.utils.formatCurrency(1000, 'gbp');
731
+ *
732
+ * //Returns $10.00
733
+ * sdk.utils.formatCurrency(1000, 'usd');
734
+ *
735
+ */
736
+ service.formatCurrency = function(value, currency, decimalPoints) {
737
+
738
+ if (!value || isNaN(value)) {
739
+ value = 0;
740
+ }
741
+
742
+ decimalPoints = decimalPoints || 2;
743
+
744
+ var currencyPrefix = service.currencySymbol(currency);
745
+ return `${currencyPrefix}${parseFloat(Number(value) / 100).toFixed(decimalPoints)}`;
746
+
747
+ }
748
+
749
+
750
+
751
+ /**
752
+ * A function that will take an id and return the type key
753
+ * @alias utils.getTypeFromID
754
+ * @param {String} id The id of an object
755
+ * @return {String} The key
756
+ * @example
757
+ *
758
+ * // Returns 'user'
759
+ * sdk.utils.getTypeFromID('52b523f775beea960013f6cd');
760
+ *
761
+ * // Returns 'role'
762
+ * sdk.utils.getTypeFromID('62b59cb572fb4772e7b5fa93');
763
+ *
764
+ */
765
+ service.getTypeFromID = function(id) {
766
+
767
+ id = service.id(id);
768
+
769
+ if (!id) {
770
+ return;
771
+ }
772
+
773
+ const lookup = {
774
+ "21": "organisation",
775
+ "23": "comment",
776
+ "24": "persona",
777
+ "25": "audio",
778
+ "26": "campaign",
779
+ "28": "smartlist",
780
+ "29": "cache",
781
+ "40": "application",
782
+ "41": "action",
783
+ "42": "billinginvoice",
784
+ "43": "componentsnapshot",
785
+ "44": "diff",
786
+ "45": "email",
787
+ "46": "submission",
788
+ "49": "import",
789
+ "53": "socket",
790
+ "54": "timetrigger",
791
+ "61": "article",
792
+ "63": "component",
793
+ "65": "event",
794
+ "66": "file",
795
+ "67": "tag",
796
+ "69": "image",
797
+ "70": "profile",
798
+ "72": "role",
799
+ "73": "scope",
800
+ "74": "transaction",
801
+ "75": "user",
802
+ "76": "video",
803
+ "77": "workflowcard",
804
+ "78": "variable",
805
+ "3c": "patoken",
806
+ "7b": "uatoken",
807
+ "7d": "urtoken",
808
+ "2d": "systemtask",
809
+ "3d": "export",
810
+ "5f": "systemflag",
811
+ "2b": "batch",
812
+ "3a": "log",
813
+ "2e": "stat",
814
+ "2f": "unsubscribe",
815
+ "6b": "intent",
816
+ "7c": "upload",
817
+ "2c": "systemtrigger",
818
+ "6e": "interface",
819
+ "4e": "interfacesnapshot",
820
+ "4f": "notification",
821
+ "2a": "definition",
822
+ "7e": "definitionsnapshot",
823
+ "5e": "integration",
824
+ "4c": "listener",
825
+ "6d": "topic",
826
+ "7a": "code",
827
+ "4d": "paymentmethod",
828
+ "6c": "sslcertificate"
829
+ }
830
+
831
+ var hexKey = id.slice(8, 10);
832
+ return lookup[hexKey];
833
+ }
834
+
835
+
836
+ /**
837
+ * A function that will take a currency string and return the symbol
838
+ * @alias utils.currencySymbol
839
+ * @param {String} currency The currency
840
+ * @return {String} The symbol
841
+ * @example
842
+ *
843
+ * //Returns £
844
+ * sdk.utils.currencySymbol('gbp');
845
+ *
846
+ * //Returns $
847
+ * sdk.utils.currencySymbol('usd');
848
+ *
849
+ */
850
+ service.currencySymbol = function(currency) {
851
+ //Ensure lowercase currency
852
+ currency = String(currency).toLowerCase();
853
+
854
+ switch (String(currency).toLowerCase()) {
855
+ case 'gbp':
856
+ return '£';
857
+ break;
858
+ case 'eur':
859
+ return '€';
860
+ break;
861
+ default:
862
+ return '$';
863
+ break;
864
+ }
865
+ }
866
+
867
+
868
+
869
+ service.getAvailableCurrencies = function(DefaultCountryID) {
870
+
871
+
872
+ var array = [];
873
+
874
+ array.push({
875
+ name: `USD (${service.currencySymbol("usd")})`,
876
+ value: "usd",
877
+ countryCode: { 'US': true },
878
+ });
879
+
880
+ array.push({
881
+ name: `GBP (${service.currencySymbol("gbp")})`,
882
+ value: "gbp",
883
+ countryCode: { 'GB': true, 'UK': true },
884
+ });
885
+
886
+ array.push({
887
+ name: `CAD (${service.currencySymbol("cad")})`,
888
+ value: "cad",
889
+ countryCode: { 'CA': true },
890
+ });
891
+
892
+ array.push({
893
+ name: `AUD (${service.currencySymbol("aud")})`,
894
+ value: "aud",
895
+ countryCode: { 'AU': true },
896
+ });
897
+
898
+
899
+ array.push({
900
+ name: `NZD (${service.currencySymbol("nzd")})`,
901
+ value: "nzd",
902
+ countryCode: { 'NZ': true },
903
+ });
904
+
905
+ array.push({
906
+ name: `SGD (${service.currencySymbol("sgd")})`,
907
+ value: "sgd",
908
+ countryCode: { 'SG': true },
909
+ });
910
+
911
+
912
+ if (DefaultCountryID) {
913
+
914
+ var findMatch = array.findIndex(function(currency) {
915
+ return currency.countryCode[DefaultCountryID];
916
+ })
917
+
918
+ const moveArrayItem = (array, fromIndex, toIndex) => {
919
+ const arr = [...array];
920
+ arr.splice(toIndex, 0, ...arr.splice(fromIndex, 1));
921
+ return arr;
922
+ }
923
+
924
+ if (findMatch != -1) {
925
+ array = moveArrayItem(array, findMatch, 0)
926
+ }
927
+ }
928
+
929
+ return array;
930
+ }
931
+
932
+ ///////////////////////////////////////////////////////////////////////////////
933
+
934
+ /**
935
+ * Creates a fast keyed hash object from an array of items
936
+ * @alias utils.hash
937
+ * @param {Array} array The array of items to convert into a hash
938
+ * @param {String} key The key or path to the property on each item to use as the hashed key
939
+ * @return {Object} A key/value paired object
940
+ * @example
941
+ * //Returns { jimbo:{id:'jimbo', title:'Jim Jones'}, {id:'roger', title:'Roger Fellow'} }
942
+ * sdk.utils.hash([{id:'jimbo', title:'Jim Jones'}, {id:'roger', title:'Roger Fellow'}], 'id');
943
+ *
944
+ */
945
+ service.hash = function(items, key) {
946
+ items = !Array.isArray(items) ? [] : items;
947
+ return items.reduce(function(memo, item) {
948
+ const k = _get(item, key);
949
+ memo[k] = item;
950
+ return memo;
951
+ }, {});
952
+ }
953
+
954
+
955
+
956
+
957
+ //////////////////////////////////////////////////
958
+
959
+ /**
960
+ * Returns a subset of values in an array that match a provided rule
961
+ * @alias utils.extractFromArray
962
+ * @param {Array} array The array you want to extract values from
963
+ * @param {String} key The path to the child property you want to extract
964
+ * @param {Boolean} sum Whether to sum the extracted values together in total
965
+ * @param {Boolean} flatten Whether to flatten nested child arrays
966
+ * @param {Boolean} unique Whether to only return unique values
967
+ * @param {Boolean} exclude Whether to exclude null or undefined values
968
+ * @param {Object} options Pass through extra options for how to extract the values
969
+ * @return {Array} An array of all values retrieved from the array, unless provided arguments require otherwise
970
+ * @example
971
+ * //Returns [12, 45] as all the values
972
+ * sdk.utils.extractFromArray([{name:'Wendy', age:12}, {name:'Roger', age:45}], 'age');
973
+ *
974
+ * //Returns 32
975
+ * sdk.utils.extractFromArray([{name:'Wendy', age:12}, {name:'Roger', age:20}], 'age', {sum:true});
976
+ *
977
+ */
978
+ service.extractFromArray = function(array, key, sum, flatten, unique, exclude, options) {
979
+
980
+ options = options || {}
981
+
982
+ if (sum) {
983
+ options.sum = sum;
984
+ }
985
+
986
+ if (flatten) {
987
+ options.flatten = true;
988
+ }
989
+
990
+ if (unique) {
991
+ options.unique = true;
992
+ }
993
+
994
+ if (exclude) {
995
+ options.excludeNull = true;
996
+ }
997
+
998
+ /////////////////
999
+
1000
+ //Filter the array options by a certain value and operator
1001
+ var extractedValues = array.reduce(function(set, entry) {
1002
+ //Get the value from the object
1003
+ var retrievedValue = _get(entry, key);
1004
+
1005
+ var isNull = (!retrievedValue && (retrievedValue !== false && retrievedValue !== 0));
1006
+ if (options.excludeNull && isNull) {
1007
+ return set;
1008
+ }
1009
+
1010
+ set.push(retrievedValue);
1011
+ return set;
1012
+ }, [])
1013
+
1014
+ if (options.flatten) {
1015
+ extractedValues = _.flatten(extractedValues);
1016
+ }
1017
+
1018
+ if (options.unique) {
1019
+ extractedValues = _.uniq(extractedValues);
1020
+ }
1021
+
1022
+ if (options.sum) {
1023
+ extractedValues = extractedValues.reduce(function(a, b) {
1024
+ return a + b;
1025
+ }, 0);
1026
+ }
1027
+
1028
+ return extractedValues;
1029
+ }
1030
+
1031
+
1032
+ //////////////////////////////////////////////////////
1033
+
1034
+ /**
1035
+ * A function that can return a selection of values that were found in an array that match a specific rule,
1036
+ * This is often used to evaluate expressions within form fields
1037
+ * @alias utils.matchInArray
1038
+ * @param {Array} array The array to check
1039
+ * @param {String} key The javascript dot notation path to extract
1040
+ * @param {String} value The value to compare against
1041
+ * @param {String} comparator The logical operator to use to compare the extracted value with the provided value ('>', '<', '>=', '<=', 'in', '==') Defaults to '==' (Is equal to)
1042
+ * @return {Array} Returns an array of matching values
1043
+ * @example
1044
+ * //Returns [{name:'Michael', age:45}] as that is only item in the array that matches the criteria
1045
+ * sdk.utils.matchInArray([{name:'Wendy', age:12}, {name:'Michael', age:45}], 'age', 45, '>=');
1046
+ *
1047
+ */
1048
+ service.matchInArray = function(array, key, v, comparator) {
1049
+
1050
+ //Filter the array options by a certain v and comparator
1051
+ var matches = array.filter(function(entry) {
1052
+ //Get the v from the object
1053
+ var extracted = _get(entry, key);
1054
+ var found;
1055
+
1056
+ switch (comparator) {
1057
+ case 'in':
1058
+ found = extracted.includes(v);
1059
+ break;
1060
+ case '>=':
1061
+ found = (extracted >= v);
1062
+ break;
1063
+ case '<=':
1064
+ found = (extracted <= v);
1065
+ break;
1066
+ case '<':
1067
+ found = (extracted < v);
1068
+ break;
1069
+ case '>':
1070
+ found = (extracted > v);
1071
+ break;
1072
+ case '==':
1073
+ default:
1074
+ if (v === undefined) {
1075
+ found = extracted;
1076
+ } else {
1077
+ found = (extracted == v);
1078
+ }
1079
+ break;
1080
+ }
1081
+
1082
+ return found;
1083
+ })
1084
+
1085
+ return matches;
1086
+ }
1087
+
1088
+ ///////////////////////////////////////////////////////////////////////////////
1089
+
1090
+ /**
1091
+ * A helpful class that can take an array of values and return them as a comma seperated
1092
+ * string, If the values are objects, then a property to use as the string representation can be specified
1093
+ * @alias utils.comma
1094
+ * @param {Array} array The array of values to translate
1095
+ * @param {String} path An optional property key to use for each value
1096
+ * @return {String} The resulting comma seperated string
1097
+ * @example
1098
+ * //Returns 'cat, dog, bird'
1099
+ * sdk.utils.comma(['cat', 'dog', 'bird']);
1100
+ *
1101
+ * //Returns 'cat, dog, bird'
1102
+ * sdk.utils.comma([{title:'cat'}, {title:'dog'}, {title:'bird'}], 'title');
1103
+ */
1104
+ service.comma = function(array, path, limit) {
1105
+
1106
+ if (limit) {
1107
+ array = array.slice(0, limit);
1108
+ }
1109
+
1110
+ return _.chain(array)
1111
+ .compact()
1112
+ .map(function(item) {
1113
+ if (path && path.length) {
1114
+ return _get(item, path);
1115
+ }
1116
+
1117
+ return item;
1118
+ })
1119
+ .value()
1120
+ .join(', ');
1121
+ }
1122
+
1123
+ ///////////////////////////////////////////////////////////////////////////////
1124
+
1125
+ //Helper function to get an id of an object
1126
+
1127
+ /**
1128
+ * Returns a specified _id for an object
1129
+ * @alias utils.id
1130
+ * @param {Object} input An object that is or has an _id property
1131
+ * @param {Boolean} asObjectID Whether to convert to a Mongo ObjectId
1132
+ * @return {String} Will return either a string or a Mongo ObjectId
1133
+ *
1134
+ * @example
1135
+ *
1136
+ * //Returns '5cb3d8b3a2219970e6f86927'
1137
+ * sdk.utils.id('5cb3d8b3a2219970e6f86927')
1138
+ *
1139
+ * //Returns true
1140
+ * typeof service.id({_id:'5cb3d8b3a2219970e6f86927', title, ...}) == 'string';
1141
+
1142
+ * //Returns true
1143
+ * typeof service.id({_id:'5cb3d8b3a2219970e6f86927'}, true) == 'object';
1144
+ */
1145
+ service.id = function(source) {
1146
+
1147
+ if (!source) {
1148
+ return;
1149
+ }
1150
+
1151
+ /////////////////////////////////
1152
+
1153
+ var output;
1154
+
1155
+ if (source._id) {
1156
+ output = String(source._id);
1157
+ } else {
1158
+ output = String(source);
1159
+ }
1160
+
1161
+
1162
+ var isValid = service.isValidID(output);
1163
+ if (!isValid) {
1164
+ return;
1165
+ }
1166
+
1167
+ return output;
1168
+ }
1169
+
1170
+ ///////////////////////////////////////////////////////////////////////////////
1171
+
1172
+ /**
1173
+ * Cleans and maps an array of objects to an array of IDs
1174
+ * @alias utils.ids
1175
+ * @param {Array} array An array of objects or object ids
1176
+ * @param {Boolean} asObjectID Whether or not to map the ids as Mongo ObjectIds
1177
+ * @return {Array} An array of Ids
1178
+ *
1179
+ * @example
1180
+ * //Returns ['5cb3d8b3a2219970e6f86927', '5cb3d8b3a2219970e6f86927', '5cb3d8b3a2219970e6f86927']
1181
+ * sdk.utils.ids([{_id:'5cb3d8b3a2219970e6f86927'}, {_id:'5cb3d8b3a2219970e6f86927'}, null, '5cb3d8b3a2219970e6f86927'])
1182
+ */
1183
+
1184
+ service.ids = function(array) {
1185
+
1186
+ if (!array) {
1187
+ return [];
1188
+ }
1189
+
1190
+ /////////////////////////////////
1191
+
1192
+ var ids = Object.keys(array.reduce(function(set, entry) {
1193
+
1194
+ if (!entry) {
1195
+ return set;
1196
+ }
1197
+
1198
+ var cleaned = service.id(entry)
1199
+
1200
+ if (cleaned) {
1201
+ set[cleaned] = 1;
1202
+ }
1203
+
1204
+ return set;
1205
+ }, {}))
1206
+
1207
+ ///////////////////////////////
1208
+
1209
+ return ids;
1210
+ }
1211
+
1212
+
1213
+ ///////////////////////////////////////////////////////////////////////////////
1214
+
1215
+ service.isValidID = function(input) {
1216
+ var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$")
1217
+ return checkForHexRegExp.test(String(input));
1218
+
1219
+ }
1220
+
1221
+ ///////////////////////////////////////////////////////////////////////////////
1222
+
1223
+ /**
1224
+ * Helper function for retrieving a human readable error message from server error response objects
1225
+ * @alias utils.errorMessage
1226
+ * @param {Object} error The error object to translate
1227
+ * @return {String} The resulting human readable error message
1228
+ */
1229
+ service.errorMessage = function(err) {
1230
+
1231
+ if (!err) {
1232
+ return;
1233
+ }
1234
+
1235
+
1236
+ if (Array.isArray(err)) {
1237
+ err = err[0];
1238
+ }
1239
+
1240
+ ////////////////////////////////////
1241
+
1242
+
1243
+ var candidates = [
1244
+ 'response.data.message',
1245
+ 'response.data',
1246
+ 'message',
1247
+ ]
1248
+
1249
+ var message;
1250
+
1251
+ candidates.forEach(function(path) {
1252
+ if (message) {
1253
+ return;
1254
+ }
1255
+
1256
+ var m = _get(err, path);
1257
+ if (m) {
1258
+ message = m;
1259
+ }
1260
+ })
1261
+
1262
+ if (Array.isArray(message)) {
1263
+ message = message[0];
1264
+ }
1265
+
1266
+ ////////////////////////////////////
1267
+
1268
+ message = message || JSON.stringify(err);
1269
+
1270
+ ////////////////////////////////////
1271
+
1272
+ return message;
1273
+ }
1274
+
1275
+ ////////////////////////////////////
1276
+
1277
+ /**
1278
+ * Generates a globally unique ID, helpful for adding unique keys for iterable loops
1279
+ * @alias utils.guid
1280
+ * @return {String} The new globally unique identifier
1281
+ * @example
1282
+ * //Returns 4323a78br-z16h-289j-zwl1-938lda334asd
1283
+ * sdk.utils.guid()
1284
+ */
1285
+ service.guid = function() {
1286
+ var u = (new Date()).getTime().toString(16) + Math.random().toString(16).substring(2) + "0".repeat(16);
1287
+ return u.substr(0, 8) + '-' + u.substr(8, 4) + '-4000-8' + u.substr(12, 3) + '-' + u.substr(15, 12);
1288
+ }
1289
+
1290
+
1291
+
1292
+
1293
+ ////////////////////////////////////
1294
+ ////////////////////////////////////
1295
+ ////////////////////////////////////
1296
+
1297
+ /**
1298
+ * Helper function for cleaning strings to use as database ids
1299
+ * @alias utils.machineName
1300
+ * @param {String} string The string to clean eg. (Awesome Event!)
1301
+ * @return {String} A cleaned and formatted string eg. (awesomeEvent)
1302
+ */
1303
+ service.machineName = function(string) {
1304
+
1305
+ if (!string || !string.length) {
1306
+ return;
1307
+ }
1308
+
1309
+ var regexp = /[^a-zA-Z0-9-_]+/g;
1310
+ var cleaned = String(string).replace(regexp, ' ').trim();
1311
+ return _camelCase(cleaned);
1312
+ }
1313
+
1314
+ /////////////////////////////////////////////
1315
+ /////////////////////////////////////////////
1316
+ /////////////////////////////////////////////
1317
+
1318
+
1319
+ export default service;
1320
+
1321
+
1322
+ /////////////////////////////////////////////
1323
+
1324
+ //Export the event dispatcher
1325
+ export function EventDispatcher() {
1326
+
1327
+ var listeners = {};
1328
+
1329
+ /////////////////////////////////////////////
1330
+
1331
+ var dispatcher = {}
1332
+
1333
+ /////////////////////////////////////////////
1334
+
1335
+ //Remove all listeners
1336
+ dispatcher.removeAllListeners = function() {
1337
+ listeners = {};
1338
+ }
1339
+
1340
+ /////////////////////////////////////////////
1341
+
1342
+ dispatcher.dispatch = function(event, details) {
1343
+
1344
+ if (listeners[event]) {
1345
+ //For each listener
1346
+ listeners[event].forEach(function(callback) {
1347
+ return callback(details);
1348
+ });
1349
+ }
1350
+ }
1351
+
1352
+ /////////////////////////////////////////////
1353
+
1354
+ dispatcher.addEventListener = function(event, callback) {
1355
+
1356
+ if (!listeners[event]) {
1357
+ listeners[event] = [];
1358
+ }
1359
+
1360
+ const type = typeof callback;
1361
+ if (type !== 'function') {
1362
+ throw new Error(`addEventListener() requires a function but ${type} was added`);
1363
+ } else {
1364
+ if (listeners[event].indexOf(callback) == -1) {
1365
+ //Add to the listeners
1366
+ listeners[event].push(callback)
1367
+ } else {
1368
+ //A
1369
+ //lready listening
1370
+ }
1371
+ }
1372
+ }
1373
+
1374
+ /////////////////////////////////////////////
1375
+
1376
+ dispatcher.removeEventListener = function(event, callback) {
1377
+
1378
+ if (!listeners[event]) {
1379
+ listeners[event] = [];
1380
+ }
1381
+
1382
+ //Get the index of the listener
1383
+ var index = listeners[event].indexOf(callback);
1384
+
1385
+ if (index != -1) {
1386
+ //Remove from the listeners
1387
+ listeners[event].splice(index, 1);
1388
+ }
1389
+ }
1390
+
1391
+
1392
+ /////////////////////////////////////////////
1393
+
1394
+ //Wrap the event listener functionality
1395
+ dispatcher.bootstrap = function(service) {
1396
+ if (!service) {
1397
+ // console.log('No service to bootstrap to')
1398
+ return;
1399
+ }
1400
+
1401
+ service.dispatch = dispatcher.dispatch;
1402
+ service.addEventListener = dispatcher.addEventListener;
1403
+ service.removeEventListener = dispatcher.removeEventListener;
1404
+ service.removeAllListeners = dispatcher.removeAllListeners;
1405
+ }
1406
+
1407
+ /////////////////////////////////////////////
1408
+
1409
+ return dispatcher;
1410
+ }