total5 0.0.15 → 0.0.16-10

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/aimodel.js ADDED
@@ -0,0 +1,143 @@
1
+ // AI
2
+ // The MIT License
3
+ // Copyright 2026 (c) Peter Širka <petersirka@gmail.com>
4
+
5
+ function AI(model) {
6
+ const t = this;
7
+
8
+ t.options = {};
9
+ t.options.callback = NOOP;
10
+ t.config = {};
11
+
12
+ t.payload = {};
13
+ t.payload.model = model;
14
+ t.payload.messages = [];
15
+ }
16
+
17
+ // Enables think mode
18
+ AI.prototype.think = function () {
19
+ const t = this;
20
+ t.payload.think = true;
21
+ return t;
22
+ };
23
+
24
+ // Internal function
25
+ // Appends content message
26
+ AI.prototype.message = function(role, content, merge) {
27
+
28
+ const t = this;
29
+
30
+ if (merge) {
31
+ for (let m of t.payload.messages) {
32
+ if (m.role === role) {
33
+
34
+ if (typeof(content) === 'object') {
35
+ for (let key in content)
36
+ m[key] = content[key];
37
+ } else
38
+ m.content += merge + content;
39
+
40
+ return this;
41
+ }
42
+ }
43
+ }
44
+
45
+ const msg = { role: role };
46
+
47
+ if (typeof(content) === 'object') {
48
+ for (let key in content)
49
+ msg[key] = content[key];
50
+ } else
51
+ msg.content = content;
52
+
53
+ t.payload.messages.push(msg);
54
+ return t;
55
+ };
56
+
57
+ AI.prototype.configure = function(opt) {
58
+ const t = this;
59
+ for (let key in opt)
60
+ t.config[key] = opt[key];
61
+ return t;
62
+ };
63
+
64
+ AI.prototype.system = function(content, merge) {
65
+ return this.message('system', content, merge);
66
+ };
67
+
68
+ AI.prototype.user = function(content, merge) {
69
+ return this.message('user', content, merge);
70
+ };
71
+
72
+ AI.prototype.prompt = function(content) {
73
+ this.payload.prompt = content;
74
+ return this;
75
+ };
76
+
77
+ AI.prototype.assistant = function(content, merge) {
78
+ return this.message('assistant', content, merge);
79
+ };
80
+
81
+ AI.prototype.promise = function($) {
82
+ const t = this;
83
+ return new Promise(function(resolve, reject) {
84
+ t.callback(function(err, response) {
85
+ if (err) {
86
+ if ($ && $.invalid)
87
+ $.invalid(err);
88
+ else
89
+ reject(F.TUtils.toError(err));
90
+ } else
91
+ resolve(response);
92
+ });
93
+ });
94
+ };
95
+
96
+ AI.prototype.stream = function(fn) {
97
+ const t = this;
98
+ t.options.stream = fn;
99
+ t.options.$running && clearImmediate(t.options.$running);
100
+ t.options.$running = setImmediate(() => t.run());
101
+ return t;
102
+ };
103
+
104
+ AI.prototype.callback = function(fn) {
105
+ const t = this;
106
+ t.options.callback = fn;
107
+ t.options.$running && clearImmediate(t.options.$running);
108
+ t.options.$running = setImmediate(() => t.run());
109
+ return t;
110
+ };
111
+
112
+ // Internal function
113
+ AI.prototype.run = function() {
114
+ const t = this;
115
+ let ai = F.aimodels[t.payload.model];
116
+ if (ai) {
117
+ if (ai.config) {
118
+ for (let key in ai.config) {
119
+ if (t.config[key] === undefined)
120
+ t.config[key] = ai.config[key];
121
+ }
122
+ }
123
+ ai.callback(t, t.options.callback);
124
+ } else
125
+ t.options.callback('AI model not found.');
126
+ return t;
127
+ };
128
+
129
+ exports.exec = function(model) {
130
+ return new AI(model);
131
+ };
132
+
133
+ exports.newai = function(model, config, callback) {
134
+
135
+ if (typeof(config) === 'function') {
136
+ callback = config;
137
+ config = null;
138
+ }
139
+
140
+ const models = model.split(/,/).trim();
141
+ for (const m of models)
142
+ F.aimodels[m] = { config, callback };
143
+ };
package/api.js CHANGED
@@ -10,17 +10,29 @@ const REG_TEXT = /^text\/(html|plain|xml)/;
10
10
  var cache = {};
11
11
 
12
12
  // Registers a new API type
13
- exports.newapi = function(type, callback) {
13
+ exports.newapi = function(type, config, callback) {
14
14
 
15
- if (typeof(type) === 'function') {
15
+ let t = typeof(type);
16
+
17
+ if (t === 'function') {
16
18
  callback = type;
17
19
  type = 'default';
20
+ config = null;
21
+ } else if (t === 'object') {
22
+ callback = config;
23
+ config = type;
24
+ type = 'default';
25
+ }
26
+
27
+ if (typeof(config) === 'function') {
28
+ callback = config;
29
+ config = null;
18
30
  }
19
31
 
20
32
  if (type.indexOf(',') !== -1) {
21
33
  var arr = type.split(',').trim();
22
34
  for (var m of arr)
23
- exports.newapi(m, callback);
35
+ exports.newapi(m, config, callback);
24
36
  return;
25
37
  }
26
38
 
@@ -30,15 +42,17 @@ exports.newapi = function(type, callback) {
30
42
  cache[lower] = lower;
31
43
 
32
44
  if (callback)
33
- F.apiservices[lower] = callback;
45
+ F.apiservices[lower] = { config, callback };
34
46
  else
35
47
  delete F.apiservices[lower];
36
48
 
37
49
  };
38
50
 
39
51
  function APIOptions(api) {
40
- this.api = api;
41
- this.retries = 0;
52
+ const t = this;
53
+ t.api = api;
54
+ t.retries = 0;
55
+ t.config = {};
42
56
  }
43
57
 
44
58
  APIOptions.prototype.retry = function() {
@@ -58,8 +72,8 @@ APICallProto.output = function(type) {
58
72
  };
59
73
 
60
74
  APICallProto.promise = function($) {
61
- var t = this;
62
- var promise = new Promise(function(resolve, reject) {
75
+ const t = this;
76
+ const promise = new Promise(function(resolve, reject) {
63
77
  t.$callback = function(err, response) {
64
78
  if (err) {
65
79
  if ($ && $.invalid) {
@@ -75,7 +89,7 @@ APICallProto.promise = function($) {
75
89
  };
76
90
 
77
91
  APICallProto.audit = function($, message, type) {
78
- var t = this;
92
+ const t = this;
79
93
  t.$audit = function() {
80
94
  // Dynamic arguments
81
95
  if (message)
@@ -85,8 +99,15 @@ APICallProto.audit = function($, message, type) {
85
99
  return t;
86
100
  };
87
101
 
102
+ APICallProto.configure = function(opt) {
103
+ const t = this;
104
+ for (let key in opt)
105
+ t.options.config[key] = opt[key];
106
+ return t;
107
+ };
108
+
88
109
  APICallProto.done = function($, callback) {
89
- var t = this;
110
+ const t = this;
90
111
  t.$callback = function(err, response) {
91
112
  if (err)
92
113
  $.invalid(err);
@@ -119,12 +140,12 @@ APICallProto.controller = function($) {
119
140
 
120
141
  APICallProto.file = function(filename, path, name) {
121
142
 
122
- var t = this;
143
+ const t = this;
123
144
 
124
145
  if (!t.options.files)
125
146
  t.options.files = [];
126
147
 
127
- var obj = { name: name || ('file' + t.options.files.length), filename: filename, path: path };
148
+ const obj = { name: name || ('file' + t.options.files.length), filename: filename, path: path };
128
149
 
129
150
  if (t.options.files)
130
151
  t.options.files.push(obj);
@@ -140,15 +161,20 @@ APICallProto.error = APICallProto.err = function(err, reverse) {
140
161
  return this;
141
162
  };
142
163
 
164
+ APICallProto.logerror = function() {
165
+ this.$loggerror = true;
166
+ return this;
167
+ };
168
+
143
169
  APICallProto.callback = APICallProto.pipe = function($) {
144
- var t = this;
170
+ const t = this;
145
171
  t.$callback = typeof($) === 'function' ? $ : $.callback();
146
172
  return t;
147
173
  };
148
174
 
149
175
  APICallProto.evaluate = function(err, response) {
150
176
 
151
- var t = this;
177
+ const t = this;
152
178
  if (!err && t.$error) {
153
179
  if (t.$error_reverse) {
154
180
  if (response)
@@ -161,6 +187,9 @@ APICallProto.evaluate = function(err, response) {
161
187
  err = t.$error;
162
188
  }
163
189
 
190
+ if (t.$logerror)
191
+ F.error(err, 'API: ' + t.options.name + ' --> ' + t.options.schema);
192
+
164
193
  if (err) {
165
194
  t.$callback_fail && t.$callback_fail(err);
166
195
  } else {
@@ -176,16 +205,24 @@ APICallProto.evaluate = function(err, response) {
176
205
  };
177
206
 
178
207
  function execapi(api) {
179
- var conn = F.apiservices[cache[api.options.name]] || F.apiservices['*'];
180
- if (conn)
181
- conn.call(api, api.options, (err, response) => api.evaluate(err, response));
182
- else
208
+ const conn = F.apiservices[cache[api.options.name]] || F.apiservices['*'];
209
+ if (conn) {
210
+
211
+ if (conn.config) {
212
+ for (let key in conn.config) {
213
+ if (api.options.config[key] === undefined)
214
+ api.options.config[key] = conn.config[key];
215
+ }
216
+ }
217
+
218
+ conn.callback.call(api, api.options, (err, response) => api.evaluate(err, response));
219
+ } else
183
220
  api.evaluate('API is not initialized');
184
221
  }
185
222
 
186
223
  // Executes API
187
224
  exports.exec = function(name, schema, data, $) {
188
- var api = new APICall();
225
+ const api = new APICall();
189
226
  api.options.name = cache[name] || name;
190
227
  api.options.schema = schema;
191
228
  api.options.data = data;
@@ -204,7 +241,7 @@ exports.newapi('TotalAPI,TAPI', function(opt, next) {
204
241
  if (opt.data && typeof(opt.data) !== 'object')
205
242
  opt.data = { value: opt.data };
206
243
 
207
- var req = {};
244
+ const req = {};
208
245
 
209
246
  req.method = 'POST';
210
247
  req.url = 'https://' + F.config.$tapiurl + '.api.totaljs.com/' + opt.schema + '/';
@@ -218,7 +255,7 @@ exports.newapi('TotalAPI,TAPI', function(opt, next) {
218
255
  req.type = 'json';
219
256
  req.timeout = 60000;
220
257
  req.keepalive = true;
221
- req.headers = { 'x-token': opt.token || F.config.totalapi || F.config.secret_totalapi || F.config.$tapisecret || '-', 'x-app': encodeURIComponent(F.config.name) };
258
+ req.headers = { 'x-token': opt.token || opt.config.token || F.config.totalapi || F.config.secret_totalapi || F.config.$tapisecret || '-', 'x-app': encodeURIComponent(F.config.name) };
222
259
  req.custom = true;
223
260
 
224
261
  req.callback = function(err, response) {
@@ -228,7 +265,7 @@ exports.newapi('TotalAPI,TAPI', function(opt, next) {
228
265
  return;
229
266
  }
230
267
 
231
- var buffer = [];
268
+ const buffer = [];
232
269
 
233
270
  // Error
234
271
  if (response.status > 200) {
@@ -248,7 +285,8 @@ exports.newapi('TotalAPI,TAPI', function(opt, next) {
248
285
  if (opt.output === 'base64') {
249
286
  output = output.toString('base64');
250
287
  } else if (opt.output !== 'binary' && opt.output !== 'buffer') {
251
- var type = response.headers['content-type'];
288
+
289
+ const type = response.headers['content-type'];
252
290
 
253
291
  if (REG_BINARY.test(type)) {
254
292
  next(null, output);
@@ -284,20 +322,20 @@ exports.newapi('TotalAPI,TAPI', function(opt, next) {
284
322
  }
285
323
 
286
324
  var type = (response.headers['content-type'] || '').toLowerCase();
287
- var index = type.lastIndexOf(';');
325
+ const index = type.lastIndexOf(';');
288
326
  if (index !== -1)
289
327
  type = type.substring(0, index);
290
328
 
291
- var ext = type ? F.TUtils.getExtensionFromContentType(type) : 'bin';
292
- var id = fsdata[1] || UID();
293
- var filename = fsdata[2] || id + '.' + ext;
329
+ const ext = type ? F.TUtils.getExtensionFromContentType(type) : 'bin';
330
+ const id = fsdata[1] || UID();
331
+ const filename = fsdata[2] || id + '.' + ext;
294
332
 
295
333
  response.stream.pause();
296
334
  fs.save(id, filename, response.stream, next);
297
335
  return;
298
336
  }
299
337
 
300
- var writer = F.Fs.createWriteStream(opt.output);
338
+ const writer = F.Fs.createWriteStream(opt.output);
301
339
  response.stream.pipe(writer);
302
340
  F.cleanup(writer, () => opt.next(null, opt.output));
303
341
  };
package/builders.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // Total.js Builders
2
2
  // The MIT License
3
- // Copyright 2023 (c) Peter Širka <petersirka@gmail.com>
3
+ // Copyright 2023-2026 (c) Peter Širka <petersirka@gmail.com>
4
4
 
5
5
  'use strict';
6
6
 
@@ -153,7 +153,13 @@ Options.prototype.promisify = function(fn, a, b, c) {
153
153
  });
154
154
  };
155
155
 
156
- Options.prototype.status = function() {};
156
+ Options.prototype.status = function(a, b, c, d) {
157
+ this.status2?.call(this, a, b, c, d);
158
+ };
159
+
160
+ Options.prototype.progress = function(a, b, c, d) {
161
+ this.progress2?.call(this, a, b, c, d);
162
+ };
157
163
 
158
164
  Options.prototype.publish = function(value) {
159
165
  var self = this;
@@ -241,7 +247,7 @@ Options.prototype.successful = function(callback) {
241
247
  };
242
248
  };
243
249
 
244
- Options.prototype.callback = Options.prototype.pipe = function(value) {
250
+ Options.prototype.callback = Options.prototype.output = Options.prototype.pipe = function(value) {
245
251
 
246
252
  var self = this;
247
253
 
@@ -252,7 +258,7 @@ Options.prototype.callback = Options.prototype.pipe = function(value) {
252
258
  };
253
259
  }
254
260
 
255
- self.$callback(self.error.items.length ? self.error : null, value);
261
+ self.$callback.call(self, self.error.items.length ? self.error : null, value);
256
262
  };
257
263
 
258
264
  Options.prototype.done = function(arg) {
@@ -382,9 +388,10 @@ ErrorBuilder.prototype.push = function(err, path, index) {
382
388
  return self;
383
389
  };
384
390
 
385
- ErrorBuilder.prototype.push2 = function(name, path, index) {
391
+ ErrorBuilder.prototype.push2 = function(name, path, index, error) {
386
392
  let self = this;
387
- self.items.push({ name: self.prefix + name, error: '@', path: path, index: index });
393
+
394
+ self.items.push({ name: self.prefix + name, error: error || '@', path: path, index: index });
388
395
 
389
396
  if (self.$throw) {
390
397
  let errors = self.output();
@@ -563,7 +570,12 @@ RESTP.insecure = function() {
563
570
  };
564
571
 
565
572
  RESTP.error = function(err) {
566
- this.$errorhandler = err;
573
+ this.$errormessage = err;
574
+ return this;
575
+ };
576
+
577
+ RESTP.logerror = function() {
578
+ this.$loggerror = true;
567
579
  return this;
568
580
  };
569
581
 
@@ -904,7 +916,7 @@ RESTP.exec = function(callback) {
904
916
  if (!callback)
905
917
  callback = NOOP;
906
918
 
907
- var self = this;
919
+ let self = this;
908
920
 
909
921
  if (self.operation) {
910
922
 
@@ -939,15 +951,15 @@ RESTP.exec = function(callback) {
939
951
  self.$callback = callback;
940
952
 
941
953
  if (restbuilderupgrades.length) {
942
- for (var i = 0; i < restbuilderupgrades.length; i++)
954
+ for (let i = 0; i < restbuilderupgrades.length; i++)
943
955
  restbuilderupgrades[i](self);
944
956
  }
945
957
 
946
- var key;
958
+ let key;
947
959
 
948
960
  if (self.$expire && !self.$nocache) {
949
961
  key = 'restbuilder' + ((self.options.url || '') + (self.options.socketpath || '') + (self.options.path || '') + (self.options.body || '')).hash(true);
950
- var data = F.cache.read(key);
962
+ let data = F.cache.read(key);
951
963
  if (data) {
952
964
  data = data.value;
953
965
  if (self.$resolve) {
@@ -1053,7 +1065,7 @@ function restbuilder_callback(err, response) {
1053
1065
  if (val instanceof Array && val.length && val[0] && val[0].error)
1054
1066
  err = ErrorBuilder.assign(val);
1055
1067
  else
1056
- err = null;
1068
+ err = (new ErrorBuilder()).push2(output.status, undefined, undefined, response.body);
1057
1069
  }
1058
1070
 
1059
1071
  if (!err && key)
@@ -1079,6 +1091,12 @@ function restbuilder_callback(err, response) {
1079
1091
  val = jsresponse.response;
1080
1092
  }
1081
1093
 
1094
+ if (err && self.$loggerror)
1095
+ F.error(new Error(response.body || err.toString()), 'RESTBuilder', self.options.method + ' ' + (self.options.url || self.options.path));
1096
+
1097
+ if (self.$errormessage && err)
1098
+ err = self.$errormessage;
1099
+
1082
1100
  if (self.$resolve) {
1083
1101
 
1084
1102
  if (err) {
@@ -1336,6 +1354,11 @@ ActionCaller.prototype.status = function(fn) {
1336
1354
  return this;
1337
1355
  };
1338
1356
 
1357
+ ActionCaller.prototype.progress = function(fn) {
1358
+ this.options.progress = fn;
1359
+ return this;
1360
+ };
1361
+
1339
1362
  ActionCaller.prototype.exec = function() {
1340
1363
 
1341
1364
  let self = this;
@@ -1382,6 +1405,8 @@ ActionCaller.prototype.exec = function() {
1382
1405
  let type = meta.payload || (action.input ? '+' : '-');
1383
1406
  let $ = self.$;
1384
1407
 
1408
+ $.$end = false;
1409
+ $.name = action.name;
1385
1410
  $.id = action.id;
1386
1411
  $.error = self.error;
1387
1412
  $.controller = self.controller;
@@ -1392,9 +1417,19 @@ ActionCaller.prototype.exec = function() {
1392
1417
 
1393
1418
  $.$callback = function(err, response) {
1394
1419
 
1420
+ if ($.$end)
1421
+ return;
1422
+
1423
+ $.$end = true;
1424
+
1425
+ if ($.$timeout) {
1426
+ clearTimeout($.$timeout);
1427
+ $.$timeout = null;
1428
+ }
1429
+
1395
1430
  if (!err) {
1396
1431
  if (action.jsoutput)
1397
- response = action.jsoutput.transform(response).response;
1432
+ response = action.jsoutput.transform(response).response || {};
1398
1433
 
1399
1434
  if (action.extend) {
1400
1435
  if (action.extend.includes('.'))
@@ -1458,7 +1493,7 @@ ActionCaller.prototype.exec = function() {
1458
1493
  self.cancel();
1459
1494
  return;
1460
1495
  }
1461
- $.query = response.response;
1496
+ $.query = response.response || {};
1462
1497
  } else
1463
1498
  $.query = query;
1464
1499
 
@@ -1470,7 +1505,7 @@ ActionCaller.prototype.exec = function() {
1470
1505
  self.cancel();
1471
1506
  return;
1472
1507
  }
1473
- $.params = response.response;
1508
+ $.params = response.response || {};
1474
1509
  } else
1475
1510
  $.params = params;
1476
1511
 
@@ -1480,12 +1515,21 @@ ActionCaller.prototype.exec = function() {
1480
1515
  self.cancel();
1481
1516
  return;
1482
1517
  }
1483
- $.payload = response.response;
1518
+ $.payload = response.response || {};
1484
1519
  } else
1485
1520
  $.payload = payload;
1486
1521
 
1487
1522
  if (self.options.status)
1488
- $.status = self.options.status;
1523
+ $.status2 = self.options.status;
1524
+
1525
+ if (self.options.progress)
1526
+ $.progress2 = self.options.progress;
1527
+
1528
+ if (action.timeout) {
1529
+ $.$timeout = setTimeout(function() {
1530
+ $.invalid('Timeout.');
1531
+ }, action.timeout);
1532
+ }
1489
1533
 
1490
1534
  if (action.middleware) {
1491
1535
  action.middleware.wait(function(name, next) {
@@ -1511,9 +1555,9 @@ ActionCaller.prototype.finish = function(value) {
1511
1555
  if (self.error.length)
1512
1556
  $.invalid(self.error);
1513
1557
  else
1514
- $.callback(value === undefined ? self.$.response : value);
1558
+ $.callback.call($, value === undefined ? self.$.response : value);
1515
1559
  } else
1516
- self.options.callback(self.error.length ? self.error : null, value === undefined ? self.$.response : value);
1560
+ self.options.callback.call(self.$, self.error.length ? self.error : null, value === undefined ? self.$.response : value);
1517
1561
 
1518
1562
  self.options.callback = null;
1519
1563
  }
package/changelog.txt CHANGED
@@ -1,3 +1,36 @@
1
+ ========================
2
+ 0.0.16
3
+ ========================
4
+
5
+ - improved loading plugins
6
+ - framework reads a `/config` file in `plugins`
7
+ - added `RESTBuilder.?.logerror()` method for printing errors into the console
8
+ - added `API.?.logerror()` method for printing errors into the console
9
+ - fixed handling of unexpected problems in the Flow with the main process becoming disconnected
10
+ - fixed `uptime` value in the framework stats
11
+ - improved auditlogs by adding `files`
12
+ - fixed unexpected errors when compressing/decompressing data via WebSocket
13
+ - fixed processing TMS data in the FlowStream
14
+ - added a new config key `CONF.$httpcacheoffset` for extending `last-modified` header
15
+ - exended `Total.download()` by adding `size {Number}` property to the response
16
+ - extended FlowStream by adding the ability to execute Total.js actions
17
+ - added a new global event `ON('flowstream', function(instance) {`
18
+ - added new action methods `$.progress(percentage)` and `ACTION().progress(console.log)` to measure percentage
19
+ - fixed Total error handling
20
+ - improved compiling navigation in the CMS compiler
21
+ - fixed filling of the `template` property in the CMS compiler
22
+ - added a new method `U.aistreamer(on_line, on_message)`
23
+ - added `Flow.edit(proxy_socket_url)` method for the remote editing of the FlowStream
24
+ - added a new global methods `AIMODEL()` and `NEWAIMODEL()`
25
+ - added `exec` command to the remote editing functionality
26
+ - always set `cwd` directory for the current executed script
27
+ - added `timeout {Number}` property into the `NEWACTION` method
28
+ - extended `NEWAPI(type, [config], config)` by adding the `config` argument
29
+ - replaced `Url.parse()` with `new URL()`
30
+ - fixed `NEWFORK()` method
31
+ - fixed callback with `$` in the `ACTION().callback($)`
32
+ - fixed returing a default JSON schema object in actions
33
+
1
34
  ========================
2
35
  0.0.15
3
36
  ========================
package/cms.js CHANGED
@@ -548,6 +548,7 @@ exports.compile = function(html, widgets, used) {
548
548
  opt.html = body.substring(body.lastIndexOf('~BEG~') + 5, body.lastIndexOf('~END~'));
549
549
  opt.config = config || EMPTYOBJECT;
550
550
  opt.render = widget.render;
551
+ opt.template = widget.ui ? widget.ui.template : '';
551
552
  opt.beg = opt.body.substring(0, opt.body.indexOf('>') + 1);
552
553
  opt.end = opt.body.substring(opt.body.lastIndexOf('<'));
553
554
 
@@ -575,14 +576,30 @@ exports.compile = function(html, widgets, used) {
575
576
  let endindex = html.indexOf('</script>', index);
576
577
  let endhead = html.indexOf('>', index);
577
578
  let head = html.substring(begindex, endhead);
578
- let name = head.match(/name=".*?"/i)[0];
579
+ let uid = head.match(/id=".*?"/i);
579
580
  let template = html.substring(html.indexOf('>', endhead) + 1, endindex);
581
+ let name = '';
580
582
 
581
- name = name.substring(6, name.length - 1);
582
- html = html.replace(html.substring(begindex, endindex + 9), '~WIDGET#' + response.tangular.length + '~');
583
- response.tangular.push({ id: HASH(name).toString(36), name: name, type: 'nav', template: Tangular.compile(template) });
584
- index = begindex;
583
+ if (uid && uid[0]) {
584
+ uid = uid[0];
585
+ uid = uid.substring(4, uid.length - 1);
586
+ name = uid.capitalize();
587
+ } else {
588
+ uid = head.match(/name=".*?"/i);
589
+ if (uid && uid[0]) {
590
+ uid = uid[0];
591
+ uid = uid.substring(6, uid.length - 1);
592
+ name = uid.capitalize();
593
+ uid = HASH(uid).toString(36); // Backward compatibility with old CMS
594
+ }
595
+ }
596
+
597
+ if (name) {
598
+ html = html.replace(html.substring(begindex, endindex + 9), '~WIDGET#' + response.tangular.length + '~');
599
+ response.tangular.push({ id: uid, name: name, type: 'nav', template: Tangular.compile(template) });
600
+ }
585
601
 
602
+ index = begindex;
586
603
  }
587
604
 
588
605
  index = 0;
package/controller.js CHANGED
@@ -115,7 +115,7 @@ function Controller(req, res) {
115
115
  Controller.prototype = {
116
116
 
117
117
  get query() {
118
- return this.$query || (this.$query = ctrl.uri.search.parseEncoded());
118
+ return this.$query || (this.$query = this.uri.search.parseEncoded());
119
119
  },
120
120
 
121
121
  set query(val) {
@@ -1617,7 +1617,7 @@ function send_file(ctrl, path, ext) {
1617
1617
  ctrl.response.headers['cache-control'] = NOCACHE;
1618
1618
 
1619
1619
  if (!cache)
1620
- cache = { date: stats.mtime.toUTCString(), size: stats.size };
1620
+ cache = { date: (CONF.$httpcacheoffset ? stats.mtime.add(CONF.$httpcacheoffset) : stats.mtime).toUTCString(), size: stats.size };
1621
1621
 
1622
1622
  ctrl.response.headers['last-modified'] = cache.date;
1623
1623
  ctrl.response.headers.etag = '858' + F.config.$httpetag;
package/debug.js CHANGED
@@ -75,6 +75,7 @@ function runwatching() {
75
75
  const REG_PUBLIC = /\/public\//i;
76
76
  const REG_INDEX = new RegExp(FILENAME.replace(/\.js$/, '') + '_.*?\\.js$');
77
77
  const REG_EXTENSION = /\.(js|ts|py|resource|package|bundle|build|flow|url|html)$/i;
78
+ const REG_CONFIG = /\/config$/
78
79
  const REG_RELOAD = /\.(js|ts|py|css|html|htm|jpg|png|gif|ico|svg|webp|resource)$/i;
79
80
  const isRELOAD = !!options.livereload;
80
81
  const SPEED = isRELOAD ? 1000 : 1500;
@@ -105,7 +106,6 @@ function runwatching() {
105
106
  skipbundle = true;
106
107
  F.directory = directory = F.path.join(directory, '.src');
107
108
  }
108
-
109
109
  } catch(e) {}
110
110
 
111
111
  const fork = F.Child.fork;
@@ -210,7 +210,7 @@ function runwatching() {
210
210
  if (isdir)
211
211
  return true;
212
212
 
213
- if (!REG_PUBLIC.test(path) && REG_EXTENSION.test(path))
213
+ if (!REG_PUBLIC.test(path) && (REG_CONFIG.test(path) || REG_EXTENSION.test(path)))
214
214
  return true;
215
215
 
216
216
  return false;