total5 0.0.1-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/503.html +65 -0
  2. package/CONTRIBUTING.md +55 -0
  3. package/LICENSE +211 -0
  4. package/README.md +32 -0
  5. package/api.js +289 -0
  6. package/bin/total5 +984 -0
  7. package/builders.js +1435 -0
  8. package/bundles.js +457 -0
  9. package/cache.js +58 -0
  10. package/changelog.txt +3 -0
  11. package/cluster.js +320 -0
  12. package/cms.js +625 -0
  13. package/controller.js +1419 -0
  14. package/cron.js +99 -0
  15. package/debug.js +539 -0
  16. package/edit.js +469 -0
  17. package/error.html +49 -0
  18. package/filestorage.js +1088 -0
  19. package/flow-flowstream.js +3152 -0
  20. package/flow.js +209 -0
  21. package/flowstream.js +1991 -0
  22. package/global.js +125 -0
  23. package/helpers/index.js +32 -0
  24. package/htmlparser.js +650 -0
  25. package/http.js +81 -0
  26. package/image.js +773 -0
  27. package/images.js +747 -0
  28. package/index.js +2658 -0
  29. package/jsonschema.js +691 -0
  30. package/ldap.js +792 -0
  31. package/mail.js +936 -0
  32. package/minificators.js +858 -0
  33. package/nosql-builder.js +440 -0
  34. package/nosql-querybuilder.js +316 -0
  35. package/nosql-reader.js +353 -0
  36. package/nosql-stream.js +617 -0
  37. package/nosql.js +763 -0
  38. package/openclient.js +219 -0
  39. package/package.json +32 -0
  40. package/pause.html +67 -0
  41. package/querybuilder.js +1361 -0
  42. package/release.js +167 -0
  43. package/routing.js +905 -0
  44. package/sourcemap.js +160 -0
  45. package/tangular.js +409 -0
  46. package/templates.js +145 -0
  47. package/templates.json +74 -0
  48. package/tms.js +384 -0
  49. package/tmsclient.js +125 -0
  50. package/todo.txt +7 -0
  51. package/tools/beta.sh +6 -0
  52. package/tools/release.sh +6 -0
  53. package/uibuilder.js +206 -0
  54. package/utils.js +6374 -0
  55. package/viewengine.js +880 -0
  56. package/websocket.js +1939 -0
  57. package/workers.js +129 -0
package/builders.js ADDED
@@ -0,0 +1,1435 @@
1
+ // Total.js Builders
2
+ // The MIT License
3
+ // Copyright 2023 (c) Peter Širka <petersirka@gmail.com>
4
+
5
+ 'use strict';
6
+
7
+ const REG_ARGS = /\{{1,2}[a-z0-9_.-\s]+\}{1,2}/gi;
8
+
9
+ var transforms = { error: {}, restbuilder: {} };
10
+ var restbuilderupgrades = [];
11
+
12
+ function Options(ctrl, error) {
13
+ var t = this;
14
+ t.controller = ctrl;
15
+ t.error = error || new ErrorBuilder();
16
+ t.response = {};
17
+ }
18
+
19
+ Options.prototype = {
20
+
21
+ get client() {
22
+ return this.controller;
23
+ },
24
+
25
+ get websocket() {
26
+ return this.controller.parent;
27
+ },
28
+
29
+ get value() {
30
+ return this.payload;
31
+ },
32
+
33
+ get model() {
34
+ return this.payload;
35
+ },
36
+
37
+ set value(value) {
38
+ this.payload = value;
39
+ },
40
+
41
+ set model(value) {
42
+ this.payload = value;
43
+ },
44
+
45
+ get url() {
46
+ return (this.controller ? this.controller.url : '') || '';
47
+ },
48
+
49
+ get uri() {
50
+ return this.controller ? this.controller.uri : null;
51
+ },
52
+
53
+ get path() {
54
+ return (this.controller ? this.controller.pathname : EMPTYARRAY);
55
+ },
56
+
57
+ get split() {
58
+ return (this.controller ? this.controller.split : EMPTYARRAY);
59
+ },
60
+
61
+ get split2() {
62
+ return (this.controller ? this.controller.split2 : EMPTYARRAY);
63
+ },
64
+
65
+ get language() {
66
+ return (this.controller ? this.controller.language : '') || '';
67
+ },
68
+
69
+ get ip() {
70
+ return this.controller ? this.controller.ip : null;
71
+ },
72
+
73
+ get files() {
74
+ return this.controller ? this.controller.files : null;
75
+ },
76
+
77
+ get body() {
78
+ return this.controller ? this.controller.body : null;
79
+ },
80
+
81
+ get mobile() {
82
+ return this.controller ? this.controller.mobile : null;
83
+ },
84
+
85
+ get headers() {
86
+ return this.controller ? this.controller.headers : null;
87
+ },
88
+
89
+ get ua() {
90
+ return this.controller ? this.controller.ua : null;
91
+ }
92
+ };
93
+
94
+ Options.prototype.action = function(schema, payload) {
95
+ return F.action(schema, payload, this.controller);
96
+ };
97
+
98
+ Options.prototype.publish = function(value) {
99
+ var self = this;
100
+ var name = self.id;
101
+ if (F.TMS.cache.socket && F.TMS.cache.pcache[name] && F.TMS.cache.publishers[name]) {
102
+
103
+ var tmp = {};
104
+ if (tmp) {
105
+ for (var key in value) {
106
+ if (!self.$publish || self.$publish[key])
107
+ tmp[key] = value[key];
108
+ }
109
+ }
110
+
111
+ F.stats.performance.publish++;
112
+ F.TMS.cache.socket.send({ type: 'publish', id: name, data: tmp }, client => client.tmsready);
113
+ }
114
+ return self;
115
+ };
116
+
117
+ Options.prototype.on = function(name, fn) {
118
+ var self = this;
119
+ if (!self.events)
120
+ self.events = {};
121
+ if (!self.events[name])
122
+ self.events[name] = [];
123
+ self.events[name].push(fn);
124
+ return self;
125
+ };
126
+
127
+ Options.prototype.emit = function(name, a, b, c, d) {
128
+
129
+ var self = this;
130
+
131
+ if (!self.events || !self.events[name])
132
+ return false;
133
+
134
+ for (var evt of self.events[name])
135
+ evt.call(self, a, b, c, d);
136
+
137
+ return true;
138
+ };
139
+
140
+ Options.prototype.cancel = function() {
141
+ var self = this;
142
+ self.callback = self.next = null;
143
+ self.error = null;
144
+ self.controller = null;
145
+ self.model = null;
146
+ self.options = null;
147
+ return self;
148
+ };
149
+
150
+ Options.prototype.redirect = function(url) {
151
+ this.redirect(url);
152
+ this.cancel();
153
+ };
154
+
155
+ Options.prototype.audit = function(message, type) {
156
+ F.audit(this, message ? this.variables(message) : '', type);
157
+ };
158
+
159
+ Options.prototype.success = function(value) {
160
+ var self = this;
161
+ if (self.TYPE === 'auth')
162
+ self.callback(value);
163
+ else
164
+ self.callback(DEF.onSuccess(value));
165
+ };
166
+
167
+ Options.prototype.callback = function(value) {
168
+
169
+ var self = this;
170
+
171
+ if (arguments.length == 0) {
172
+ return function(err, response) {
173
+ err && self.error.push(err);
174
+ self.callback(response);
175
+ };
176
+ }
177
+
178
+ self.$callback(self.error.items.length ? self.error : null, value);
179
+ };
180
+
181
+ Options.prototype.done = function(arg) {
182
+ var self = this;
183
+ return function(err, response) {
184
+ if (err) {
185
+ err && self.error.push(err);
186
+ self.callback();
187
+ } else {
188
+ if (self.TYPE === 'auth')
189
+ self.callback(arg === true ? response : arg);
190
+ else
191
+ self.callback(DEF.onSuccess(arg === true ? response : arg));
192
+ }
193
+ };
194
+ };
195
+
196
+ Options.prototype.invalid = function(error, path, index) {
197
+ var self = this;
198
+ self.error.push(error, path, index);
199
+ self.$callback(error);
200
+ };
201
+
202
+ Options.prototype.cookie = function(name, value, expire, options) {
203
+ var self = this;
204
+ if (value === undefined)
205
+ return self.controller.cookie(name);
206
+ if (value === null)
207
+ expire = '-1 day';
208
+ self.controller.cookie(name, value, expire, options);
209
+ return self;
210
+ };
211
+
212
+ Options.prototype.variables = function(str, data) {
213
+
214
+ if (str.indexOf('{') === -1)
215
+ return str;
216
+
217
+ var $ = this;
218
+
219
+ return str.replace(REG_ARGS, function(text) {
220
+ var l = text[1] === '{' ? 2 : 1;
221
+ var key = text.substring(l, text.length - l).trim();
222
+ var val = null;
223
+ var five = key.substring(0, 5);
224
+ if (five === 'user.') {
225
+ if ($.user) {
226
+ key = key.substring(5);
227
+ val = key.indexOf('.') === -1 ? $.user[key] : F.TUtils.get($.user, key);
228
+ }
229
+ } else if (five === 'data.') {
230
+ if (data) {
231
+ key = key.substring(5);
232
+ val = key.indexOf('.') === -1 ? data[key] : F.TUtils.get(data, key);
233
+ }
234
+ } else {
235
+ var six = key.substring(0, 6);
236
+ if (six === 'model.' || six === 'value.') {
237
+ if ($.model) {
238
+ key = key.substring(6);
239
+ val = key.indexOf('.') === -1 ? $.model[key] : F.TUtils.get($.model, key);
240
+ }
241
+ } else if (six === 'query.')
242
+ val = $.query[key.substring(6)];
243
+ else if (key.substring(0, 7) === 'params.')
244
+ val = $.params[key.substring(7)];
245
+ }
246
+ return val == null ? text : val;
247
+ });
248
+
249
+ };
250
+
251
+ function ErrorBuilder() {
252
+ var t = this;
253
+ t.items = [];
254
+ // t.replacer = null;
255
+ t.status = 400;
256
+ t.prefix = '';
257
+ }
258
+
259
+ ErrorBuilder.prototype = {
260
+ get length() {
261
+ return this.items.length;
262
+ }
263
+ };
264
+
265
+ ErrorBuilder.prototype.push = function(err, path, index) {
266
+ var self = this;
267
+
268
+ if (!err)
269
+ err = 401;
270
+
271
+ if (err > 399) {
272
+ self.status = err;
273
+ self.items.push({ error: F.TUtils.httpstatus(err) });
274
+ } else
275
+ self.items.push({ error: err.toString(), path: path, index: index });
276
+ return self;
277
+ };
278
+
279
+ ErrorBuilder.prototype.push2 = function(name, path, index) {
280
+ var self = this;
281
+ self.items.push({ name: self.prefix + name, error: '@', path: path, index: index });
282
+ return self;
283
+ };
284
+
285
+ ErrorBuilder.assign = function(arr) {
286
+ var builder = new ErrorBuilder();
287
+ if (arr instanceof Array) {
288
+ for (var i = 0; i < arr.length; i++) {
289
+ if (arr[i].error)
290
+ builder.items.push(arr[i]);
291
+ }
292
+ } else {
293
+ var type = typeof(arr);
294
+ if (type === 'number' || type === 'string')
295
+ builder.push(arr);
296
+ else if (arr instanceof Error)
297
+ builder.push(arr + '');
298
+ }
299
+ return builder;
300
+ };
301
+
302
+ ErrorBuilder.prototype.replace = function(search, value) {
303
+ var self = this;
304
+ if (!self.replacer)
305
+ self.replacer = {};
306
+ self.replacer[search] = value;
307
+ return self;
308
+ };
309
+
310
+ ErrorBuilder.prototype.output = function(language = 'default') {
311
+
312
+ var self = this;
313
+ var output = [];
314
+
315
+ for (let m of self.items) {
316
+
317
+ let err = m.error;
318
+
319
+ if (err[0] == '@')
320
+ err = F.resource(language, 'T' + (err === '@' ? m.name : err.substring(1)).hash(true).toString(36)) || 'The field "' + m.name + '" is invalid';
321
+
322
+ if (self.replacer) {
323
+ for (let key in self.replacer)
324
+ err = err.replaceAll(key, self.replacer[key]);
325
+ }
326
+
327
+ output.push({ name: m.name, error: err, path: m.path, index: m.index });
328
+ }
329
+
330
+ if (ErrorBuilder.$transform)
331
+ output = ErrorBuilder.$transform(output, language);
332
+
333
+ return output;
334
+ };
335
+
336
+ ErrorBuilder.prototype.toString = function(language = 'default') {
337
+ var self = this;
338
+ var output = self.output(language);
339
+ var str = '';
340
+ for (let err of output)
341
+ str += (str ? '\n' : '') + err.error;
342
+ return str;
343
+ };
344
+
345
+ ErrorBuilder.transform = function(callback) {
346
+ ErrorBuilder.$transform = callback;
347
+ };
348
+
349
+ function RESTBuilder(url) {
350
+
351
+ this.$length = 0;
352
+ this.$transform = transforms.restbuilder_default;
353
+ this.$persistentcookies = false;
354
+
355
+ this.options = { url: url, timeout: 10000, method: 'GET', resolve: true, headers: { 'user-agent': 'Total.js/v' + F.version_header, accept: 'application/json, text/plain, text/plain, text/xml' }};
356
+
357
+ // this.$data = {};
358
+ // this.$nodnscache = true;
359
+ // this.$expire;
360
+ // this.$redirect
361
+
362
+ // Auto Total.js Error Handling
363
+ this.$errorbuilderhandler = true;
364
+ }
365
+
366
+ RESTBuilder.make = function(fn) {
367
+ var instance = new RESTBuilder();
368
+ fn && fn(instance);
369
+ return instance;
370
+ };
371
+
372
+ RESTBuilder.url = function(url) {
373
+ return new RESTBuilder(url);
374
+ };
375
+
376
+ RESTBuilder.GET = function(url, data) {
377
+ var builder = new RESTBuilder(url);
378
+ builder.options.query = data;
379
+ return builder;
380
+ };
381
+
382
+ RESTBuilder.API = function(url, name, data) {
383
+ var builder = new RESTBuilder(url);
384
+ builder.operation = name;
385
+ builder.options.method = 'POST';
386
+ builder.raw(data, 'raw');
387
+ return builder;
388
+ };
389
+
390
+ RESTBuilder.POST = function(url, data) {
391
+ var builder = new RESTBuilder(url);
392
+ builder.options.method = 'POST';
393
+ data && builder.raw(data, 'json');
394
+ return builder;
395
+ };
396
+
397
+ RESTBuilder.PUT = function(url, data) {
398
+ var builder = new RESTBuilder(url);
399
+ builder.options.method = 'PUT';
400
+ data && builder.raw(data, 'json');
401
+ return builder;
402
+ };
403
+
404
+ RESTBuilder.DELETE = function(url, data) {
405
+ var builder = new RESTBuilder(url);
406
+ builder.$method = 'delete';
407
+ builder.options.method = 'DELETE';
408
+ data && builder.raw(data, 'json');
409
+ return builder;
410
+ };
411
+
412
+ RESTBuilder.PATCH = function(url, data) {
413
+ var builder = new RESTBuilder(url);
414
+ builder.$method = 'patch';
415
+ builder.options.method = 'PATCH';
416
+ data && builder.raw(data, 'json');
417
+ return builder;
418
+ };
419
+
420
+ RESTBuilder.HEAD = function(url) {
421
+ var builder = new RESTBuilder(url);
422
+ builder.options.method = 'HEAD';
423
+ return builder;
424
+ };
425
+
426
+ RESTBuilder.upgrade = function(fn) {
427
+ restbuilderupgrades.push(fn);
428
+ };
429
+
430
+ var RESTP = RESTBuilder.prototype;
431
+
432
+ RESTP.insecure = function() {
433
+ this.options.insecure = true;
434
+ return this;
435
+ };
436
+
437
+ RESTP.error = function(err) {
438
+ this.$errorhandler = err;
439
+ return this;
440
+ };
441
+
442
+ RESTP.noparse = function() {
443
+ this.$noparse = true;
444
+ return this;
445
+ };
446
+
447
+ RESTP.debug = function() {
448
+ this.$debug = true;
449
+ return this;
450
+ };
451
+
452
+ RESTP.unixsocket = function(socket, path) {
453
+ var self = this;
454
+ self.options.unixsocket = { socket: socket, path: path };
455
+ return self;
456
+ };
457
+
458
+ RESTP.promise = function($) {
459
+ var self = this;
460
+ return new Promise(function(resolve, reject) {
461
+ self.exec(function(err, response) {
462
+ if (err) {
463
+ if ($ && $.invalid)
464
+ $.invalid(err);
465
+ else
466
+ reject(err);
467
+ } else
468
+ resolve(response);
469
+ });
470
+ });
471
+ };
472
+
473
+ RESTP.proxy = function(value) {
474
+ this.options.proxy = value;
475
+ return this;
476
+ };
477
+
478
+ RESTP.url = function(url) {
479
+ if (url === undefined)
480
+ return this.options.url;
481
+ this.options.url = url;
482
+ return this;
483
+ };
484
+
485
+ RESTP.cert = function(key, cert, dhparam) {
486
+ this.options.key = key;
487
+ this.options.cert = cert;
488
+ this.options.dhparam = dhparam;
489
+ return this;
490
+ };
491
+
492
+ RESTP.file = function(name, filename, buffer) {
493
+
494
+ var self = this;
495
+ var obj = { name: name, filename: filename };
496
+
497
+ if (buffer) {
498
+ if (typeof(buffer) === 'string') {
499
+ if (buffer.isURL())
500
+ obj.url = buffer;
501
+ else
502
+ obj.path = buffer;
503
+ } else
504
+ obj.buffer = buffer;
505
+ }
506
+
507
+ if (self.options.files)
508
+ self.options.files.push(obj);
509
+ else
510
+ self.options.files = [obj];
511
+
512
+ return self;
513
+ };
514
+
515
+ RESTP.timeout = function(number) {
516
+ this.options.timeout = number;
517
+ return this;
518
+ };
519
+
520
+ RESTP.maxlength = function(number) {
521
+ this.options.limit = number;
522
+ return this;
523
+ };
524
+
525
+ RESTP.auth = function(user, password) {
526
+ this.options.headers.authorization = password == null ? user : 'Basic ' + Buffer.from(user + ':' + password).toString('base64');
527
+ return this;
528
+ };
529
+
530
+ RESTP.convert = function(convert) {
531
+ this.$convert = convert;
532
+ return this;
533
+ };
534
+
535
+ RESTP.nodnscache = function() {
536
+ this.options.resolve = false;
537
+ return this;
538
+ };
539
+
540
+ RESTP.nocache = function() {
541
+ this.$nocache = true;
542
+ return this;
543
+ };
544
+
545
+ RESTP.make = function(fn) {
546
+ fn.call(this, this);
547
+ return this;
548
+ };
549
+
550
+ RESTP.xhr = function() {
551
+ this.options.xhr = true;
552
+ return this;
553
+ };
554
+
555
+ RESTP.method = function(method, data) {
556
+ this.options.method = method.charCodeAt(0) > 96 ? method.toUpperCase() : method;
557
+ data && this.raw(data, 'json');
558
+ return this;
559
+ };
560
+
561
+ RESTP.referer = RESTP.referrer = function(value) {
562
+ this.options.headers.Referer = value;
563
+ return this;
564
+ };
565
+
566
+ RESTP.origin = function(value) {
567
+ this.options.headers.Origin = value;
568
+ return this;
569
+ };
570
+
571
+ RESTP.robot = function() {
572
+ if (this.options.headers['User-Agent'])
573
+ this.options.headers['User-Agent'] += ' Bot';
574
+ else
575
+ this.options.headers['User-Agent'] = 'Bot';
576
+ return this;
577
+ };
578
+
579
+ RESTP.mobile = function() {
580
+ if (this.options.headers['User-Agent'])
581
+ this.options.headers['User-Agent'] += ' iPhone';
582
+ else
583
+ this.options.headers['User-Agent'] = 'iPhone';
584
+ return this;
585
+ };
586
+
587
+ RESTP.put = RESTP.PUT = function(data) {
588
+ this.options.method = 'PUT';
589
+ data && this.raw(data, this.options.type || 'json');
590
+ return this;
591
+ };
592
+
593
+ RESTP.delete = RESTP.DELETE = function(data) {
594
+ this.options.method = 'DELETE';
595
+ data && this.raw(data, this.options.type || 'json');
596
+ return this;
597
+ };
598
+
599
+ RESTP.get = RESTP.GET = function(data) {
600
+ this.options.method = 'GET';
601
+ this.options.query = data;
602
+ return this;
603
+ };
604
+
605
+ RESTP.post = RESTP.POST = function(data) {
606
+ this.options.method = 'POST';
607
+ data && this.raw(data, this.options.type || 'json');
608
+ return this;
609
+ };
610
+
611
+ RESTP.head = RESTP.HEAD = function() {
612
+ this.options.method = 'HEAD';
613
+ return this;
614
+ };
615
+
616
+ RESTP.patch = RESTP.PATCH = function(data) {
617
+ this.options.method = 'PATCH';
618
+ data && this.raw(data, this.options.type || 'json');
619
+ return this;
620
+ };
621
+
622
+ RESTP.json = function(data) {
623
+ data && this.raw(data, 'json');
624
+ if (this.options.method === 'GET')
625
+ this.options.method = 'POST';
626
+ return this;
627
+ };
628
+
629
+ RESTP.urlencoded = function(data) {
630
+ if (this.options.method === 'GET')
631
+ this.options.method = 'POST';
632
+ this.options.type = 'urlencoded';
633
+ data && this.raw(data, this.options.type);
634
+ return this;
635
+ };
636
+
637
+ RESTP.accept = function(ext) {
638
+ var type;
639
+ if (ext.length > 8)
640
+ type = ext;
641
+ else
642
+ type = F.TUtils.contentTypes[ext];
643
+ this.options.headers.Accept = type;
644
+ return this;
645
+ };
646
+
647
+ RESTP.xml = function(data, replace) {
648
+
649
+ if (this.options.method === 'GET')
650
+ this.options.method = 'POST';
651
+
652
+ if (replace)
653
+ this.$replace = true;
654
+
655
+ this.options.type = 'xml';
656
+ data && this.raw(data, this.options.type);
657
+ return this;
658
+ };
659
+
660
+ RESTP.redirect = function(value) {
661
+ this.options.noredirect = !value;
662
+ return this;
663
+ };
664
+
665
+ RESTP.raw = function(value, type) {
666
+ this.options.type = type;
667
+ this.options.body = value;
668
+ return this;
669
+ };
670
+
671
+ RESTP.text = RESTP.plain = function(val) {
672
+ this.$plain = true;
673
+ this.options.body = val;
674
+ this.options.type = 'plain';
675
+ return this;
676
+ };
677
+
678
+ RESTP.cook = function(value) {
679
+ this.options.cook = value !== false;
680
+ return this;
681
+ };
682
+
683
+ RESTP.cookies = function(obj) {
684
+ this.options.cookies = obj;
685
+ return this;
686
+ };
687
+
688
+ RESTP.cookie = function(name, value) {
689
+ if (!this.options.cookies)
690
+ this.options.cookies = {};
691
+ this.options.cookies[name] = value;
692
+ return this;
693
+ };
694
+
695
+ RESTP.header = function(name, value) {
696
+ this.options.headers[name] = value;
697
+ return this;
698
+ };
699
+
700
+ RESTP.type = function(value) {
701
+ this.options.headers['Content-Type'] = value;
702
+ return this;
703
+ };
704
+
705
+ function execrestbuilder(instance, callback) {
706
+ instance.exec(callback);
707
+ }
708
+
709
+ RESTP.callback = function(fn) {
710
+
711
+ var self = this;
712
+
713
+ if (typeof(fn) === 'function') {
714
+ setImmediate(execrestbuilder, self, fn);
715
+ return self;
716
+ }
717
+
718
+ self.$ = fn;
719
+ setImmediate(execrestbuilder, self);
720
+ return new Promise(function(resolve, reject) {
721
+ self.$resolve = resolve;
722
+ self.$reject = reject;
723
+ });
724
+ };
725
+
726
+ RESTP.csrf = function(value) {
727
+ this.options.headers['X-Csrf-Token'] = value;
728
+ return this;
729
+ };
730
+
731
+ RESTP.encrypt = function(key) {
732
+ this.options.encrypt = key || DEF.secret_encryption;
733
+ return this;
734
+ };
735
+
736
+ RESTP.compress = function(val) {
737
+ this.$compress = val == null || val == true;
738
+ return this;
739
+ };
740
+
741
+ RESTP.cache = function(expire) {
742
+ this.$expire = expire;
743
+ return this;
744
+ };
745
+
746
+ RESTP.set = function(name, value) {
747
+ if (!this.options.body)
748
+ this.options.body = {};
749
+ if (typeof(name) !== 'object') {
750
+ this.options.body[name] = value;
751
+ } else {
752
+ for (var key in name)
753
+ this.options.body[key] = name[key];
754
+ }
755
+ return this;
756
+ };
757
+
758
+ RESTP.rem = function(name) {
759
+ if (this.options.body && this.options.body[name])
760
+ this.options.body[name] = undefined;
761
+ return this;
762
+ };
763
+
764
+ RESTP.progress = function(fn) {
765
+ this.options.onprogress = fn;
766
+ return this;
767
+ };
768
+
769
+ RESTP.stream = function(callback) {
770
+ var self = this;
771
+ self.options.custom = true;
772
+ setImmediate(streamresponse, self, callback);
773
+ return self;
774
+ };
775
+
776
+ function streamresponse(builder, callback) {
777
+ builder.exec(callback);
778
+ }
779
+
780
+ RESTP.keepalive = function() {
781
+ this.options.keepalive = true;
782
+ return this;
783
+ };
784
+
785
+ RESTP.exec = function(callback) {
786
+
787
+ if (!callback)
788
+ callback = NOOP;
789
+
790
+ var self = this;
791
+
792
+ if (self.operation) {
793
+
794
+ // API
795
+ if (self.options.body)
796
+ self.options.body = { data: self.options.body };
797
+ else
798
+ self.options.body = {};
799
+
800
+ if (self.options.query) {
801
+ self.options.body.query = self.options.query;
802
+ self.options.query = null;
803
+ }
804
+
805
+ self.options.body.schema = self.operation;
806
+ self.options.body = JSON.stringify(self.options.body, self.$compress ? exports.json2replacer : null);
807
+ self.options.type = 'json';
808
+ }
809
+
810
+ if (self.options.files && self.options.method === 'GET')
811
+ self.options.method = 'POST';
812
+
813
+ if (self.options.body && !self.options.files && typeof(self.options.body) !== 'string' && self.options.type !== 'raw')
814
+ self.options.body = self.options.type === 'urlencoded' ? F.TUtils.toURLEncode(self.options.body) : JSON.stringify(self.options.body);
815
+
816
+ if (self.options.unixsocket && self.options.url) {
817
+ if (!self.options.path)
818
+ self.options.path = self.options.url;
819
+ self.options.url = undefined;
820
+ }
821
+
822
+ self.$callback = callback;
823
+
824
+ if (restbuilderupgrades.length) {
825
+ for (var i = 0; i < restbuilderupgrades.length; i++)
826
+ restbuilderupgrades[i](self);
827
+ }
828
+
829
+ var key;
830
+
831
+ if (self.$expire && !self.$nocache) {
832
+ key = 'restbuilder' + ((self.options.url || '') + (self.options.socketpath || '') + (self.options.path || '') + (self.options.body || '')).hash(true);
833
+ var data = F.cache.read(key);
834
+ if (data) {
835
+ data = data.value;
836
+ if (self.$resolve) {
837
+ self.$resolve(data);
838
+ self.$reject = null;
839
+ self.$resolve = null;
840
+ } else
841
+ callback(null, data, data);
842
+ return self;
843
+ }
844
+ }
845
+
846
+ self.$cachekey = key;
847
+ self.options.callback = restbuilder_callback;
848
+ self.options.response = {};
849
+ self.options.response.builder = self;
850
+ self.request = F.TUtils.request(self.options);
851
+ return self;
852
+ };
853
+
854
+ function restbuilder_callback(err, response) {
855
+
856
+ var self = response.builder;
857
+
858
+ if (self.options.custom) {
859
+ if (self.$resolve) {
860
+ if (err)
861
+ self.$.invalid(err);
862
+ else
863
+ self.$resolve(response);
864
+ self.$ = null;
865
+ self.$reject = null;
866
+ self.$resolve = null;
867
+ } else
868
+ self.$callback.call(self, err, response);
869
+ return;
870
+ }
871
+
872
+ var callback = self.$callback;
873
+ var key = self.$cachekey;
874
+ var type = err ? '' : response.headers['content-type'] || '';
875
+ var output = new RESTBuilderResponse();
876
+
877
+ if (self.options.cook && self.options.cookies)
878
+ output.cookies = self.options.cookies;
879
+
880
+ if (type) {
881
+ var index = type.lastIndexOf(';');
882
+ if (index !== -1)
883
+ type = type.substring(0, index).trim();
884
+ }
885
+
886
+ var ishead = response.status === 204;
887
+ if (ishead) {
888
+ output.value = response.status < 400;
889
+ } else if (self.$plain || self.$noparse) {
890
+ output.value = response.body;
891
+ } else {
892
+ switch (type.toLowerCase()) {
893
+ case 'text/xml':
894
+ case 'application/xml':
895
+ output.value = response.body ? response.body.parseXML(self.$replace ? true : false) : {};
896
+ break;
897
+ case 'application/x-www-form-urlencoded':
898
+ output.value = response.body ? DEF.parsers.urlencoded(response.body) : {};
899
+ break;
900
+ case 'application/json':
901
+ case 'text/json':
902
+ output.value = response.body ? response.body.parseJSON(true) : null;
903
+ break;
904
+ default:
905
+ output.value = response.body && response.body.isJSON() ? response.body.parseJSON(true) : null;
906
+ break;
907
+ }
908
+ }
909
+
910
+ if (output.value == null)
911
+ output.value = EMPTYOBJECT;
912
+
913
+ output.response = response.body;
914
+ output.status = response.status;
915
+ output.headers = response.headers;
916
+ output.hostname = response.host;
917
+ output.origin = response.origin;
918
+ output.cache = false;
919
+
920
+ if (self.$debug)
921
+ console.log('--DEBUG-- RESTBuilder: ' + response.status + ' ' + self.options.method + ' ' + QUERIFY(self.options.url || (self.options.unixsocket + self.options.path), self.options.query), '|', 'Error:', err, '|', 'Response:', response.body);
922
+
923
+ var val = output.value;
924
+
925
+ if (!err && output.status >= 400) {
926
+ err = output.status;
927
+ if (val instanceof Array && val.length && val[0] && val[0].error)
928
+ err = ErrorBuilder.assign(val);
929
+ else
930
+ err = null;
931
+ }
932
+
933
+ if (!err && key)
934
+ F.cache.add(key, output, self.$expire);
935
+
936
+ if (self.$errorbuilderhandler) {
937
+ // Is the response Total.js ErrorBuilder?
938
+ if (val instanceof Array && val.length && val[0] && val[0].error) {
939
+ err = ErrorBuilder.assign(val);
940
+ if (err)
941
+ val = null;
942
+ }
943
+ }
944
+
945
+ if (!err && output.status >= 400)
946
+ err = output.status;
947
+
948
+ if (!err && self.$jsonschema && val) {
949
+ let jsresponse = $jsonschema.transform(val);
950
+ if (jsresponse.error)
951
+ err = jsresponse.error;
952
+ else
953
+ val = jsresponse.response;
954
+ }
955
+
956
+ if (self.$resolve) {
957
+
958
+ if (err)
959
+ self.$.invalid(err);
960
+ else
961
+ self.$resolve(val);
962
+
963
+ self.$ = null;
964
+ self.$reject = null;
965
+ self.$resolve = null;
966
+
967
+ } else {
968
+ callback(err, val, output);
969
+ output.cache = true;
970
+ }
971
+
972
+ }
973
+
974
+ function RESTBuilderResponse() {}
975
+
976
+ RESTBuilderResponse.prototype.cookie = function(name) {
977
+
978
+ var self = this;
979
+ if (self.cookies)
980
+ return F.TUtils.decodeURIComponent(self.cookies[name] || '');
981
+
982
+ self.cookies = {};
983
+
984
+ var cookies = self.headers['set-cookie'];
985
+ if (!cookies)
986
+ return '';
987
+
988
+ if (typeof(cookies) === 'string')
989
+ cookies = [cookies];
990
+
991
+ for (var i = 0; i < cookies.length; i++) {
992
+ var line = cookies[i].split(';', 1)[0];
993
+ var index = line.indexOf('=');
994
+ if (index !== -1)
995
+ self.cookies[line.substring(0, index)] = line.substring(index + 1);
996
+ }
997
+
998
+ return F.TUtils.decodeURIComponent(self.cookies[name] || '');
999
+ };
1000
+
1001
+ function parseactioncache(obj, meta) {
1002
+
1003
+ var query = meta.query;
1004
+ var user = meta.user;
1005
+ var params = meta.params;
1006
+ var language = meta.language;
1007
+ var search = meta.id || meta.key;
1008
+
1009
+ if (typeof(user) === 'string')
1010
+ user = user.split(',').trim();
1011
+ else if (user === true)
1012
+ user = ['id'];
1013
+ else
1014
+ user = null;
1015
+
1016
+ if (typeof(params) === 'string')
1017
+ params = params.split(',').trim();
1018
+ else if (params === true) {
1019
+ if (obj.jsparams) {
1020
+ params = [];
1021
+ for (var key in obj.jsparams.properties)
1022
+ params.push(key);
1023
+ } else
1024
+ params = null;
1025
+ } else
1026
+ params = null;
1027
+
1028
+ if (typeof(query) === 'string')
1029
+ query = query.split(',').trim();
1030
+ else if (query === true) {
1031
+ if (obj.jsquery) {
1032
+ query = [];
1033
+ for (var key in obj.jsquery.properties)
1034
+ query.push(key);
1035
+ } else
1036
+ query = null;
1037
+ } else
1038
+ query = null;
1039
+
1040
+ return function($, value) {
1041
+ if (value === undefined) {
1042
+
1043
+ var key = 'action|' + (search ? (search + '|') : '') + $.ID;
1044
+ var sum = '';
1045
+ var tmp;
1046
+
1047
+ if (language)
1048
+ sum += ($.language || '');
1049
+
1050
+ if (query) {
1051
+ for (let key of query) {
1052
+ tmp = $.query[key];
1053
+ if (tmp)
1054
+ sum += '|' + tmp;
1055
+ }
1056
+ }
1057
+
1058
+ if (params) {
1059
+ for (let key of params) {
1060
+ tmp = $.params[key];
1061
+ if (tmp)
1062
+ sum += '|' + tmp;
1063
+ }
1064
+ }
1065
+
1066
+ if (user && $.user) {
1067
+ for (let key of user) {
1068
+ tmp = $.user[key];
1069
+ if (tmp)
1070
+ sum += '|' + tmp;
1071
+ }
1072
+ }
1073
+
1074
+ $.cachekey = key + sum;
1075
+ return F.cache.read($.cachekey);
1076
+ }
1077
+
1078
+ $.cachekey && F.cache.set($.cachekey, value && value.success ? CLONE(value) : value, meta.expire || '5 minutes');
1079
+ };
1080
+
1081
+ }
1082
+
1083
+ exports.newaction = function(name, obj) {
1084
+
1085
+ if (typeof(name) === 'object') {
1086
+ obj = name;
1087
+ name = obj.id || obj.name;
1088
+ }
1089
+
1090
+ var url = name;
1091
+ var tmp = name.split('/').trim();
1092
+ if (tmp.length)
1093
+ obj.$url = url.replace(/\//g, '_').toLowerCase();
1094
+
1095
+ if (F.actions[name])
1096
+ F.actions[name].remove();
1097
+
1098
+ F.actions[name] = obj;
1099
+ obj.id = name;
1100
+ obj.jsinput = obj.input ? F.TUtils.jsonschema(obj.input, true) : null;
1101
+ obj.jsoutput = obj.output ? F.TUtils.jsonschema(obj.output, true) : null;
1102
+ obj.jsparams = obj.params ? F.TUtils.jsonschema(obj.params, true) : null;
1103
+ obj.jsquery = obj.query ? F.TUtils.jsonschema(obj.query, true) : null;
1104
+ obj.options = {};
1105
+ obj.options.csrf = obj.csrf;
1106
+ obj.options.encrypt = obj.encrypt;
1107
+ obj.options.compress = obj.compress;
1108
+
1109
+ if (obj.cache)
1110
+ obj.cache = parseactioncache(obj, obj.cache);
1111
+
1112
+ if (obj.middleware)
1113
+ obj.middleware = obj.middleware.replace(/,/g, ' ').replace(/\s{2,}/, ' ');
1114
+
1115
+ obj.remove = function() {
1116
+ obj.route && obj.route.remove();
1117
+ delete F.actions[obj.id];
1118
+ obj = null;
1119
+ F.makesourcemap && F.makesourcemap();
1120
+ };
1121
+
1122
+ if (obj.route) {
1123
+ if (obj.route.indexOf('-->') === -1)
1124
+ obj.route = obj.route + ' ' + (obj.input ? '+' : '-') + obj.$url + ' * --> ' + name;
1125
+ var flags = null;
1126
+ if (obj.encrypt)
1127
+ flags = '@encrypt';
1128
+ obj.route = F.route(obj.route, flags || []);
1129
+ }
1130
+
1131
+ if (obj.permissions && typeof(obj.permissions) === 'string')
1132
+ obj.permissions = obj.permissions.split(/,|;/).trim();
1133
+
1134
+ if (obj.publish) {
1135
+
1136
+ var tmsschema = obj.publish == true ? (obj.input || obj.output) : obj.publish;
1137
+
1138
+ if (typeof(tmsschema) === 'string') {
1139
+ if (tmsschema[0] === '+')
1140
+ tmsschema = (obj.input || obj.output) + ',' + tmsschema.substring(1);
1141
+
1142
+ var keys = tmsschema.split(',');
1143
+ obj.$publish = [];
1144
+ for (var key of keys) {
1145
+ var index = key.indexOf(':');
1146
+ obj.$publish.push(index === -1 ? key : key.substring(0, index));
1147
+ }
1148
+ }
1149
+
1150
+ F.TMS.newpublish(name, tmsschema);
1151
+ }
1152
+
1153
+ F.makesourcemap && F.makesourcemap();
1154
+ return obj;
1155
+ };
1156
+
1157
+ function ActionCaller() {
1158
+ var self = this;
1159
+ self.$ = new Options();
1160
+ self.error = new ErrorBuilder();
1161
+ self.options = {};
1162
+ self.actions = [];
1163
+ setImmediate(self => self.exec(), self);
1164
+ }
1165
+
1166
+ ActionCaller.prototype.debug = function() {
1167
+ this.options.debug = true;
1168
+ return this;
1169
+ };
1170
+
1171
+ ActionCaller.prototype.params = function(value) {
1172
+ this.options.params = value;
1173
+ return this;
1174
+ };
1175
+
1176
+ ActionCaller.prototype.exec = function() {
1177
+
1178
+ var self = this;
1179
+ var id = self.actions.shift();
1180
+
1181
+ if (!id) {
1182
+ self.finish && self.finish();
1183
+ self.error = null;
1184
+ self.options = null;
1185
+ self.$ = null;
1186
+ return;
1187
+ }
1188
+
1189
+ var meta = F.temporary.actions[id];
1190
+ if (!meta) {
1191
+
1192
+ let arr = id.split(' ');
1193
+
1194
+ meta = {};
1195
+ meta.response = arr[1] ? true : false;
1196
+ meta.id = arr[0];
1197
+ meta.payload = null;
1198
+
1199
+ let c = meta.id[0];
1200
+ if (c === '+' || c === '-' || c === '%') {
1201
+ // + payload
1202
+ // - without payload
1203
+ // % partial payload
1204
+ meta.payload = c;
1205
+ meta.id = meta.id.substring(1);
1206
+ }
1207
+
1208
+ F.temporary.actions[id] = meta;
1209
+ }
1210
+
1211
+ var action = F.actions[meta.id];
1212
+
1213
+ if (!action) {
1214
+ self.error.push('The action "{0}" not found'.format(meta.id));
1215
+ self.cancel();
1216
+ return;
1217
+ }
1218
+
1219
+ var type = meta.payload || (action.input ? '+' : '-');
1220
+ var $ = self.$;
1221
+
1222
+ $.id = id;
1223
+ $.error = self.error;
1224
+ $.controller = self.controller;
1225
+ $.fields = action.fields;
1226
+ $.user = self.options.user;
1227
+
1228
+ $.$callback = function(err, response) {
1229
+ if (err) {
1230
+ // close
1231
+ self.cancel();
1232
+ } else {
1233
+ $.response[$.id] = response;
1234
+ meta.response && self.finish && self.finish(response);
1235
+ self.exec();
1236
+ }
1237
+ };
1238
+
1239
+ if (action.user && !$.user) {
1240
+ $.invalid(401);
1241
+ return;
1242
+ }
1243
+
1244
+ if (action.sa) {
1245
+ if (!$.user || (!$.user.sa && !$.user.su)) {
1246
+ $.invalid(401);
1247
+ return;
1248
+ }
1249
+ }
1250
+
1251
+ if (action.permissions) {
1252
+ let permissions = action.permissions.slice(0);
1253
+ permissions.unshift($);
1254
+ if (F.unauthorized.apply(global, permissions)) {
1255
+ self.finish = null;
1256
+ self.cancel();
1257
+ return;
1258
+ }
1259
+ }
1260
+
1261
+ var params = self.options.params || EMPTYOBJECT;
1262
+ var query = self.options.query || EMPTYOBJECT;
1263
+ var payload = self.options.payload || EMPTYOBJECT;
1264
+ var response = null;
1265
+
1266
+ if (action.jsquery) {
1267
+ self.error.prefix = 'query.';
1268
+ response = action.jsquery.transform(query, false, self.error);
1269
+ self.error.prefix = '';
1270
+ if (response.error) {
1271
+ self.cancel();
1272
+ return;
1273
+ }
1274
+ $.query = response.response;
1275
+ }
1276
+
1277
+ if (action.jsparams) {
1278
+ self.error.prefix = 'params.';
1279
+ response = action.jsparams.transform(params, false, self.error);
1280
+ self.error.prefix = '';
1281
+ if (response.error) {
1282
+ self.cancel();
1283
+ return;
1284
+ }
1285
+ $.params = response.response;
1286
+ }
1287
+
1288
+ if (action.jsinput && type !== '-') {
1289
+ response = action.jsinput.transform(payload, type === '%', self.error);
1290
+ if (response.error) {
1291
+ self.cancel();
1292
+ return;
1293
+ }
1294
+ $.payload = response.response;
1295
+ }
1296
+
1297
+ action.action($, $.payload);
1298
+ };
1299
+
1300
+ ActionCaller.prototype.finish = function(value) {
1301
+ var self = this;
1302
+ self.finish = null;
1303
+ self.options.callback(self.error.length ? self.error : null, value === undefined ? self.$.response : value);
1304
+ self.options.callback = null;
1305
+ };
1306
+
1307
+ ActionCaller.prototype.cancel = function() {
1308
+ var self = this;
1309
+ self.actions.length = 0;
1310
+ self.exec();
1311
+ };
1312
+
1313
+ ActionCaller.prototype.payload = function(value) {
1314
+ this.options.payload = value;
1315
+ return this;
1316
+ };
1317
+
1318
+ ActionCaller.prototype.query = function(value) {
1319
+ this.options.query = value;
1320
+ return this;
1321
+ };
1322
+
1323
+ ActionCaller.prototype.user = function(value) {
1324
+
1325
+ if (value instanceof Options)
1326
+ value = value.user;
1327
+
1328
+ this.options.user = value;
1329
+ return this;
1330
+ };
1331
+
1332
+ ActionCaller.prototype.language = function(value) {
1333
+ this.options.language = value;
1334
+ return this;
1335
+ };
1336
+
1337
+ ActionCaller.prototype.error = function(value) {
1338
+ this.options.error = value;
1339
+ return this;
1340
+ };
1341
+
1342
+ ActionCaller.prototype.done = function($, fn) {
1343
+ this.options.callback = function(err, response) {
1344
+ if (err)
1345
+ $.invalid(err);
1346
+ else
1347
+ fn(response);
1348
+ };
1349
+ return this;
1350
+ };
1351
+
1352
+ ActionCaller.prototype.callback = function(value) {
1353
+ this.options.callback = value;
1354
+ return this;
1355
+ };
1356
+
1357
+ ActionCaller.prototype.promise = function($) {
1358
+ var self = this;
1359
+ return new Promise(function(resolve, reject) {
1360
+ self.options.callback = function(err, response) {
1361
+ if (err) {
1362
+ self.options.error && self.options.error(err);
1363
+ if ($ && $.invalid)
1364
+ $.invalid(err);
1365
+ else
1366
+ reject(err);
1367
+ } else
1368
+ resolve(response);
1369
+ };
1370
+ });
1371
+ };
1372
+
1373
+ ActionCaller.prototype.autorespond = function() {
1374
+ var self = this;
1375
+ self.options.callback = function(err, response) {
1376
+ if (err)
1377
+ self.controller.invalid(err);
1378
+ else
1379
+ self.controller.json(response);
1380
+ };
1381
+ return self;
1382
+ };
1383
+
1384
+ ActionCaller.prototype.controller = function(ctrl) {
1385
+
1386
+ if (ctrl instanceof Options)
1387
+ ctrl = ctrl.controller;
1388
+
1389
+ this.options.controller = ctrl;
1390
+ return this;
1391
+ };
1392
+
1393
+ exports.action = function(name, payload, controller) {
1394
+
1395
+ var key = '$' + name;
1396
+ var actions = F.temporary.actions[key];
1397
+
1398
+ if (!actions) {
1399
+ actions = name.replace(/(\s)?\(response\)/i, '\0').split(/\s|\,|\n/);
1400
+ let isresponse = false;
1401
+ for (let i = 0; i < actions.length; i++) {
1402
+ actions[i] = actions[i].replaceAll('\0', ' (response)');
1403
+ if (actions[i].indexOf('(') !== -1)
1404
+ isresponse = true;
1405
+ }
1406
+
1407
+ if (actions.length === 1 && !isresponse)
1408
+ actions[0] += ' (response)';
1409
+ F.temporary.actions[key] = actions;
1410
+ }
1411
+
1412
+ var action = new ActionCaller();
1413
+ action.controller = controller;
1414
+ action.payload = payload;
1415
+ action.actions = actions.slice(0);
1416
+ action.options.payload = payload;
1417
+ action.options.user = controller?.user;
1418
+ action.options.query = controller?.query;
1419
+ action.options.params = controller?.params;
1420
+ return action;
1421
+ };
1422
+
1423
+ exports.newschema = function(name, callback) {
1424
+ var $ = {};
1425
+ $.name = name;
1426
+ $.actions = {};
1427
+ $.action = function(aname, meta) {
1428
+ return $.actions[aname] = F.newaction(name + '/' + aname, meta);
1429
+ };
1430
+ callback($);
1431
+ };
1432
+
1433
+ exports.RESTBuilder = RESTBuilder;
1434
+ exports.ErrorBuilder = ErrorBuilder;
1435
+ exports.Options = Options;