skapi-js 0.0.52 → 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/dist/skapi.js +3 -0
- package/dist/skapi.js.LICENSE.txt +21 -0
- package/dist/skapi.js.map +1 -0
- package/dist/skapi.module.js +3 -0
- package/dist/skapi.module.js.LICENSE.txt +21 -0
- package/dist/skapi.module.js.map +1 -0
- package/package.json +4 -1
- package/deploy.py +0 -29
- package/src/Api.ts +0 -3
- package/src/Types.ts +0 -386
- package/src/decorators.ts +0 -95
- package/src/skapi.ts +0 -3387
- package/src/skapi_error.ts +0 -43
- package/src/utils.ts +0 -794
- package/tsconfig.json +0 -116
- package/webpack.config.js +0 -25
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
|
-
};
|