skapi-js 0.0.51 → 0.0.53

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/src/utils.ts DELETED
@@ -1,794 +0,0 @@
1
- import SkapiError from "./skapi_error";
2
- import { RecordData, Form } from "./Types";
3
-
4
- class MD5 {
5
- private static readonly alphabet = '0123456789abcdef';
6
-
7
- public static hash(str?: string): string {
8
- if (typeof str !== 'string') {
9
- console.warn('coercing non-string value to empty string');
10
- str = '';
11
- }
12
-
13
- const x = MD5.sb(str);
14
- let a = 1732584193;
15
- let b = -271733879;
16
- let c = -1732584194;
17
- let d = 271733878;
18
- let lastA;
19
- let lastB;
20
- let lastC;
21
- let lastD;
22
- for (let i = 0; i < x.length; i += 16) {
23
- lastA = a;
24
- lastB = b;
25
- lastC = c;
26
- lastD = d;
27
-
28
- a = MD5.ff(a, b, c, d, x[i], 7, -680876936);
29
- d = MD5.ff(d, a, b, c, x[i + 1], 12, -389564586);
30
- c = MD5.ff(c, d, a, b, x[i + 2], 17, 606105819);
31
- b = MD5.ff(b, c, d, a, x[i + 3], 22, -1044525330);
32
- a = MD5.ff(a, b, c, d, x[i + 4], 7, -176418897);
33
- d = MD5.ff(d, a, b, c, x[i + 5], 12, 1200080426);
34
- c = MD5.ff(c, d, a, b, x[i + 6], 17, -1473231341);
35
- b = MD5.ff(b, c, d, a, x[i + 7], 22, -45705983);
36
- a = MD5.ff(a, b, c, d, x[i + 8], 7, 1770035416);
37
- d = MD5.ff(d, a, b, c, x[i + 9], 12, -1958414417);
38
- c = MD5.ff(c, d, a, b, x[i + 10], 17, -42063);
39
- b = MD5.ff(b, c, d, a, x[i + 11], 22, -1990404162);
40
- a = MD5.ff(a, b, c, d, x[i + 12], 7, 1804603682);
41
- d = MD5.ff(d, a, b, c, x[i + 13], 12, -40341101);
42
- c = MD5.ff(c, d, a, b, x[i + 14], 17, -1502002290);
43
- b = MD5.ff(b, c, d, a, x[i + 15], 22, 1236535329);
44
- a = MD5.gg(a, b, c, d, x[i + 1], 5, -165796510);
45
- d = MD5.gg(d, a, b, c, x[i + 6], 9, -1069501632);
46
- c = MD5.gg(c, d, a, b, x[i + 11], 14, 643717713);
47
- b = MD5.gg(b, c, d, a, x[i], 20, -373897302);
48
- a = MD5.gg(a, b, c, d, x[i + 5], 5, -701558691);
49
- d = MD5.gg(d, a, b, c, x[i + 10], 9, 38016083);
50
- c = MD5.gg(c, d, a, b, x[i + 15], 14, -660478335);
51
- b = MD5.gg(b, c, d, a, x[i + 4], 20, -405537848);
52
- a = MD5.gg(a, b, c, d, x[i + 9], 5, 568446438);
53
- d = MD5.gg(d, a, b, c, x[i + 14], 9, -1019803690);
54
- c = MD5.gg(c, d, a, b, x[i + 3], 14, -187363961);
55
- b = MD5.gg(b, c, d, a, x[i + 8], 20, 1163531501);
56
- a = MD5.gg(a, b, c, d, x[i + 13], 5, -1444681467);
57
- d = MD5.gg(d, a, b, c, x[i + 2], 9, -51403784);
58
- c = MD5.gg(c, d, a, b, x[i + 7], 14, 1735328473);
59
- b = MD5.gg(b, c, d, a, x[i + 12], 20, -1926607734);
60
- a = MD5.hh(a, b, c, d, x[i + 5], 4, -378558);
61
- d = MD5.hh(d, a, b, c, x[i + 8], 11, -2022574463);
62
- c = MD5.hh(c, d, a, b, x[i + 11], 16, 1839030562);
63
- b = MD5.hh(b, c, d, a, x[i + 14], 23, -35309556);
64
- a = MD5.hh(a, b, c, d, x[i + 1], 4, -1530992060);
65
- d = MD5.hh(d, a, b, c, x[i + 4], 11, 1272893353);
66
- c = MD5.hh(c, d, a, b, x[i + 7], 16, -155497632);
67
- b = MD5.hh(b, c, d, a, x[i + 10], 23, -1094730640);
68
- a = MD5.hh(a, b, c, d, x[i + 13], 4, 681279174);
69
- d = MD5.hh(d, a, b, c, x[i], 11, -358537222);
70
- c = MD5.hh(c, d, a, b, x[i + 3], 16, -722521979);
71
- b = MD5.hh(b, c, d, a, x[i + 6], 23, 76029189);
72
- a = MD5.hh(a, b, c, d, x[i + 9], 4, -640364487);
73
- d = MD5.hh(d, a, b, c, x[i + 12], 11, -421815835);
74
- c = MD5.hh(c, d, a, b, x[i + 15], 16, 530742520);
75
- b = MD5.hh(b, c, d, a, x[i + 2], 23, -995338651);
76
- a = MD5.ii(a, b, c, d, x[i], 6, -198630844);
77
- d = MD5.ii(d, a, b, c, x[i + 7], 10, 1126891415);
78
- c = MD5.ii(c, d, a, b, x[i + 14], 15, -1416354905);
79
- b = MD5.ii(b, c, d, a, x[i + 5], 21, -57434055);
80
- a = MD5.ii(a, b, c, d, x[i + 12], 6, 1700485571);
81
- d = MD5.ii(d, a, b, c, x[i + 3], 10, -1894986606);
82
- c = MD5.ii(c, d, a, b, x[i + 10], 15, -1051523);
83
- b = MD5.ii(b, c, d, a, x[i + 1], 21, -2054922799);
84
- a = MD5.ii(a, b, c, d, x[i + 8], 6, 1873313359);
85
- d = MD5.ii(d, a, b, c, x[i + 15], 10, -30611744);
86
- c = MD5.ii(c, d, a, b, x[i + 6], 15, -1560198380);
87
- b = MD5.ii(b, c, d, a, x[i + 13], 21, 1309151649);
88
- a = MD5.ii(a, b, c, d, x[i + 4], 6, -145523070);
89
- d = MD5.ii(d, a, b, c, x[i + 11], 10, -1120210379);
90
- c = MD5.ii(c, d, a, b, x[i + 2], 15, 718787259);
91
- b = MD5.ii(b, c, d, a, x[i + 9], 21, -343485551);
92
-
93
- a = MD5.ad(a, lastA);
94
- b = MD5.ad(b, lastB);
95
- c = MD5.ad(c, lastC);
96
- d = MD5.ad(d, lastD);
97
- }
98
-
99
- return MD5.rh(a) + MD5.rh(b) + MD5.rh(c) + MD5.rh(d);
100
- }
101
-
102
- private static rh(n: number): string {
103
- let s = '';
104
- for (let j = 0; j <= 3; j++) {
105
- s += MD5.alphabet.charAt((n >> (j * 8 + 4)) & 0x0F) + MD5.alphabet.charAt((n >> (j * 8)) & 0x0F);
106
- }
107
-
108
- return s;
109
- }
110
-
111
- private static ad(x: number, y: number): number {
112
- const l = (x & 0xFFFF) + (y & 0xFFFF);
113
- const m = (x >> 16) + (y >> 16) + (l >> 16);
114
-
115
- return (m << 16) | (l & 0xFFFF);
116
- }
117
-
118
- private static rl(n: number, c: number): number {
119
- return (n << c) | (n >>> (32 - c));
120
- }
121
-
122
- private static cm(q: number, a: number, b: number, x: number, s: number, t: number): number {
123
- return MD5.ad(MD5.rl(MD5.ad(MD5.ad(a, q), MD5.ad(x, t)), s), b);
124
- }
125
-
126
- private static ff(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number {
127
- return MD5.cm(b & c | ~b & d, a, b, x, s, t);
128
- }
129
-
130
- private static gg(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number {
131
- return MD5.cm(b & d | c & ~d, a, b, x, s, t);
132
- }
133
-
134
- private static hh(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number {
135
- return MD5.cm(b ^ c ^ d, a, b, x, s, t);
136
- }
137
-
138
- private static ii(a: number, b: number, c: number, d: number, x: number, s: number, t: number): number {
139
- return MD5.cm(c ^ (b | ~d), a, b, x, s, t);
140
- }
141
-
142
- private static sb(x: string): number[] {
143
- let i;
144
- const numBlocks = ((x.length + 8) >> 6) + 1;
145
-
146
- const blocks = new Array(numBlocks * 16);
147
- for (i = 0; i < numBlocks * 16; i++) {
148
- blocks[i] = 0;
149
- }
150
-
151
- for (i = 0; i < x.length; i++) {
152
- blocks[i >> 2] |= x.charCodeAt(i) << ((i % 4) * 8);
153
- }
154
-
155
- blocks[i >> 2] |= 0x80 << ((i % 4) * 8);
156
- blocks[numBlocks * 16 - 2] = x.length * 8;
157
-
158
- return blocks;
159
- }
160
- }
161
-
162
- // validation checks
163
-
164
- function validateUserId(id: string, param = 'User ID') {
165
- let uuid_regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
166
-
167
- if (!id) {
168
- throw new SkapiError(`${param} is empty.`, { code: 'INVALID_PARAMETER' });
169
- }
170
- else if (typeof id !== 'string') {
171
- throw new SkapiError(`${param} should be type: string.`, { code: 'INVALID_PARAMETER' });
172
- }
173
- else if (!id.match(uuid_regex)) {
174
- throw new SkapiError(`${param} is invalid.`, { code: 'INVALID_PARAMETER' });
175
- }
176
-
177
- return id;
178
- }
179
-
180
- function validatePhoneNumber(value: string) {
181
- if (typeof value !== 'string' || value.charAt(0) !== '+' || isNaN(Number(value.substring(1)))) {
182
- throw new SkapiError('"phone_number" is invalid. The format should be "+00123456789". Type: string.', { code: 'INVALID_PARAMETER' });
183
- }
184
- return value;
185
- }
186
-
187
- function validateBirthdate(birthdate: string) {
188
- // yyyy-mm-dd
189
- if (typeof birthdate !== 'string') {
190
- throw new SkapiError('"birthdate" is invalid. The format should be "yyyy-mm-dd". Type: string.', { code: 'INVALID_PARAMETER' });
191
- }
192
-
193
- else {
194
- let date_regex = new RegExp(/([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))/);
195
- if (birthdate.length !== 10 || birthdate.split('-').length !== 3 || !date_regex.test(birthdate)) {
196
- throw new SkapiError('"birthdate" is invalid. The format should be "yyyy-mm-dd". Type: string.', { code: 'INVALID_PARAMETER' });
197
- }
198
- }
199
- return birthdate;
200
- }
201
-
202
- function validatePassword(password: string) {
203
- if (!password) {
204
- throw new SkapiError('"password" is empty.', { code: 'PASSWORD_REQUIRED' });
205
- }
206
- else if (typeof password !== 'string') {
207
- throw new SkapiError('"password" should be type: string.', { code: 'INVALID_PASSWORD' });
208
- }
209
- else if (password.length < 6) {
210
- throw new SkapiError('"password" should be at least 6 characters.', { code: 'INVALID_PASSWORD' });
211
- }
212
- else if (password.length > 60) {
213
- throw new SkapiError('"password" can be up to 60 characters max.', { code: 'INVALID_PASSWORD' });
214
- }
215
-
216
- return password;
217
- }
218
-
219
- function validateEmail(email: string, paramName: string = 'email') {
220
- if (!email) {
221
- throw new SkapiError(`"${paramName}" is empty.`, { code: 'EMAIL_REQUIRED' });
222
- }
223
-
224
- else if (typeof email !== 'string') {
225
- throw new SkapiError(`"${paramName}"should be type: string.`, { code: 'INVALID_EMAIL' });
226
- }
227
-
228
- else if (email.length < 5 || email.length > 64) {
229
- throw new SkapiError(`"${paramName}" should be at least 5 characters and max 64 characters.`, { code: 'INVALID_EMAIL' });
230
- }
231
-
232
- else if (/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(email)) {
233
- email = email.trim();
234
- let splitAt = email.split('@');
235
- let tld = splitAt[1].split('.');
236
-
237
- if (tld.length >= 2) {
238
- return email.toLowerCase();
239
- }
240
- }
241
-
242
- throw new SkapiError(`"${email}" is an invalid email.`, { code: 'INVALID_EMAIL' });
243
- }
244
-
245
- function validateUrl(url: string | string[]) {
246
- const baseUrl = (() => {
247
- let baseUrl = window?.location?.origin || null;
248
-
249
- if (baseUrl === 'file://') {
250
- baseUrl += window.location.pathname;
251
- let _baseUrl = baseUrl.split('/');
252
- _baseUrl.pop();
253
- baseUrl = _baseUrl.join('/');
254
- }
255
-
256
- return baseUrl;
257
- })();
258
- let check = (c: string) => {
259
- if (typeof c === 'string') {
260
- if (c === '*') {
261
- return '*';
262
- }
263
- else {
264
- let cu = c.trim();
265
- if (!cu.includes(' ') && !cu.includes(',')) {
266
- if (cu.substring(0, 1) === '/' && baseUrl) {
267
- cu = baseUrl + cu;
268
- }
269
- let _url = null;
270
-
271
- try {
272
- _url = new URL(cu);
273
- } catch (err) {
274
- throw new SkapiError(`"${c}" is an invalid url.`, { code: 'INVALID_PARAMETER' });
275
- }
276
-
277
- if (_url.protocol) {
278
- let url = _url.href;
279
- if (url.charAt(url.length - 1) === '/')
280
- url = url.substring(0, url.length - 1);
281
-
282
- return url;
283
- }
284
- }
285
- }
286
- }
287
-
288
- throw new SkapiError(`"${c}" is an invalid url.`, { code: 'INVALID_PARAMETER' });
289
- };
290
-
291
- if (Array.isArray(url)) {
292
- return url.map(u => check(u));
293
- }
294
- else {
295
- return check(url);
296
- }
297
- }
298
-
299
- function normalize_record_data(record: Record<string, any>): RecordData {
300
- function base_decode(chars) {
301
- let charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
302
- return chars.split('').reverse().reduce((prev, curr, i) =>
303
- prev + (charset.indexOf(curr) * (62 ** i)), 0);
304
- }
305
-
306
- const output: Record<string, any> = {
307
- config: {
308
- reference_limit: null
309
- }
310
- };
311
-
312
- const keys = {
313
- 'ip': (r: string) => {
314
- output.ip = r;
315
- },
316
- 'rec': (r: string) => {
317
- if (!r) return;
318
- output.record_id = r;
319
- let base62timestamp = r.substring(0, r.length - 9); // id: [base62 timestamp][random 5 char][suid]
320
- let uploaded = base_decode(base62timestamp);
321
- output.uploaded = uploaded;
322
- },
323
- 'usr': (r: string) => {
324
- output.user_id = r;
325
- },
326
- 'tbl': (r: string) => {
327
- if (!r) return;
328
- let rSplit = r.split('/');
329
- output.table = rSplit[0];
330
- output.access_group = rSplit[2] == '**' ? 'private' : parseInt(rSplit[2]);
331
- if (rSplit?.[3]) {
332
- output.subscription = {
333
- user_id: rSplit[3],
334
- group: parseInt(rSplit[4])
335
- };
336
- }
337
- },
338
- 'idx': (r: string) => {
339
- if (!r) return;
340
- let rSplit = r.split('!');
341
- let name = rSplit.splice(0, 1)[0];
342
- let value = normalize_typed_string('!' + rSplit.join('!'));
343
- output.index = {
344
- name,
345
- value
346
- };
347
- },
348
- 'ref': (r: string) => {
349
- if (!r) return;
350
- output.reference = r.split('/')[0];
351
- },
352
- 'tags': (r: string[]) => {
353
- output.tags = r;
354
- },
355
- 'upd': (r: number) => {
356
- output.updated = r;
357
- },
358
- 'acpt_mrf': (r: boolean) => {
359
- output.config.allow_multiple_reference = r;
360
- },
361
- 'ref_limt': (r: number) => {
362
- output.config.reference_limit = r;
363
- },
364
- 'rfd': (r: number) => {
365
- output.referenced_count = r;
366
- },
367
- 'data': (r: any) => {
368
- let data = r;
369
- if (r === '!D%{}') {
370
- data = {};
371
- }
372
- else if (r === '!L%[]') {
373
- data = [];
374
- }
375
- output.data = data;
376
- }
377
- };
378
-
379
- if (record.record_id) {
380
- // bypass already normalized records
381
- return record as RecordData;
382
- }
383
-
384
- for (let k in keys) {
385
- keys[k](record[k]);
386
- }
387
-
388
- return output as RecordData;
389
- }
390
-
391
- function normalize_typed_string(v: string) {
392
- let value = v.substring(3);
393
- let type = v.substring(0, 3);
394
-
395
- switch (type) {
396
- case "!S%":
397
- // !S%string
398
- return value;
399
- case "!N%":
400
- // !N%0
401
- return Number(value) - 4503599627370496;
402
- case "!B%":
403
- // !B%1
404
- return value === '1';
405
- case "!L%":
406
- case "!D%":
407
- // !L%[0, "hello"] / !D%{}
408
- try {
409
- return JSON.parse(value);
410
- } catch (err) {
411
- throw new SkapiError('Value parse error.', { code: 'PARSE_ERROR' });
412
- }
413
- default:
414
- return v;
415
- }
416
- }
417
-
418
- function checkWhiteSpaceAndSpecialChars(
419
- string: string | string[],
420
- p = 'parameter',
421
- allowPeriods = false,
422
- allowWhiteSpace = false
423
- ) {
424
- let checkStr = (s: string) => {
425
- if (typeof s !== 'string') {
426
- throw new SkapiError(`${p} should be type: <string | string[]>.`, { code: 'INVALID_PARAMETER' });
427
- }
428
-
429
- if (!allowWhiteSpace && string.includes(' ')) {
430
- throw new SkapiError(`${p} should not have whitespace.`, { code: 'INVALID_PARAMETER' });
431
- }
432
-
433
- if (!allowPeriods && string.includes('.')) {
434
- throw new SkapiError(`${p} should not have periods.`, { code: 'INVALID_PARAMETER' });
435
- }
436
-
437
- if (/[`!@#$%^&*()_+\-=\[\]{};':"\\|,<>\/?~]/.test(s)) {
438
- throw new SkapiError(`${p} should not have special characters.`, { code: 'INVALID_PARAMETER' });
439
- }
440
- };
441
-
442
- if (Array.isArray(string)) {
443
- for (let s of string) {
444
- checkStr(s);
445
- }
446
- }
447
-
448
- else {
449
- checkStr(string);
450
- }
451
-
452
- return string;
453
- }
454
-
455
- function checkParams(
456
- params: any,
457
- struct: Record<string, any>,
458
- required: string[] | null = null,
459
- bypassCheck: string[] | null = [],
460
- _parentKey: string | null = null
461
- ): any {
462
- // struct = {
463
- // a: 'boolean',
464
- // b: ['number', 'boolean', 'string', 'array', 'function', 'custom value', () => 'default value'],
465
- // c: (v: any) => { return 'value to assign'; }
466
- // }
467
-
468
- if (Array.isArray(bypassCheck)) {
469
- bypassCheck = bypassCheck.concat([
470
- // list of default key names to bypass
471
- 'service',
472
- 'service_owner',
473
- // 'alertError',
474
- // 'response',
475
- // 'startKey'
476
- ]);
477
- }
478
-
479
- function isObjectWithKeys(obj: any) {
480
- if (obj instanceof Promise) {
481
- throw new SkapiError('Parameter should not be a promise', { code: 'INVALID_PARAMETER' });
482
- }
483
- return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length;
484
- }
485
-
486
- function isEmptyObject(obj: any) {
487
- return obj && typeof obj === 'object' && !Array.isArray(obj) && !Object.keys(obj).length;
488
- }
489
-
490
- let _params = params; // processed params
491
- let val: any; // value to return
492
- let errToThrow: any = null; // error msg to output
493
- let isInvalid = _parentKey ? ` in "${_parentKey}" is invalid.` : '. Parameter should be type <object>.';
494
-
495
- if (_parentKey === null) {
496
- // parent level. executes on first run
497
- if (isObjectWithKeys(_params)) {
498
- if (_params instanceof HTMLFormElement || _params instanceof FormData) {
499
- // first execution, it's an object or form element
500
- _params = extractFormMetaData(params)?.meta;
501
- }
502
-
503
- else {
504
- _params = JSON.parse(JSON.stringify(params));
505
- }
506
-
507
- for (let k in _params) {
508
- // check if there is invalid key names
509
- if (!struct.hasOwnProperty(k) && Array.isArray(bypassCheck) && !bypassCheck.includes(k)) {
510
- throw new SkapiError(`Key name "${k}" is invalid in parameter.`, { code: 'INVALID_PARAMETER' });
511
- }
512
- }
513
-
514
- if (Array.isArray(required) && required.length) {
515
- // check if any required key names are missing
516
- for (let k of required) {
517
- if (!Object.keys(_params).includes(k)) {
518
- throw new SkapiError(`Key "${k}" is required in parameter.`, { code: 'INVALID_PARAMETER' });
519
- }
520
- }
521
- }
522
- }
523
-
524
- else if (isEmptyObject(_params) || typeof _params === 'undefined') {
525
- // parameter is empty or undefined
526
- let defaults: Record<string, any> = {};
527
-
528
- // sets default for all keys
529
- // key: [()=>'default']
530
- for (let s in struct) {
531
- // iterate whole structure object
532
- let structValue = struct[s];
533
- if (Array.isArray(structValue) && typeof structValue[structValue.length - 1] === 'function')
534
- // set all default values
535
- defaults[s] = structValue[structValue.length - 1]();
536
- }
537
-
538
- // return if there is any default value
539
- return Object.keys(defaults).length ? defaults : _params;
540
- }
541
-
542
- if (_params === null) {
543
- // if null ignore defaults
544
- return null;
545
- }
546
- }
547
-
548
- if (isObjectWithKeys(struct) && isObjectWithKeys(_params)) {
549
- for (let s in struct) {
550
- // loop through structure keys
551
- let structValue = struct[s];
552
-
553
- if (_params.hasOwnProperty(s) && typeof _params[s] != 'undefined') {
554
- // recurse to check data type
555
- _params[s] = checkParams(_params[s], structValue, null, null, s);
556
- }
557
-
558
- else {
559
- // if current _params does not have the corresponding key name
560
- let defaultSetter =
561
- Array.isArray(structValue) &&
562
- typeof structValue[structValue.length - 1] === 'function' ? structValue[structValue.length - 1] : null;
563
-
564
- if (defaultSetter) {
565
- // set default
566
- let def = defaultSetter();
567
- if (def !== undefined) {
568
- _params[s] = def;
569
- }
570
- }
571
- }
572
- }
573
-
574
- val = _params;
575
- }
576
-
577
- // recursive level
578
- else if (Array.isArray(struct)) {
579
- // loop through value types
580
- for (let s of struct) {
581
- try {
582
- if (typeof _params !== undefined && typeof s !== 'function') {
583
- // dive in, check value types
584
- val = checkParams(_params, s, null, null, _parentKey);
585
- }
586
- // if error, loop to next, otherwise break
587
- break;
588
- } catch (err) {
589
- if (typeof err === 'string' && err.substring(0, 6) === 'BREAK:') {
590
- // break on BREAK message
591
- err = err.substring(6);
592
- let errMsg = (err as string).split(':');
593
- errToThrow = new SkapiError(errMsg[1], { code: errMsg[0] });
594
- break;
595
- }
596
- else {
597
- errToThrow = err;
598
- }
599
- }
600
- }
601
- }
602
-
603
- // returned values will be applied to params
604
- else if (typeof struct === 'function') {
605
- return struct(_params);
606
- }
607
-
608
- else if (typeof struct === 'string') {
609
- // setup value type range
610
- if (Array.isArray(_params)) {
611
- // check for array
612
- if (struct !== 'array') {
613
- throw new SkapiError(`Invalid type "${typeof _params}"${isInvalid}`, { code: 'INVALID_PARAMETER' });
614
- }
615
-
616
- // array only accepts number, string, boolean, null.
617
- // object is not allowed to be nested in array.
618
- for (let p of _params) {
619
- if (!['number', 'string', 'boolean'].includes(typeof p) && p !== null) {
620
- throw new SkapiError(`Invalid type "${typeof p}" in "${_parentKey}" array value.`, { code: 'INVALID_PARAMETER' });
621
- }
622
- }
623
-
624
- val = _params;
625
- }
626
- else if (!['number', 'string', 'boolean', 'array', 'function'].includes(struct)) {
627
- // match custom string values
628
- if (_params === struct) {
629
- val = _params;
630
- }
631
-
632
- else {
633
- throw new SkapiError(`Value: ${_params}${isInvalid}`, { code: 'INVALID_PARAMETER' });
634
- }
635
- }
636
- else if (typeof _params === struct) {
637
- if (struct === 'number') {
638
- // throws error if number range is invalid
639
- if (Math.abs(_params) > 4503599627370496) {
640
- throw `BREAK:INVALID_PARAMETER:"${_parentKey}" integer value should be within -4503599627370496 ~ +4503599627370546.`;
641
- }
642
- }
643
-
644
- val = _params;
645
- }
646
- else {
647
- throw new SkapiError(`Value: ${_params}${isInvalid}`, { code: 'INVALID_PARAMETER' });
648
- }
649
- }
650
-
651
- else if (struct === null) {
652
- // bypass value on null
653
- val = _params;
654
- }
655
-
656
- if (val === undefined && errToThrow) {
657
- throw errToThrow;
658
- }
659
-
660
- return val;
661
- }
662
-
663
- function extractFormMetaData(form: Form) {
664
- // creates meta object to post
665
-
666
- function appendData(meta, key, val, append = true) {
667
- if (meta[key] && append) {
668
- if (Array.isArray(meta)) {
669
- meta[key].push(val);
670
- }
671
- else {
672
- meta[key] = [meta[key], val];
673
- }
674
- }
675
- else {
676
- meta[key] = val;
677
- }
678
- }
679
-
680
- if (form instanceof FormData) {
681
- let meta = {};
682
- let totalFileSize = 0;
683
- let files = [];
684
-
685
- for (let pair of form.entries()) {
686
- let name = pair[0];
687
- let v: any = pair[1];
688
-
689
- if (v instanceof File) {
690
- if (!files.includes(name)) {
691
- files.push(name);
692
- }
693
-
694
- totalFileSize += Math.round((v.size / 1024));
695
- }
696
-
697
- else if (v instanceof FileList) {
698
- if (!files.includes(name)) {
699
- files.push(name);
700
- }
701
-
702
- if (v && v.length > 0) {
703
- for (let idx = 0; idx <= v.length - 1; idx++) {
704
- totalFileSize += Math.round((v.item(idx).size / 1024));
705
- }
706
- }
707
- }
708
-
709
- else {
710
- appendData(meta, name, v);
711
- }
712
- }
713
-
714
- if (totalFileSize > 5120) {
715
- throw new SkapiError('Files cannot exceed 5MB. Use skapi.uploadFiles(...) instead.', { code: 'INVALID_REQUEST' });
716
- }
717
-
718
- return { meta, files };
719
- }
720
-
721
- else if (form instanceof HTMLFormElement) {
722
- let meta = {};
723
- let files = [];
724
- let totalFileSize = 0;
725
- let inputs = form.querySelectorAll('input');
726
- let textarea = form.querySelectorAll('textarea');
727
-
728
- for (let i of textarea) {
729
- if (i.name) {
730
- appendData(meta, i.name, i.value);
731
- }
732
- }
733
-
734
- for (let i of inputs) {
735
- if (i.name) {
736
- if (i.type === 'number' && i.value) {
737
- appendData(meta, i.name, Number(i.value));
738
- }
739
-
740
- else if (i.type === 'checkbox' || i.type === 'radio') {
741
- if (i.value === 'on' || i.value === 'true') {
742
- appendData(meta, i.name, i.checked, false);
743
- }
744
-
745
- else if (i.value === 'false') {
746
- appendData(meta, i.name, !i.checked, false);
747
- }
748
-
749
- else if (i.checked) {
750
- appendData(meta, i.name, i.value, false);
751
- }
752
- }
753
-
754
- else if (i.type === 'file') {
755
- if (!files.includes(i.name)) {
756
- files.push(i.name);
757
- }
758
-
759
- if (i.files && i.files.length > 0) {
760
- for (let idx = 0; idx <= i.files.length - 1; idx++) {
761
- totalFileSize += Math.round((i.files.item(idx).size / 1024));
762
- }
763
- }
764
- }
765
-
766
- else {
767
- appendData(meta, i.name, i.value);
768
- }
769
- }
770
- }
771
-
772
- if (totalFileSize > 5120) {
773
- throw new SkapiError('Files cannot exceed 5MB. Use skapi.uploadFiles(...) instead.', { code: 'INVALID_REQUEST' });
774
- }
775
-
776
- return { meta, files };
777
- }
778
-
779
- return null;
780
- }
781
-
782
- export {
783
- checkWhiteSpaceAndSpecialChars,
784
- normalize_record_data,
785
- checkParams,
786
- extractFormMetaData,
787
- validateUserId,
788
- validateBirthdate,
789
- validateEmail,
790
- validatePassword,
791
- validatePhoneNumber,
792
- validateUrl,
793
- MD5
794
- };