hola-server 2.0.1 → 3.0.0

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 (242) hide show
  1. package/README.md +318 -132
  2. package/dist/config/index.d.ts +46 -0
  3. package/dist/config/index.d.ts.map +1 -0
  4. package/dist/config/index.js +55 -0
  5. package/dist/config/index.js.map +1 -0
  6. package/dist/core/array.d.ts +27 -0
  7. package/dist/core/array.d.ts.map +1 -0
  8. package/dist/core/array.js +66 -0
  9. package/dist/core/array.js.map +1 -0
  10. package/dist/core/bash.d.ts +51 -0
  11. package/dist/core/bash.d.ts.map +1 -0
  12. package/dist/core/bash.js +161 -0
  13. package/dist/core/bash.js.map +1 -0
  14. package/dist/core/chart.d.ts +11 -0
  15. package/dist/core/chart.d.ts.map +1 -0
  16. package/dist/core/chart.js +35 -0
  17. package/dist/core/chart.js.map +1 -0
  18. package/dist/core/date.d.ts +11 -0
  19. package/dist/core/date.d.ts.map +1 -0
  20. package/dist/core/date.js +18 -0
  21. package/dist/core/date.js.map +1 -0
  22. package/dist/core/encrypt.d.ts +18 -0
  23. package/dist/core/encrypt.d.ts.map +1 -0
  24. package/dist/core/encrypt.js +50 -0
  25. package/dist/core/encrypt.js.map +1 -0
  26. package/dist/core/file.d.ts +22 -0
  27. package/dist/core/file.d.ts.map +1 -0
  28. package/dist/core/file.js +21 -0
  29. package/dist/core/file.js.map +1 -0
  30. package/dist/core/lhs.d.ts +17 -0
  31. package/dist/core/lhs.d.ts.map +1 -0
  32. package/dist/core/lhs.js +30 -0
  33. package/dist/core/lhs.js.map +1 -0
  34. package/dist/core/meta.d.ts +200 -0
  35. package/dist/core/meta.d.ts.map +1 -0
  36. package/dist/core/meta.js +336 -0
  37. package/dist/core/meta.js.map +1 -0
  38. package/dist/core/number.d.ts +37 -0
  39. package/dist/core/number.d.ts.map +1 -0
  40. package/dist/core/number.js +99 -0
  41. package/dist/core/number.js.map +1 -0
  42. package/dist/core/obj.d.ts +9 -0
  43. package/dist/core/obj.d.ts.map +1 -0
  44. package/dist/core/obj.js +15 -0
  45. package/dist/core/obj.js.map +1 -0
  46. package/dist/core/random.d.ts +7 -0
  47. package/dist/core/random.d.ts.map +1 -0
  48. package/dist/core/random.js +7 -0
  49. package/dist/core/random.js.map +1 -0
  50. package/dist/core/role.d.ts +42 -0
  51. package/dist/core/role.d.ts.map +1 -0
  52. package/dist/core/role.js +81 -0
  53. package/dist/core/role.js.map +1 -0
  54. package/dist/core/thread.d.ts +7 -0
  55. package/dist/core/thread.d.ts.map +1 -0
  56. package/dist/core/thread.js +7 -0
  57. package/dist/core/thread.js.map +1 -0
  58. package/dist/core/type.d.ts +46 -0
  59. package/dist/core/type.d.ts.map +1 -0
  60. package/dist/core/type.js +281 -0
  61. package/dist/core/type.js.map +1 -0
  62. package/dist/core/url.d.ts +20 -0
  63. package/dist/core/url.d.ts.map +1 -0
  64. package/dist/core/url.js +24 -0
  65. package/dist/core/url.js.map +1 -0
  66. package/dist/core/validate.d.ts +11 -0
  67. package/dist/core/validate.d.ts.map +1 -0
  68. package/dist/core/validate.js +19 -0
  69. package/dist/core/validate.js.map +1 -0
  70. package/dist/db/db.d.ts +72 -0
  71. package/dist/db/db.d.ts.map +1 -0
  72. package/dist/db/db.js +225 -0
  73. package/dist/db/db.js.map +1 -0
  74. package/dist/db/entity.d.ts +77 -0
  75. package/dist/db/entity.d.ts.map +1 -0
  76. package/dist/db/entity.js +671 -0
  77. package/dist/db/entity.js.map +1 -0
  78. package/dist/db/gridfs.d.ts +29 -0
  79. package/dist/db/gridfs.d.ts.map +1 -0
  80. package/dist/db/gridfs.js +125 -0
  81. package/dist/db/gridfs.js.map +1 -0
  82. package/dist/db/index.d.ts +8 -0
  83. package/dist/db/index.d.ts.map +1 -0
  84. package/dist/db/index.js +8 -0
  85. package/dist/db/index.js.map +1 -0
  86. package/dist/errors/auth.d.ts +15 -0
  87. package/dist/errors/auth.d.ts.map +1 -0
  88. package/dist/errors/auth.js +21 -0
  89. package/dist/errors/auth.js.map +1 -0
  90. package/dist/errors/http.d.ts +15 -0
  91. package/dist/errors/http.d.ts.map +1 -0
  92. package/dist/errors/http.js +21 -0
  93. package/dist/errors/http.js.map +1 -0
  94. package/dist/errors/index.d.ts +18 -0
  95. package/dist/errors/index.d.ts.map +1 -0
  96. package/dist/errors/index.js +18 -0
  97. package/dist/errors/index.js.map +1 -0
  98. package/dist/errors/validation.d.ts +11 -0
  99. package/dist/errors/validation.d.ts.map +1 -0
  100. package/dist/errors/validation.js +15 -0
  101. package/dist/errors/validation.js.map +1 -0
  102. package/dist/http/code.d.ts +21 -0
  103. package/dist/http/code.d.ts.map +1 -0
  104. package/dist/http/code.js +27 -0
  105. package/dist/http/code.js.map +1 -0
  106. package/dist/index.d.ts +57 -0
  107. package/dist/index.d.ts.map +1 -0
  108. package/dist/index.js +61 -0
  109. package/dist/index.js.map +1 -0
  110. package/dist/meta/index.d.ts +9 -0
  111. package/dist/meta/index.d.ts.map +1 -0
  112. package/dist/meta/index.js +11 -0
  113. package/dist/meta/index.js.map +1 -0
  114. package/dist/meta/router.d.ts +26 -0
  115. package/dist/meta/router.d.ts.map +1 -0
  116. package/dist/meta/router.js +258 -0
  117. package/dist/meta/router.js.map +1 -0
  118. package/dist/meta/schema.d.ts +41 -0
  119. package/dist/meta/schema.d.ts.map +1 -0
  120. package/dist/meta/schema.js +69 -0
  121. package/dist/meta/schema.js.map +1 -0
  122. package/dist/plugins/auth.d.ts +248 -0
  123. package/dist/plugins/auth.d.ts.map +1 -0
  124. package/dist/plugins/auth.js +121 -0
  125. package/dist/plugins/auth.js.map +1 -0
  126. package/dist/plugins/body.d.ts +47 -0
  127. package/dist/plugins/body.d.ts.map +1 -0
  128. package/dist/plugins/body.js +36 -0
  129. package/dist/plugins/body.js.map +1 -0
  130. package/dist/plugins/cors.d.ts +62 -0
  131. package/dist/plugins/cors.d.ts.map +1 -0
  132. package/dist/plugins/cors.js +17 -0
  133. package/dist/plugins/cors.js.map +1 -0
  134. package/dist/plugins/error.d.ts +51 -0
  135. package/dist/plugins/error.d.ts.map +1 -0
  136. package/dist/plugins/error.js +51 -0
  137. package/dist/plugins/error.js.map +1 -0
  138. package/dist/plugins/index.d.ts +9 -0
  139. package/dist/plugins/index.d.ts.map +1 -0
  140. package/dist/plugins/index.js +9 -0
  141. package/dist/plugins/index.js.map +1 -0
  142. package/dist/setting.d.ts +66 -0
  143. package/dist/setting.d.ts.map +1 -0
  144. package/dist/setting.js +27 -0
  145. package/dist/setting.js.map +1 -0
  146. package/dist/tool/gen_i18n.d.ts +10 -0
  147. package/dist/tool/gen_i18n.d.ts.map +1 -0
  148. package/{tool → dist/tool}/gen_i18n.js +9 -22
  149. package/dist/tool/gen_i18n.js.map +1 -0
  150. package/dist/tool/vector_store.d.ts +72 -0
  151. package/dist/tool/vector_store.d.ts.map +1 -0
  152. package/dist/tool/vector_store.js +203 -0
  153. package/dist/tool/vector_store.js.map +1 -0
  154. package/package.json +37 -22
  155. package/core/array.js +0 -124
  156. package/core/bash.js +0 -294
  157. package/core/chart.js +0 -46
  158. package/core/cron.js +0 -21
  159. package/core/date.js +0 -26
  160. package/core/encrypt.js +0 -26
  161. package/core/file.js +0 -51
  162. package/core/lhs.js +0 -53
  163. package/core/meta.js +0 -283
  164. package/core/msg.js +0 -24
  165. package/core/number.js +0 -181
  166. package/core/obj.js +0 -25
  167. package/core/random.js +0 -12
  168. package/core/role.js +0 -108
  169. package/core/thread.js +0 -13
  170. package/core/type.js +0 -368
  171. package/core/url.js +0 -30
  172. package/core/validate.js +0 -35
  173. package/db/db.js +0 -446
  174. package/db/entity.js +0 -920
  175. package/db/gridfs.js +0 -175
  176. package/design/add_default_field_attr.md +0 -56
  177. package/http/code.js +0 -18
  178. package/http/context.js +0 -31
  179. package/http/cors.js +0 -32
  180. package/http/error.js +0 -39
  181. package/http/express.js +0 -104
  182. package/http/params.js +0 -85
  183. package/http/router.js +0 -83
  184. package/http/session.js +0 -73
  185. package/index.js +0 -112
  186. package/router/clone.js +0 -65
  187. package/router/create.js +0 -54
  188. package/router/delete.js +0 -49
  189. package/router/read.js +0 -191
  190. package/router/update.js +0 -89
  191. package/setting.js +0 -67
  192. package/skills/array.md +0 -155
  193. package/skills/bash.md +0 -91
  194. package/skills/chart.md +0 -54
  195. package/skills/code.md +0 -422
  196. package/skills/context.md +0 -177
  197. package/skills/date.md +0 -58
  198. package/skills/express.md +0 -255
  199. package/skills/file.md +0 -60
  200. package/skills/lhs.md +0 -54
  201. package/skills/meta.md +0 -1023
  202. package/skills/msg.md +0 -30
  203. package/skills/number.md +0 -88
  204. package/skills/obj.md +0 -36
  205. package/skills/params.md +0 -206
  206. package/skills/random.md +0 -22
  207. package/skills/role.md +0 -59
  208. package/skills/session.md +0 -281
  209. package/skills/storage.md +0 -743
  210. package/skills/thread.md +0 -22
  211. package/skills/type.md +0 -547
  212. package/skills/url.md +0 -34
  213. package/skills/validate.md +0 -48
  214. package/test/cleanup/close-db.js +0 -5
  215. package/test/core/array.js +0 -226
  216. package/test/core/chart.js +0 -51
  217. package/test/core/date.js +0 -37
  218. package/test/core/encrypt.js +0 -14
  219. package/test/core/file.js +0 -59
  220. package/test/core/lhs.js +0 -44
  221. package/test/core/meta.js +0 -594
  222. package/test/core/number.js +0 -172
  223. package/test/core/obj.js +0 -47
  224. package/test/core/random.js +0 -24
  225. package/test/core/thread.js +0 -20
  226. package/test/core/type.js +0 -216
  227. package/test/core/validate.js +0 -67
  228. package/test/db/db-ops.js +0 -99
  229. package/test/db/db.js +0 -72
  230. package/test/db/pipe_test.txt +0 -0
  231. package/test/db/test_case_design.md +0 -528
  232. package/test/db/test_db_class.js +0 -613
  233. package/test/db/test_entity_class.js +0 -414
  234. package/test/db/test_gridfs_class.js +0 -234
  235. package/test/entity/create.js +0 -442
  236. package/test/entity/delete-mixed.js +0 -156
  237. package/test/entity/delete.js +0 -480
  238. package/test/entity/read.js +0 -285
  239. package/test/entity/ref-filter.js +0 -63
  240. package/test/entity/update.js +0 -252
  241. package/test/router/role.js +0 -15
  242. package/tool/test.json +0 -25
package/core/meta.js DELETED
@@ -1,283 +0,0 @@
1
- /**
2
- * @fileoverview Meta programming core - Entity definition and validation.
3
- * @module core/meta
4
- *
5
- * Field attributes:
6
- * - name: Field name (required).
7
- * - type: Data type (string, int, float, etc., default: "string").
8
- * - required: Whether field is required (default: false).
9
- * - default: Default value for the field. Value must be valid for the field type.
10
- * - ref: Reference to another entity (collection name).
11
- * - link: Link to another field in this entity (must be a field of type 'ref').
12
- * This field's value will be auto-populated from the referenced entity.
13
- * Only supports { name, link, list } attributes.
14
- * - delete: Deletion behavior for ref fields.
15
- * - "keep": Keep this record when referenced entity is deleted.
16
- * - "cascade": Delete this record when referenced entity is deleted.
17
- * - Default: undefined (no action).
18
- * - create: Show in create form (default: true).
19
- * - list: Show in table list (default: true).
20
- * - search: Show in search form (default: true).
21
- * - update: Allow update (default: true).
22
- * - clone: Include in clone (default: true).
23
- * - sys: System field (server-side only, not sent to client unless explicitly needed).
24
- * - secure: Hidden from client entirely (e.g., password hash).
25
- * - group: User group sharing control (field name containing group ID).
26
- * - view: Form view identifier - controls which form view(s) display this field.
27
- * - "*": All views (default for editable fields).
28
- * - "view_name": Specific view only.
29
- * Only applicable to editable fields (create !== false or update !== false).
30
- * Multiple form views can reference different subsets of fields for different contexts.
31
- */
32
-
33
- const { get_type } = require('./type');
34
- const { validate_meta_role } = require('./role');
35
-
36
- const meta_manager = {};
37
-
38
- const FIELD_ATTRS = ["name", "type", "required", "default", "ref", "link", "delete", "create", "list", "search", "update", "clone", "sys", "secure", "group", "view"];
39
- const LINK_FIELD_ATTRS = ["name", "link", "list"];
40
- const CALLBACK_NAMES = ["after_read", "list_query", "before_create", "before_clone", "before_update", "before_delete",
41
- "after_create", "after_clone", "after_update", "after_delete", "create", "clone", "update", "batch_update", "after_batch_update", "delete"];
42
- const OPERATION_FLAGS = ["creatable", "readable", "updatable", "deleteable", "cloneable", "importable", "exportable"];
43
- const MODE_MAP = { creatable: "c", readable: "rs", updatable: "u", deleteable: "db", cloneable: "o", importable: "i", exportable: "e" };
44
-
45
- const META_ATTRS = ["collection", "roles", "primary_keys", "fields", ...OPERATION_FLAGS, ...CALLBACK_NAMES, "ref_label", "ref_filter", "route", "user_field"];
46
- const DELETE_MODE = Object.freeze({ all: ["keep", "cascade"], keep: "keep", cascade: "cascade" });
47
-
48
- /** Convert fields array to name-keyed map. */
49
- const to_fields_map = (fields) => fields.reduce((m, f) => { m[f.name] = f; return m; }, {});
50
-
51
- /** Format error message with meta context. */
52
- const meta_error = (collection, msg, field = null) => {
53
- const prefix = field ? `meta:${collection},field:${field.name}` : `meta:${collection}`;
54
- return new Error(`${prefix} ${msg}`);
55
- };
56
-
57
- /**
58
- * Validate and normalize field definition.
59
- * @param {Object} meta - Entity meta.
60
- * @param {Object} field - Field definition.
61
- * @throws {Error} If field configuration is invalid.
62
- */
63
- const validate_field = (meta, field) => {
64
- if (!field.name) throw meta_error(meta.collection, `name attr required for field:${JSON.stringify(field)}`);
65
-
66
- if (field.type) get_type(field.type);
67
- else if (!field.link) field.type = "string";
68
-
69
- if (meta.primary_keys.includes(field.name)) field.required = true;
70
-
71
- // Validate default value against field type
72
- if (field.default !== undefined && field.type) {
73
- const type = get_type(field.type);
74
- const result = type.convert(field.default);
75
- if (result.err) throw meta_error(meta.collection, `invalid default value [${field.default}] for type [${field.type}]`, field);
76
- }
77
-
78
- if (field.ref && !field.link) {
79
- const ref_meta = meta_manager[field.ref];
80
- if (!ref_meta) throw meta_error(meta.collection, `refers invalid meta:${field.ref}`, field);
81
- if (!ref_meta.ref_label) throw meta_error(meta.collection, `refers meta:${field.ref} without ref_label`, field);
82
-
83
- const ref_by_collections = ref_meta.ref_by_metas.map((m) => m.collection);
84
- if (!ref_by_collections.includes(this.collection)) ref_meta.ref_by_metas.push(meta_manager[meta.collection]);
85
- }
86
-
87
- if (field.delete) {
88
- if (!field.ref) throw meta_error(meta.collection, `delete not allowed on non-ref field`, field);
89
- if (!DELETE_MODE.all.includes(field.delete)) throw meta_error(meta.collection, `invalid delete:${field.delete}, valid:${JSON.stringify(DELETE_MODE.all)}`, field);
90
- }
91
-
92
- if (field.link) {
93
- const invalid_keys = Object.keys(field).filter((k) => !LINK_FIELD_ATTRS.includes(k));
94
- if (invalid_keys.length) throw meta_error(meta.collection, `Link field only supports ${LINK_FIELD_ATTRS.join(",")}. Unsupported:${invalid_keys.join(",")}`);
95
- }
96
-
97
- const editable = (field.create !== false) || (field.update !== false);
98
- if (field.view && !editable) throw meta_error(meta.collection, `view only for editable fields`);
99
- if (!field.view && editable) field.view = "*";
100
-
101
- const invalid_attrs = Object.keys(field).filter((k) => !FIELD_ATTRS.includes(k));
102
- if (invalid_attrs.length) throw meta_error(meta.collection, `Unsupported attribute [${invalid_attrs.join(",")}] for field:${JSON.stringify(field)}`);
103
- };
104
-
105
- /**
106
- * Validate all fields in meta definition.
107
- * @param {Object} meta - Entity meta.
108
- * @param {Object[]} fields - Field definitions.
109
- * @returns {boolean} True if valid.
110
- * @throws {Error} If validation fails.
111
- */
112
- const validate_fields = (meta, fields) => {
113
- const fields_map = to_fields_map(fields);
114
- const seen_names = new Set();
115
-
116
- for (const field of fields) {
117
- validate_field(meta, field);
118
-
119
- if (seen_names.has(field.name)) throw meta_error(meta.collection, `Duplicate field [${JSON.stringify(field)}]`);
120
- seen_names.add(field.name);
121
-
122
- if (field.link) {
123
- const link_field = fields_map[field.link];
124
- if (!link_field) throw meta_error(meta.collection, `link field [${JSON.stringify(field)}] should link to field`);
125
- if (!link_field.ref) throw meta_error(meta.collection, `link field [${JSON.stringify(field)}] target [${JSON.stringify(link_field)}] must ref entity`);
126
-
127
- const entity = get_entity_meta(link_field.ref);
128
- const link_entity_field = entity.fields_map[field.name];
129
- if (!link_entity_field) throw meta_error(entity.collection, `link field [${JSON.stringify(field)}] should link to field`);
130
-
131
- Object.assign(field, { type: link_entity_field.type, required: false, create: false, search: false, update: false, clone: false, delete: "cascade" });
132
- if (link_entity_field.ref) field.ref = link_entity_field.ref;
133
- }
134
- }
135
- return true;
136
- };
137
-
138
- /** Validate all registered metas after loading. */
139
- const validate_all_metas = () => Object.values(meta_manager).forEach((m) => m.validate_meta_info());
140
-
141
- /**
142
- * Set callback function on entity meta.
143
- * @param {Object} entity_meta - Entity meta object.
144
- * @param {string} cb_name - Callback name.
145
- * @param {Function} cb - Callback function.
146
- * @throws {Error} If callback is not a function.
147
- */
148
- const set_callback = (entity_meta, cb_name, cb) => {
149
- if (!cb) return;
150
- if (!(cb instanceof Function)) throw new Error(`callback [${cb_name}] for meta:${entity_meta.collection} isn't function`);
151
- entity_meta[cb_name] = cb;
152
- };
153
-
154
- /** Get entity meta by collection name. */
155
- const get_entity_meta = (collection) => meta_manager[collection];
156
-
157
- /** Get all registered meta collection names. */
158
- const get_all_metas = () => Object.keys(meta_manager);
159
-
160
-
161
- /**
162
- * Entity Meta wrapper class.
163
- * Validates meta structure and sets default values.
164
- */
165
- class EntityMeta {
166
- /**
167
- * Create EntityMeta instance.
168
- * @param {Object} meta - Meta definition object.
169
- * @throws {Error} If duplicate meta registered.
170
- */
171
- constructor(meta) {
172
- this.meta = meta;
173
- this.collection = meta.collection;
174
- this.roles = meta.roles;
175
- this.primary_keys = meta.primary_keys;
176
- this.user_field = meta.user_field;
177
- this.ref_label = meta.ref_label;
178
- this.ref_filter = meta.ref_filter;
179
-
180
- // Set operation flags with defaults
181
- OPERATION_FLAGS.forEach((flag) => { this[flag] = meta[flag] ?? false; });
182
- this.editable = this.creatable || this.updatable;
183
-
184
- // Build mode string
185
- this.mode = OPERATION_FLAGS.filter((f) => this[f]).map((f) => MODE_MAP[f]).join("");
186
-
187
- // Field organization
188
- this.fields = meta.fields;
189
- this.fields_map = to_fields_map(meta.fields);
190
- this.field_names = this.fields.map((f) => f.name);
191
- this._init_field_subsets(meta);
192
-
193
- // Reference handling
194
- this.ref_fields = this.fields.filter((f) => f.ref);
195
- this.link_fields = this.fields.filter((f) => f.link);
196
- this.ref_by_metas = [];
197
-
198
- // Set callbacks and register meta
199
- CALLBACK_NAMES.forEach((cb) => set_callback(this, cb, meta[cb]));
200
- if (meta_manager[meta.collection]) throw new Error(`Duplicate meta info:${this.collection}`);
201
- meta_manager[meta.collection] = this;
202
- }
203
-
204
- /** Initialize field subsets for different operations. @private */
205
- _init_field_subsets(meta) {
206
- const not_sys = (f) => f.sys !== true;
207
- const not_secure = (f) => f.secure !== true;
208
-
209
- this.client_fields = this.fields.filter(not_sys);
210
- this.property_fields = this.fields.filter((f) => not_sys(f) && not_secure(f));
211
- this.create_fields = this.fields.filter((f) => f.create !== false && not_sys(f));
212
- this.update_fields = this.fields.filter((f) => f.create !== false && f.update !== false && not_sys(f));
213
- this.search_fields = this.fields.filter((f) => f.search !== false && not_sys(f));
214
- this.clone_fields = this.fields.filter((f) => f.clone !== false && not_sys(f));
215
- this.list_fields = this.fields.filter((f) => f.list !== false && not_sys(f) && not_secure(f));
216
- this.primary_key_fields = this.fields.filter((f) => meta.primary_keys.includes(f.name));
217
- this.required_field_names = this.fields.filter((f) => f.required === true || this.primary_keys.includes(f.name)).map((f) => f.name);
218
- this.file_fields = this.fields.filter((f) => f.type === 'file');
219
- this.upload_fields = this.file_fields.map((f) => ({ name: f.name }));
220
- }
221
-
222
- /**
223
- * Validate meta information.
224
- * @returns {boolean} True if valid.
225
- * @throws {Error} If validation fails.
226
- */
227
- validate_meta_info() {
228
- if (!this.collection) throw new Error(`no collection defined for meta:${JSON.stringify(this.meta)}`);
229
-
230
- const invalid_attrs = Object.keys(this.meta).filter((k) => !META_ATTRS.includes(k));
231
- if (invalid_attrs.length) throw meta_error(this.collection, `Unsupported attribute [${invalid_attrs.join(",")}]`);
232
-
233
- this._validate_primary_keys();
234
- this._validate_roles();
235
- this._validate_field_exists("ref_label", this.ref_label);
236
- this._validate_field_exists("user_field", this.user_field);
237
- if (this.ref_filter && this.ref_filter.constructor !== Object) {
238
- throw meta_error(this.collection, `ref_filter should be object`);
239
- }
240
-
241
- return validate_fields(this.meta, this.fields);
242
- }
243
-
244
- /** Validate primary keys configuration. @private */
245
- _validate_primary_keys() {
246
- if (!this.primary_keys) throw meta_error(this.collection, `no primary_keys defined`);
247
- if (!Array.isArray(this.primary_keys)) throw meta_error(this.collection, `primary_keys should be array`);
248
- for (const key of this.primary_keys) {
249
- if (!this.field_names.includes(key)) throw meta_error(this.collection, `wrong primary_key ${key}`);
250
- }
251
- }
252
-
253
- /** Validate a field name exists in fields. @private */
254
- _validate_field_exists(attr_name, value) {
255
- if (value && !this.field_names.includes(value)) {
256
- throw meta_error(this.collection, `${attr_name} [${value}] not found in fields`);
257
- }
258
- }
259
-
260
- /** Validate roles configuration. @private */
261
- _validate_roles() {
262
- if (!this.roles) return;
263
- if (!Array.isArray(this.roles)) throw meta_error(this.collection, `roles should be array`);
264
-
265
- for (const role of this.roles) {
266
- const parts = role.split(":");
267
- if (parts.length < 2 || parts.length > 3) {
268
- throw meta_error(this.collection, `wrong role config [${role}]. Use : to separate role name with mode.`);
269
- }
270
-
271
- const [role_name, role_mode] = parts;
272
- if (!validate_meta_role(role_name)) throw meta_error(this.collection, `role [${role_name}] not defined in settings`);
273
-
274
- if (role_mode !== "*") {
275
- for (const mode of role_mode) {
276
- if (!this.mode.includes(mode)) throw meta_error(this.collection, `role [${role_name}] mode [${mode}] doesn't match entity mode [${this.mode}]`);
277
- }
278
- }
279
- }
280
- }
281
- }
282
-
283
- module.exports = { EntityMeta, validate_all_metas, get_entity_meta, get_all_metas, DELETE_MODE };
package/core/msg.js DELETED
@@ -1,24 +0,0 @@
1
- /**
2
- * @fileoverview Message sending utility functions using wxmnode.
3
- * @module core/msg
4
- */
5
-
6
- const wxm = require('wxmnode');
7
-
8
- /**
9
- * Initialize wxm with credentials.
10
- * @param {string} name - Account name.
11
- * @param {string} password - Account password.
12
- */
13
- const init_wxm = (name, password) => wxm.init(name, password);
14
-
15
- /**
16
- * Send message via wxm.
17
- * @param {string} content - Message content.
18
- * @param {string} type - Message type.
19
- * @param {Object} detail - Additional message details.
20
- * @returns {Promise<Object>} Message send result.
21
- */
22
- const send_msg = async (content, type, detail) => await wxm.sendMsg(content, type, detail);
23
-
24
- module.exports = { init_wxm, send_msg };
package/core/number.js DELETED
@@ -1,181 +0,0 @@
1
- /**
2
- * @fileoverview Number manipulation and mathematical utility functions.
3
- * @module core/number
4
- */
5
-
6
- const { has_value } = require('./validate');
7
- const { is_object } = require('./obj');
8
-
9
- /**
10
- * Parse string value to number, returns 0 if invalid.
11
- * @param {string|number} str - Value to parse.
12
- * @returns {number} Parsed number or 0.
13
- */
14
- const parse_num = (str) => {
15
- const value = parseFloat(str);
16
- return value ? value : 0;
17
- };
18
-
19
- /**
20
- * Parse string value to number with 2 decimal places.
21
- * @param {string|number} str - Value to parse.
22
- * @returns {number} Parsed number rounded to 2 decimal places.
23
- */
24
- const to_fixed2 = (str) => {
25
- const value = parse_num(str);
26
- return value ? parseFloat(value.toFixed(2)) : 0;
27
- };
28
-
29
- /**
30
- * Round number to 2 decimal places.
31
- * @param {number} num - Number to round.
32
- * @returns {number} Rounded number.
33
- */
34
- const round_to_fixed2 = (num) => Math.round(num * 100) / 100;
35
-
36
- /**
37
- * Generate range array. Example: range(3) = [0,1,2], range(1,5) = [1,2,3,4,5]
38
- * @param {number} start - Start value or length if end not provided.
39
- * @param {number} [end] - End value (inclusive).
40
- * @param {number} [step=1] - Step increment.
41
- * @returns {number[]} Array of numbers in the range.
42
- */
43
- const range = (start, end, step = 1) => {
44
- if (!end) return Array.from({ length: start }, (_, key) => key);
45
- return [...Array(Math.floor((end - start) / step) + 1)].map((_, i) => start + i * step);
46
- };
47
-
48
- /**
49
- * Generate scale array with exponential growth. Example: scale(2,10) = [2,4,8]
50
- * @param {number} start - Start value.
51
- * @param {number} end - End value.
52
- * @param {number} [ratio=2] - Scale multiplier.
53
- * @returns {number[]} Array of scaled numbers.
54
- */
55
- const scale = (start, end, ratio = 2) => {
56
- const length = Math.floor(Math.log(end / start) / Math.log(ratio)) + 1;
57
- return [...Array(length)].map((_, i) => start * Math.pow(ratio, i));
58
- };
59
-
60
- /**
61
- * Create a space object representing a min-max range.
62
- * @param {number} min - Minimum value.
63
- * @param {number} max - Maximum value.
64
- * @returns {{min: number, max: number}} Space object.
65
- * @throws {Error} If min or max not provided.
66
- */
67
- const space = (min, max) => {
68
- if (!has_value(min) || !has_value(max)) throw new Error("min and max not provided for space");
69
- return { min, max };
70
- };
71
-
72
- /**
73
- * Check if value is a space object (has min and max properties).
74
- * @param {*} value - Value to check.
75
- * @returns {boolean} True if value is a space object.
76
- */
77
- const is_space = (value) => is_object(value) && has_value(value.min) && has_value(value.max);
78
-
79
- /**
80
- * Check if value is an integer.
81
- * @param {*} value - Value to check.
82
- * @returns {boolean} True if value is an integer.
83
- */
84
- const is_integer = (value) => /^-?[0-9]+$/.test(value);
85
-
86
- /**
87
- * Check if object contains any space objects as property values.
88
- * @param {Object} obj - Object to check.
89
- * @returns {boolean} True if any property is a space object.
90
- */
91
- const contains_space = (obj) => {
92
- for (const key in obj) {
93
- if (is_space(obj[key])) return true;
94
- }
95
- return false;
96
- };
97
-
98
- /**
99
- * Generate random number between min and max.
100
- * @param {number} min - Minimum value.
101
- * @param {number} max - Maximum value.
102
- * @returns {number} Random number (integer if both bounds are integers).
103
- */
104
- const random_number = (min, max) => {
105
- const random = Math.random() * (max - min) + min;
106
- return is_integer(min) && is_integer(max) ? Math.floor(random) : to_fixed2(random);
107
- };
108
-
109
- /**
110
- * Generate Latin Hypercube Sampling ranges for a given range.
111
- * @param {number} min - Minimum value.
112
- * @param {number} max - Maximum value.
113
- * @param {number} n - Number of samples.
114
- * @returns {{min: number, max: number}[]} Array of sample ranges.
115
- */
116
- const lhs_samples = (min, max, n) => {
117
- const all_int = is_integer(min + "") && is_integer(max + "");
118
- const interval = (max - min) / n;
119
- const ranges = [];
120
-
121
- for (let i = 0; i < n; i++) {
122
- const start = i * interval + min;
123
- const end = (i === n - 1) ? max : start + interval;
124
- const min_val = Math.min(start, end);
125
- const max_val = Math.max(start, end);
126
-
127
- ranges.push(all_int
128
- ? { min: Math.floor(min_val), max: Math.floor(max_val) }
129
- : { min: to_fixed2(min_val), max: to_fixed2(max_val) }
130
- );
131
- }
132
- return ranges;
133
- };
134
-
135
- /**
136
- * Create random sample object from configuration with arrays or space objects.
137
- * @param {Object} obj - Configuration object with arrays or space values.
138
- * @returns {Object} Sample object with randomly selected values.
139
- */
140
- const random_sample = (obj) => {
141
- const sample_obj = {};
142
- for (const key in obj) {
143
- const value = obj[key];
144
- if (Array.isArray(value)) {
145
- sample_obj[key] = value[Math.floor(random_number(0, value.length))];
146
- } else if (is_space(value)) {
147
- sample_obj[key] = random_number(value.min, value.max);
148
- } else {
149
- sample_obj[key] = value;
150
- }
151
- }
152
- return sample_obj;
153
- };
154
-
155
- /**
156
- * Extract numeric value from string containing numbers.
157
- * @param {string} value - String to extract number from.
158
- * @returns {number} Extracted number or 0 if not found.
159
- */
160
- const extract_number = (value) => {
161
- const numbers = value.match(/([+\-0-9\\.]+)/g);
162
- if (!numbers) return 0;
163
- const values = numbers.map(Number).filter((v) => has_value(v));
164
- return values.length === 1 ? values[0] : 0;
165
- };
166
-
167
- module.exports = {
168
- parse_num,
169
- extract_number,
170
- to_fixed2,
171
- round_to_fixed2,
172
- range,
173
- scale,
174
- space,
175
- is_space,
176
- contains_space,
177
- is_integer,
178
- random_number,
179
- random_sample,
180
- lhs_samples
181
- };
package/core/obj.js DELETED
@@ -1,25 +0,0 @@
1
- /**
2
- * @fileoverview Object manipulation utility functions.
3
- * @module core/obj
4
- */
5
-
6
- /**
7
- * Create a new object by copying specified attributes from source object.
8
- * @param {Object} obj - Source object to copy from.
9
- * @param {string[]} attrs - Array of attribute names to copy.
10
- * @returns {Object} New object containing only the specified attributes.
11
- */
12
- const copy_obj = (obj, attrs) => {
13
- const copied = {};
14
- attrs.forEach((attr) => { copied[attr] = obj[attr]; });
15
- return copied;
16
- };
17
-
18
- /**
19
- * Check if a value is a plain object (not null, not array).
20
- * @param {*} obj - Value to check.
21
- * @returns {boolean} True if value is a plain object, false otherwise.
22
- */
23
- const is_object = (obj) => typeof obj === 'object' && obj !== null && !Array.isArray(obj);
24
-
25
- module.exports = { copy_obj, is_object };
package/core/random.js DELETED
@@ -1,12 +0,0 @@
1
- /**
2
- * @fileoverview Random generation utility functions.
3
- * @module core/random
4
- */
5
-
6
- /**
7
- * Generate random 6-digit code.
8
- * @returns {number} Random number between 0 and 999999.
9
- */
10
- const random_code = () => Math.floor(Math.random() * 1000000);
11
-
12
- module.exports = { random_code };
package/core/role.js DELETED
@@ -1,108 +0,0 @@
1
- /**
2
- * @fileoverview Role-based access control utility functions.
3
- * @module core/role
4
- */
5
-
6
- const { get_settings } = require("../setting");
7
-
8
- /**
9
- * Find a role by name from settings.
10
- * @param {string} role_name - Role name to find.
11
- * @returns {Object|undefined} Role object or undefined if not found.
12
- */
13
- const find_role = (role_name) => {
14
- const settings = get_settings();
15
- return settings.roles ? settings.roles.find((role) => role.name === role_name) : undefined;
16
- };
17
-
18
- /**
19
- * Validate role name exists in settings configuration.
20
- * @param {string} role_name - Role name to validate.
21
- * @returns {boolean} True if role is valid and configured.
22
- */
23
- const validate_meta_role = (role_name) => {
24
- const settings = get_settings();
25
- if (!settings.roles) return false;
26
- return find_role(role_name) !== undefined;
27
- };
28
-
29
- /**
30
- * Check if role name exists in settings.
31
- * @param {string} role_name - Role name to check.
32
- * @returns {boolean} True if role exists.
33
- */
34
- const is_valid_role = (role_name) => find_role(role_name) !== undefined;
35
-
36
- /**
37
- * Check if role has root/admin privileges.
38
- * @param {string} role_name - Role name to check.
39
- * @returns {boolean} True if role is root.
40
- */
41
- const is_root_role = (role_name) => {
42
- const role = find_role(role_name);
43
- return role ? role.root === true : true;
44
- };
45
-
46
- /**
47
- * Get user role from session.
48
- * @param {Object} req - HTTP request object.
49
- * @returns {string|null} User's role or null.
50
- */
51
- const get_session_user_role = (req) => {
52
- const user = req && req.session ? req.session.user : null;
53
- return user ? user.role : null;
54
- };
55
-
56
- /**
57
- * Get user object from session.
58
- * @param {Object} req - HTTP request object.
59
- * @returns {Object|null} User object or null.
60
- */
61
- const get_session_user = (req) => req && req.session ? req.session.user : null;
62
-
63
- /**
64
- * Check if current user has root privileges.
65
- * @param {Object} req - HTTP request object.
66
- * @returns {boolean} True if user is root.
67
- */
68
- const is_root_user = (req) => is_root_role(get_session_user_role(req));
69
-
70
- /**
71
- * Get user's role permissions for a meta entity.
72
- * @param {Object} req - HTTP request object.
73
- * @param {Object} meta - Meta entity definition.
74
- * @returns {[string, string]} Array of [mode, view] permissions.
75
- */
76
- const get_user_role_right = (req, meta) => {
77
- const settings = get_settings();
78
- if (!settings.roles || !meta.roles) return [meta.mode, "*"];
79
-
80
- const user_role = get_session_user_role(req);
81
- if (!user_role) return ["", ""];
82
- if (!is_valid_role(user_role)) return ["", ""];
83
-
84
- for (const role of meta.roles) {
85
- const role_settings = role.split(":");
86
- const [role_name, role_mode] = role_settings;
87
- const role_view = role_settings.length === 3 ? role_settings[2] : "*";
88
- if (user_role === role_name) {
89
- return role_mode === "*" ? [meta.mode, role_view] : [role_mode, role_view];
90
- }
91
- }
92
- return ["", ""];
93
- };
94
-
95
- /**
96
- * Check if user has required mode permission on meta.
97
- * @param {Object} req - HTTP request object.
98
- * @param {Object} meta - Meta entity definition.
99
- * @param {string} mode - Required mode (c/r/u/d).
100
- * @param {string} view - Required view.
101
- * @returns {boolean} True if user has permission.
102
- */
103
- const check_user_role = (req, meta, mode, view) => {
104
- const [role_mode, role_view] = get_user_role_right(req, meta);
105
- return role_mode.includes(mode) && (role_view === "*" || role_view.includes(view));
106
- };
107
-
108
- module.exports = { is_root_role, is_root_user, validate_meta_role, check_user_role, get_user_role_right, get_session_user };
package/core/thread.js DELETED
@@ -1,13 +0,0 @@
1
- /**
2
- * @fileoverview Threading and async utility functions.
3
- * @module core/thread
4
- */
5
-
6
- /**
7
- * Sleep for specified milliseconds.
8
- * @param {number} ms - Milliseconds to sleep.
9
- * @returns {Promise<void>} Promise that resolves after delay.
10
- */
11
- const snooze = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
12
-
13
- module.exports = { snooze };