mm_os 4.1.3 → 4.1.5

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 (2) hide show
  1. package/com/db/drive.js +96 -92
  2. package/package.json +1 -1
package/com/db/drive.js CHANGED
@@ -18,20 +18,20 @@ var keyword_default_tip = '昵称、手机号、钱包地址';
18
18
  class Drive extends Item {
19
19
  static config = {
20
20
  // 库表名称(唯一标识)
21
- 'name': 'db',
21
+ name: '',
22
22
  // 标题(中文名)
23
- 'title': '',
23
+ title: '',
24
24
  // 表名
25
- 'table': '',
25
+ table: '',
26
26
  // 主键,用于实体模型
27
- 'key': '',
27
+ key: '',
28
28
  // 字段
29
- 'fields': [
29
+ fields: [
30
30
  /* */
31
31
  ],
32
- 'index‌': [],
32
+ index: [],
33
33
  // 主程序文件 - 默认为空
34
- 'main': ''
34
+ main: ''
35
35
  };
36
36
 
37
37
  /**
@@ -48,7 +48,7 @@ class Drive extends Item {
48
48
  /**
49
49
  * 重置配置参数
50
50
  */
51
- Drive.prototype._reset = function () {
51
+ Drive.prototype._preset = function () {
52
52
  this.query_string = ['name', 'title', 'keywords', 'tag', 'description', 'content'];
53
53
 
54
54
  // 是否设置数值类型为可查询
@@ -61,7 +61,7 @@ Drive.prototype._reset = function () {
61
61
  this.get_not = ['password', 'salt', 'content'];
62
62
 
63
63
  // 是否设置以下字段为getObj查对象SQL时不可见
64
- this.getobj_not = ['password', 'salt', 'display'];
64
+ this.get_obj_not = ['password', 'salt', 'display'];
65
65
 
66
66
  // 是否设置默认该表仅用户可访问
67
67
  this.query_default_table = ['user'];
@@ -78,10 +78,10 @@ Drive.prototype._parseFieldType = function (type) {
78
78
  var max = 0;
79
79
  var decimal = 0;
80
80
  if (len) {
81
- max = number(len.left(',', true));
81
+ max = Number(len.left(',', true));
82
82
  var d = len.right(',');
83
83
  if (d) {
84
- decimal = number(d);
84
+ decimal = Number(d);
85
85
  }
86
86
  }
87
87
  return { tp, max, decimal };
@@ -110,11 +110,11 @@ Drive.prototype._parseFieldNote = function (note, tp, max_length) {
110
110
  if (range) {
111
111
  var min_str = range.left(',', true);
112
112
  if (min_str) {
113
- min = number(min_str);
113
+ min = Number(min_str);
114
114
  }
115
115
  var max_str = range.right(',');
116
116
  if (max_str) {
117
- var n = number(max_str);
117
+ var n = Number(max_str);
118
118
  if (tp === 'varchar') {
119
119
  if (n < local_max_length) {
120
120
  local_max_length = n;
@@ -126,8 +126,11 @@ Drive.prototype._parseFieldNote = function (note, tp, max_length) {
126
126
  }
127
127
  map = desc.between('(', ')');
128
128
  }
129
-
130
- return { title, description, map, min, max, max_length: local_max_length };
129
+ let min_length = 0;
130
+ if (min > 0) {
131
+ min_length = min;
132
+ }
133
+ return { title, description, map, min, max, min_length, max_length: local_max_length };
131
134
  };
132
135
 
133
136
  /**
@@ -137,7 +140,7 @@ Drive.prototype._parseFieldNote = function (note, tp, max_length) {
137
140
  * @param {number} max_length 最大长度
138
141
  * @returns {number} 计算后的最大值
139
142
  */
140
- Drive.prototype._calculateMaxValue = function (tp, max, max_length) {
143
+ Drive.prototype._calcMaxValue = function (tp, max, max_length) {
141
144
  var local_max = max;
142
145
  if (local_max === 0) {
143
146
  switch (tp) {
@@ -275,6 +278,7 @@ Drive.prototype.model = function (fields) {
275
278
  map,
276
279
  min,
277
280
  max: parsedMax,
281
+ min_length,
278
282
  max_length: parsedMaxLength
279
283
  } = this._parseFieldNote(note, tp, max_length);
280
284
 
@@ -309,12 +313,12 @@ Drive.prototype.model = function (fields) {
309
313
  * @property {string} o.Manager_comment 索引备注
310
314
  * @returns {object} 返回索引模型
311
315
  */
312
- Drive.prototype.modelmanager = function (o) {
316
+ Drive.prototype.newIndexModel = function (o) {
313
317
  return {
314
- 'name': o.Key_name,
315
- 'type': o.Non_unique ? 'unique' : 'index',
316
- 'fields': o.Column_name.replace(/`/g, '').split(','),
317
- 'comment': o.Manager_comment
318
+ name: o.Key_name,
319
+ type: o.Non_unique ? 'unique' : 'index',
320
+ fields: o.Column_name.replace(/`/g, '').split(','),
321
+ comment: o.Manager_comment
318
322
  };
319
323
  };
320
324
 
@@ -323,16 +327,16 @@ Drive.prototype.modelmanager = function (o) {
323
327
  * @param {object} db 数据库管理器
324
328
  * @returns {Array} 索引列表
325
329
  */
326
- Drive.prototype.updateFilemanager = function (db) {
330
+ Drive.prototype._updateFile = async function (db) {
327
331
  var sql = 'SHOW INDEX FROM `' + this.config.table + '`';
328
- var rows = db.run(sql);
332
+ var rows = await db.run(sql);
329
333
  var dict = {};
330
334
  for (var i = 0; i < rows.length; i++) {
331
335
  var o = rows[i];
332
336
  if (o.Key_name !== 'PRIMARY') {
333
337
  if (!dict[o.Key_name]) {
334
338
  dict[o.Key_name] = {
335
- column_name: []
339
+ Column_name: []
336
340
  };
337
341
  }
338
342
  dict[o.Key_name].Column_name.push(o.Column_name);
@@ -340,7 +344,7 @@ Drive.prototype.updateFilemanager = function (db) {
340
344
  }
341
345
  var list = [];
342
346
  for (var k in dict) {
343
- var m = this.modelmanager(dict[k]);
347
+ var m = this.newIndexModel(dict[k]);
344
348
  list.push(m);
345
349
  }
346
350
 
@@ -381,7 +385,7 @@ Drive.prototype.updateFile = async function (db, cover) {
381
385
  list.push(field);
382
386
  }
383
387
  cg.fields = list;
384
- cg.index = await this.updateFilemanager(db);
388
+ cg.index = await this._updateFile(db);
385
389
  if (!cg.name) {
386
390
  cg.name = cg.table;
387
391
  }
@@ -392,14 +396,14 @@ Drive.prototype.updateFile = async function (db, cover) {
392
396
  * 更新索引
393
397
  * @param {object} db 数据库管理器
394
398
  */
395
- Drive.prototype.updateDbmanager = async function (db) {
399
+ Drive.prototype._updateDb = async function (db) {
396
400
  var cg = this.config;
397
401
  let index = cg.index || [];
398
402
  // 更新索引
399
403
  if (index) {
400
404
  var len = index.length;
401
405
  for (var i = 0; i < len; i++) {
402
- var o = index[i];
406
+ var o = index[i];
403
407
  var sql_start = '';
404
408
  if (o.type === 'unique') {
405
409
  sql_start = 'CREATE UNIQUE INDEX `';
@@ -470,7 +474,6 @@ Drive.prototype._generateFieldSql = function (o) {
470
474
  var notnull = this._getNotNullSql(o);
471
475
  var value = this._getValueSql(o);
472
476
  var note = this._getNoteSql(o);
473
-
474
477
  return this._buildFieldSql(o.name, type, notnull, value, note);
475
478
  };
476
479
 
@@ -715,8 +718,7 @@ Drive.prototype._addOrUpdateField = async function (db, table, o, fields) {
715
718
  */
716
719
  Drive.prototype.updateDb = async function (db) {
717
720
  var cg = this.config;
718
- db.table = cg.table + '';
719
- var table = cg.table;
721
+ var table = cg.table + '';
720
722
  var list = cg.fields;
721
723
 
722
724
  var fields = await this._initTable(db, cg, list);
@@ -742,14 +744,14 @@ Drive.prototype.updateDb = async function (db) {
742
744
  * @returns {object} 目录信息
743
745
  * @private
744
746
  */
745
- Drive.prototype._deteDire = function (cg) {
747
+ Drive.prototype._deteDir = function (cg) {
748
+ var arr = cg.table.split('_');
749
+ var scope = arr[0];
746
750
  var p = './app/'.fullname();
747
- var dir_arr = cg.table.split('_');
748
- var scope = dir_arr[0];
749
- var dir = p + scope;
750
- var dir_api = dir + '/plugin/server';
751
- var db_dir = dir_api + '/db';
752
- var config_file = db_dir.fullname() + cg.table.replace(scope + '_', '') + '.db.json';
751
+ var dir = ('./' + scope).fullname(p);
752
+ var dir_api = ('./plugin/server').fullname(dir);
753
+ var db_dir = ('./db').fullname(dir_api);
754
+ var config_file = ('./' + cg.table.replace(scope + '_', '') + '.db.json').fullname(db_dir);
753
755
 
754
756
  return {
755
757
  scope,
@@ -790,7 +792,7 @@ Drive.prototype._handleConfigFile = function (f, cover) {
790
792
  delete o.description;
791
793
  }
792
794
  $.push(jobj, o, true);
793
- f.saveText(JSON.stringify(jobj, null, 4));
795
+ f.saveJson(jobj);
794
796
  }
795
797
  };
796
798
 
@@ -804,33 +806,31 @@ Drive.prototype.updateApp = async function (cover) {
804
806
  var dir_api;
805
807
 
806
808
  if (!this.config_file) {
807
- var dirs = this._deteDire(cg);
808
-
809
+ var dirs = this._deteDir(cg);
809
810
  this._ensureDir(dirs.dir);
810
811
  this._ensureDir(dirs.dir + '/plugin');
811
812
  this._ensureDir(dirs.dir_api);
812
813
  this._ensureDir(dirs.db_dir);
813
-
814
- this.dir = dirs.db_dir.fullname();
814
+ this._dir = dirs.db_dir;
815
815
  this.config_file = dirs.config_file;
816
816
  f = dirs.config_file;
817
817
  dir_api = dirs.dir_api;
818
818
  } else {
819
- f = this.config_file + '.db.json';
819
+ if (this.config_file.endsWith('.db.json')) {
820
+ f = this.config_file;
821
+ } else {
822
+ f = this.config_file + '.db.json';
823
+ }
820
824
  }
821
825
 
822
826
  if (f) {
823
- if (!this.dir) {
824
- this.dir = f.dirname();
825
- if (!fs.existsSync(this.dir)) {
826
- fs.mkdirSync(this.dir);
827
- }
828
- }
827
+ f.addDir();
829
828
  if (!dir_api) {
830
- dir_api = this.dir.dirname();
829
+ dir_api = f.dirname().dirname();
831
830
  }
832
-
831
+ // 处理db配置文件,生成xxx.db.json文件
833
832
  this._handleConfigFile(f, cover);
833
+ // 更新API及相关配置文件
834
834
  this.updateApi(dir_api, cover);
835
835
  }
836
836
  };
@@ -855,9 +855,10 @@ Drive.prototype._ensureApiDir = function (dir) {
855
855
  * @returns {string} 完整目录路径
856
856
  * @private
857
857
  */
858
- Drive.prototype._deteApiDir = function (dir, app, type, name) {
858
+ Drive.prototype._getApiDir = function (dir, app, type, name) {
859
859
  var l = $.slash;
860
- var o = $.pool.api[app + '_' + type];
860
+ let event_api = $.admin.event('api');
861
+ var o = event_api.getMod(app + '_' + type);
861
862
  var api_dir;
862
863
 
863
864
  if (o) {
@@ -888,10 +889,10 @@ Drive.prototype.updateApi = async function (dir, cover) {
888
889
  }
889
890
  var app = arr[0];
890
891
 
891
- var client = this._deteApiDir(dir, app, 'client', name);
892
- var manage = this._deteApiDir(dir, app, 'manage', name);
892
+ var client = this._getApiDir(dir, app, 'client', name);
893
+ var manage = this._getApiDir(dir, app, 'manage', name);
893
894
 
894
- this.newSql(client, manage, cover);
895
+ await this.newSql(client, manage, cover);
895
896
  await this.newParam(client, manage, cover);
896
897
  this.newApi(client, manage, cover);
897
898
  };
@@ -1050,10 +1051,9 @@ Drive.prototype._procFieldSel = function (field_name, field_type) {
1050
1051
  if (this.isCan(field_name, this.get_not, field_type)) {
1051
1052
  res.field += ',`' + field_name + '`';
1052
1053
  }
1053
- if (this.isCan(field_name, this.getObj_not)) {
1054
+ if (this.isCan(field_name, this.get_obj_not)) {
1054
1055
  res.field_obj += ',`' + field_name + '`';
1055
1056
  }
1056
-
1057
1057
  return res;
1058
1058
  };
1059
1059
 
@@ -1104,7 +1104,7 @@ Drive.prototype._procNumberQuery = function (
1104
1104
  update: { ...update_obj }
1105
1105
  };
1106
1106
 
1107
- if (!field_name.end('id')) {
1107
+ if (!field_name.endsWith('id')) {
1108
1108
  query[field_name + '_min'] = '`' + field_name + '` >= {0}';
1109
1109
  query[field_name + '_max'] = '`' + field_name + '` <= {0}';
1110
1110
  res.update[field_name + '_add'] = '`' + field_name + '` = `' + field_name + '` + {0}';
@@ -1164,7 +1164,7 @@ Drive.prototype._procFieldType = function (
1164
1164
 
1165
1165
  /**
1166
1166
  * 处理单个字段
1167
- * @param {object} field 字段对象
1167
+ * @param {object} o 字段对象
1168
1168
  * @param {object} query 查询对象
1169
1169
  * @param {object} update_obj 更新对象
1170
1170
  * @param {string} uid 用户ID
@@ -1175,14 +1175,12 @@ Drive.prototype._procFieldType = function (
1175
1175
  * @private
1176
1176
  */
1177
1177
  Drive.prototype._procSingleField = async function (
1178
- field, query, update_obj, uid, query_default_user, orderby, keyword
1178
+ o, query, update_obj, uid, query_default_user, orderby, keyword
1179
1179
  ) {
1180
- var o = field;
1181
- var p = o.type;
1182
- var n = o.name;
1180
+ var { type, name } = o;
1183
1181
  var result = {
1184
- field: '',
1185
- field_obj: '',
1182
+ field: '*',
1183
+ field_obj: '*',
1186
1184
  keyword: keyword,
1187
1185
  orderby: orderby,
1188
1186
  update_obj: update_obj,
@@ -1190,12 +1188,12 @@ Drive.prototype._procSingleField = async function (
1190
1188
  format: []
1191
1189
  };
1192
1190
 
1193
- var field_sel = this._procFieldSel(n, p);
1191
+ var field_sel = this._procFieldSel(name, type);
1194
1192
  result.field = field_sel.field;
1195
1193
  result.field_obj = field_sel.field_obj;
1196
1194
 
1197
1195
  var type_info = this._procFieldType(
1198
- p, n, query, update_obj, uid, query_default_user, orderby, keyword
1196
+ type, name, query, update_obj, uid, query_default_user, orderby, keyword
1199
1197
  );
1200
1198
  result.keyword = type_info.keyword;
1201
1199
  result.orderby = type_info.orderby;
@@ -1254,8 +1252,8 @@ Drive.prototype._procFields = async function (fields, table) {
1254
1252
  return {
1255
1253
  query,
1256
1254
  update: update_obj,
1257
- field,
1258
- field_obj,
1255
+ field: field.replace(',', ''),
1256
+ field_obj: field_obj.replace(',', ''),
1259
1257
  query_default,
1260
1258
  format,
1261
1259
  orderby,
@@ -1292,7 +1290,7 @@ Drive.prototype._procKeyword = function (keyword, table) {
1292
1290
  * @returns {object} 基础模型
1293
1291
  * @private
1294
1292
  */
1295
- Drive.prototype._createBaseModel = function (cg, processed, keyword_query) {
1293
+ Drive.prototype._createSqlConfig = function (cg, processed, keyword_query) {
1296
1294
  return {
1297
1295
  name: cg.table,
1298
1296
  title: cg.title,
@@ -1319,12 +1317,12 @@ Drive.prototype._createBaseModel = function (cg, processed, keyword_query) {
1319
1317
  * @param {boolean} cover 是否覆盖文件
1320
1318
  * @private
1321
1319
  */
1322
- Drive.prototype._saveClientConfig = function (client, base_model, orderby, uid, table, cover) {
1320
+ Drive.prototype._saveClientConfig = function (client, base_model, cover, orderby, uid, table) {
1323
1321
  var oj = { ...base_model };
1324
1322
  if (orderby) {
1325
1323
  oj.orderby_default = orderby;
1326
1324
  }
1327
- if (oj.query_default[uid] && table.indexOf('user_') !== -1) {
1325
+ if (oj.orderby_default && oj.query_default[uid] && table.indexOf('user_') !== -1) {
1328
1326
  oj.filter = {
1329
1327
  'table': 'table',
1330
1328
  'page': 'page',
@@ -1351,7 +1349,7 @@ Drive.prototype._saveManageConfig = function (manage, base_model, cover) {
1351
1349
  delete m.method;
1352
1350
  m.field_hide = [];
1353
1351
  m.name += 2;
1354
- m.field_obj = m.field_obj.replace(',`time_create`', '').replace(',`time_update`', '')
1352
+ m.field_obj = (m.field_obj || '*').replace(',`time_create`', '').replace(',`time_update`', '')
1355
1353
  .replace(',`create_time`', '').replace(',`update_time`', '');
1356
1354
  delete m.query_default;
1357
1355
  this.saveFile(manage + '/sql.json', m, cover);
@@ -1369,10 +1367,10 @@ Drive.prototype.newSql = async function (client, manage, cover) {
1369
1367
 
1370
1368
  var processed = await this._procFields(cg.fields, cg.table);
1371
1369
  var keyword_query = this._procKeyword(processed.keyword, cg.table);
1372
- var base_model = this._createBaseModel(cg, processed, keyword_query);
1370
+ var base_model = this._createSqlConfig(cg, processed, keyword_query);
1373
1371
 
1374
1372
  if (client) {
1375
- this._saveClientConfig(client, base_model, processed.orderby, uid, cg.table, cover);
1373
+ this._saveClientConfig(client, base_model, cover, processed.orderby, uid, cg.table);
1376
1374
  }
1377
1375
 
1378
1376
  if (manage) {
@@ -1388,7 +1386,7 @@ Drive.prototype.newSql = async function (client, manage, cover) {
1388
1386
  */
1389
1387
  Drive.prototype.saveFile = function (file, model, cover) {
1390
1388
  if (!file.hasFile()) {
1391
- file.saveText(JSON.stringify(model, null, 4));
1389
+ file.saveText(JSON.stringify(model, null, 2));
1392
1390
  } else if (cover) {
1393
1391
  var jobj = file.loadJson();
1394
1392
  for (var k in model) {
@@ -1398,7 +1396,7 @@ Drive.prototype.saveFile = function (file, model, cover) {
1398
1396
  }
1399
1397
  }
1400
1398
  $.push(jobj, model, true);
1401
- file.saveText(JSON.stringify(jobj, null, 4));
1399
+ file.saveText(JSON.stringify(jobj, null, 2));
1402
1400
  }
1403
1401
  };
1404
1402
 
@@ -1408,7 +1406,7 @@ Drive.prototype.saveFile = function (file, model, cover) {
1408
1406
  * @param {string} manage 管理端配置保存路径
1409
1407
  * @param {boolean} cover 是否覆盖文件
1410
1408
  */
1411
- Drive.prototype.new = async function (client, manage, cover) {
1409
+ Drive.prototype.newParam = async function (client, manage, cover) {
1412
1410
  var cg = this.config;
1413
1411
  var lt = cg.fields;
1414
1412
  var cm = this._initParamConfig(cg);
@@ -1418,7 +1416,7 @@ Drive.prototype.new = async function (client, manage, cover) {
1418
1416
  var o = lt[i];
1419
1417
  var p = o.type;
1420
1418
  var n = o.name;
1421
- var m = this._createBaseModel(o, p, n);
1419
+ var m = this._createParamModel(o, p, n);
1422
1420
 
1423
1421
  if (this._isStringType(p)) {
1424
1422
  keyword = this._processStringField(cm, m, o, n, keyword);
@@ -1470,14 +1468,14 @@ Drive.prototype._initParamConfig = function (cg) {
1470
1468
  };
1471
1469
 
1472
1470
  /**
1473
- * 创建基础模型
1471
+ * 创建参数模型
1474
1472
  * @param {object} field 字段对象
1475
1473
  * @param {string} type 字段类型
1476
1474
  * @param {string} name 字段名
1477
- * @returns {object} 基础模型对象
1475
+ * @returns {object} 参数模型对象
1478
1476
  * @private
1479
1477
  */
1480
- Drive.prototype._createBaseModel = function (field, type, name) {
1478
+ Drive.prototype._createParamModel = function (field, type, name) {
1481
1479
  return {
1482
1480
  name: name,
1483
1481
  title: field.title,
@@ -1665,7 +1663,7 @@ Drive.prototype._addDateTimeRange = function (cm, m, n) {
1665
1663
  */
1666
1664
  Drive.prototype._processNumberField = function (cm, m, o, n, cg) {
1667
1665
  m.type = 'number';
1668
- m.default = number(o.default) + '';
1666
+ m.default = Number(o.default) + '';
1669
1667
  m.number = {};
1670
1668
 
1671
1669
  this._addNumberRange(m, o);
@@ -1738,7 +1736,7 @@ Drive.prototype._processNonPrimaryKey = function (cm, m, n) {
1738
1736
  */
1739
1737
  Drive.prototype._processNonTinyInt = function (cm, m, n) {
1740
1738
  var ne = n;
1741
- if (!ne.end('id')) {
1739
+ if (!ne.endsWith('id')) {
1742
1740
  this._addNumberRangeFields(cm, m, n);
1743
1741
  } else {
1744
1742
  cm.get.query.push(n);
@@ -1826,6 +1824,9 @@ Drive.prototype._saveParamFiles = function (cm, client, manage, cover) {
1826
1824
  * @returns {boolean} 是否设置
1827
1825
  */
1828
1826
  Drive.prototype.isSet = function (name, arr) {
1827
+ if (!arr) {
1828
+ return false;
1829
+ }
1829
1830
  var bl = false;
1830
1831
  for (var i = 0; i < arr.length; i++) {
1831
1832
  if (name.indexOf(arr[i]) !== -1) {
@@ -1847,14 +1848,17 @@ Drive.prototype.isCan = function (name, arr, type) {
1847
1848
  if (type === 'longtext') {
1848
1849
  return false;
1849
1850
  }
1850
- var bl = false;
1851
+ if (!arr) {
1852
+ return true;
1853
+ }
1854
+ var bl = true;
1851
1855
  for (var i = 0; i < arr.length; i++) {
1852
1856
  if (name.indexOf(arr[i]) !== -1) {
1853
- bl = true;
1857
+ bl = false;
1854
1858
  break;
1855
1859
  }
1856
1860
  }
1857
- return !bl;
1861
+ return bl;
1858
1862
  };
1859
1863
 
1860
1864
 
@@ -1879,10 +1883,10 @@ Drive.prototype._deteApiPath = function (cg) {
1879
1883
  * 创建基础API配置
1880
1884
  * @param {object} cg 配置对象
1881
1885
  * @param {string} path API路径
1882
- * @returns {object} 基础API配置
1886
+ * @returns {object} API配置
1883
1887
  * @private
1884
1888
  */
1885
- Drive.prototype._createBaseApiConfig = function (cg, path) {
1889
+ Drive.prototype._createApiConfig = function (cg, path) {
1886
1890
  return {
1887
1891
  'name': cg.table,
1888
1892
  'title': cg.title,
@@ -1967,7 +1971,7 @@ Drive.prototype._saveManageApiConfig = function (manage, base_config, cover) {
1967
1971
  Drive.prototype.newApi = async function (client, manage, cover) {
1968
1972
  var cg = this.config;
1969
1973
  var path = this._deteApiPath(cg);
1970
- var base_config = this._createBaseApiConfig(cg, path);
1974
+ var base_config = this._createApiConfig(cg, path);
1971
1975
 
1972
1976
  if (client) {
1973
1977
  this._saveClientApiConfig(client, base_config, cg, cover);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mm_os",
3
3
  "description": "MM_OS服务端架构,用于快速构建应用程序,支持网站建设、小程序后台、AI应用、物联网(IOT/AIOT)、游戏服务端等多种场景。",
4
- "version": "4.1.3",
4
+ "version": "4.1.5",
5
5
  "main": "index.js",
6
6
  "keywords": [
7
7
  "AI",