spice-js 2.6.70 → 2.6.71

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.
@@ -6,40 +6,28 @@ var _lodash = _interopRequireDefault(require("lodash"));
6
6
 
7
7
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
8
8
 
9
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
9
+ try {
10
+ var resources = ["models", "controllers", "schemas", "cache"];
10
11
 
11
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
12
+ for (var resource of resources) {
13
+ var paths = _path.default.join(spice.root_path, resource);
12
14
 
13
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
15
+ spice[resource] = {};
14
16
 
15
- function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
17
+ var files = require("fs").readdirSync(paths);
16
18
 
17
- try {
18
- var resources = ["models", "controllers", "schemas", "cache"];
19
+ for (var file of files) {
20
+ var file_name = file.split(".")[0];
21
+
22
+ var imported = require(_path.default.join(paths, file));
23
+
24
+ var moduleDefault = imported.default || imported; // ⚡ Only store once, create both references to same object
19
25
 
20
- _lodash.default.each(resources,
21
- /*#__PURE__*/
22
- function () {
23
- var _ref = _asyncToGenerator(function* (resource) {
24
- var paths = _path.default.join(spice.root_path, resource);
25
-
26
- spice[resource] = {};
27
-
28
- for (var file of require("fs").readdirSync(paths)) {
29
- var file_name = file.split(".")[0];
30
- spice[resource][file_name.toLowerCase()] = (yield Promise.resolve("" + _path.default.join(paths, file)).then(s => _interopRequireWildcard(require(s)))).default;
31
- spice[resource][file_name] = (yield Promise.resolve("" + _path.default.join(paths, file)).then(s => _interopRequireWildcard(require(s)))).default;
32
-
33
- if (resource == "models") {
34
- new spice[resource][file_name]({});
35
- }
36
- }
37
- });
38
-
39
- return function (_x) {
40
- return _ref.apply(this, arguments);
41
- };
42
- }());
26
+ spice[resource][file_name] = moduleDefault;
27
+ spice[resource][file_name.toLowerCase()] = moduleDefault; // ⚡ REMOVED: No longer instantiating models at startup
28
+ // Models will be instantiated when needed via `new spice.models[name]({})`
29
+ }
30
+ }
43
31
  } catch (error) {
44
32
  console.log("Error Happened", error);
45
33
  }
@@ -2,17 +2,53 @@
2
2
 
3
3
  var _path = _interopRequireDefault(require("path"));
4
4
 
5
+ var _fs = _interopRequireDefault(require("fs"));
6
+
7
+ var _util = require("util");
8
+
5
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
6
10
 
7
- spice.routers = {};
11
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
12
+
13
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
14
+
15
+ var readdir = (0, _util.promisify)(_fs.default.readdir);
16
+ spice.routers = {}; // ⚡ OPTIMIZED: Async file operations for non-blocking route loading
17
+
18
+ function loadRoutes() {
19
+ return _loadRoutes.apply(this, arguments);
20
+ }
21
+
22
+ function _loadRoutes() {
23
+ _loadRoutes = _asyncToGenerator(function* () {
24
+ var paths = _path.default.join(spice.root_path, 'routes');
25
+
26
+ try {
27
+ var files = yield readdir(paths);
28
+
29
+ for (var file of files) {
30
+ if (file !== 'index.js' && file.endsWith('.js')) {
31
+ try {
32
+ var router = require(_path.default.join(paths, file)); // Handle ESM default exports
33
+
8
34
 
9
- var paths = _path.default.join(spice.root_path, 'routes');
35
+ if (router.default) {
36
+ router = router.default;
37
+ }
10
38
 
11
- require('fs').readdirSync(paths).forEach(function (file) {
12
- if (file != 'index.js') {
13
- var router = require(_path.default.join(paths, file));
39
+ var routerName = file.split('.')[0];
40
+ spice.routers[routerName] = router;
41
+ spice.app.use(spice.routers[routerName].routes()).use(spice.routers[routerName].allowedMethods());
42
+ } catch (routeError) {
43
+ console.error("Failed to load route " + file + ":", routeError.message);
44
+ }
45
+ }
46
+ }
47
+ } catch (error) {
48
+ console.error('Error loading routes:', error);
49
+ }
50
+ });
51
+ return _loadRoutes.apply(this, arguments);
52
+ }
14
53
 
15
- spice.routers[file.split('.')[0]] = router;
16
- spice.app.use(spice.routers[file.split('.')[0]].routes()).use(spice.routers[file.split('.')[0]].allowedMethods());
17
- }
18
- });
54
+ module.exports = loadRoutes;
@@ -4,22 +4,51 @@ var _path = _interopRequireDefault(require("path"));
4
4
 
5
5
  var _fs = _interopRequireDefault(require("fs"));
6
6
 
7
+ var _util = require("util");
8
+
7
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
8
10
 
9
- var paths = _path.default.join(spice.root_path, "schema_extenders");
11
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
12
+
13
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
14
+
15
+ var readdir = (0, _util.promisify)(_fs.default.readdir);
16
+ spice.schema_extenders = {}; // ⚡ OPTIMIZED: Async file operations for non-blocking schema extender loading
17
+
18
+ function loadSchemaExtenders() {
19
+ return _loadSchemaExtenders.apply(this, arguments);
20
+ }
10
21
 
11
- spice.schema_extenders = {};
22
+ function _loadSchemaExtenders() {
23
+ _loadSchemaExtenders = _asyncToGenerator(function* () {
24
+ var paths = _path.default.join(spice.root_path, "schema_extenders");
12
25
 
13
- if (_fs.default.existsSync(paths)) {
14
- _fs.default.readdirSync(paths).forEach(function (file) {
15
- if (_path.default.extname(file) === ".js" && file !== "index.js") {
26
+ if (_fs.default.existsSync(paths)) {
16
27
  try {
17
- var extender = require(_path.default.join(paths, file));
28
+ var files = yield readdir(paths);
18
29
 
19
- spice.schema_extenders[_path.default.basename(file, ".js")] = extender;
30
+ for (var file of files) {
31
+ if (_path.default.extname(file) === ".js" && file !== "index.js") {
32
+ try {
33
+ var extender = require(_path.default.join(paths, file)); // Handle ESM default exports
34
+
35
+
36
+ if (extender.default) {
37
+ extender = extender.default;
38
+ }
39
+
40
+ spice.schema_extenders[_path.default.basename(file, ".js")] = extender;
41
+ } catch (error) {
42
+ console.error("Failed to load schema extender " + file + ":", error.message);
43
+ }
44
+ }
45
+ }
20
46
  } catch (error) {
21
- console.error("Failed to load " + file + ":", error);
47
+ console.error("Error loading schema extenders:", error);
22
48
  }
23
49
  }
24
50
  });
25
- }
51
+ return _loadSchemaExtenders.apply(this, arguments);
52
+ }
53
+
54
+ module.exports = loadSchemaExtenders;
@@ -2,37 +2,50 @@
2
2
 
3
3
  var _path = _interopRequireDefault(require("path"));
4
4
 
5
+ var _fs = _interopRequireDefault(require("fs"));
6
+
7
+ var _util = require("util");
8
+
5
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
6
10
 
7
- /**
8
- * Created by chadfraser on 25/02/2017.
9
- */
10
- module.exports = function () {
11
- return new Promise(function (resolve, reject) {
12
- try {
13
- var locations = [spice.module_root_path + '/val', spice.root_path + '/validators'];
11
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
14
12
 
15
- var _loop = function _loop(i) {
16
- var files = require('fs').readdirSync(i);
13
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
17
14
 
18
- files.forEach(function (file) {
19
- if (file != 'index.js') {
20
- file.split('.')[0];
15
+ var readdir = (0, _util.promisify)(_fs.default.readdir); // ⚡ OPTIMIZED: Async file operations for non-blocking validator loading
21
16
 
22
- require(_path.default.join(i, file));
17
+ module.exports =
18
+ /*#__PURE__*/
19
+ _asyncToGenerator(function* () {
20
+ try {
21
+ var locations = [spice.module_root_path + '/val', spice.root_path + '/validators'];
23
22
 
24
- console.log('Loading Validator', _path.default.join(i, file));
25
- }
26
- });
27
- };
23
+ for (var location of locations) {
24
+ // Check if directory exists before trying to read it
25
+ if (_fs.default.existsSync(location)) {
26
+ try {
27
+ var files = yield readdir(location);
28
28
 
29
- for (var i of locations) {
30
- _loop(i);
31
- }
29
+ for (var file of files) {
30
+ if (file !== 'index.js' && file.endsWith('.js')) {
31
+ try {
32
+ require(_path.default.join(location, file));
32
33
 
33
- resolve({});
34
- } catch (e) {
35
- reject(e);
34
+ console.log('Loading Validator', _path.default.join(location, file));
35
+ } catch (validatorError) {
36
+ console.error("Failed to load validator " + file + ":", validatorError.message);
37
+ }
38
+ }
39
+ }
40
+ } catch (error) {
41
+ console.log("Error reading " + location + ":", error.message);
42
+ }
43
+ }
36
44
  }
37
- });
38
- };
45
+
46
+ return {};
47
+ } catch (e) {
48
+ console.error('Error in validation bootstrap:', e);
49
+ throw e;
50
+ }
51
+ });
package/build/index.js CHANGED
@@ -175,22 +175,88 @@ class Spice {
175
175
  /* app._io.on("connection", (sock) => {
176
176
  console.log("Connection Up", sock);
177
177
  }); */
178
-
179
-
178
+ // ⚡ OPTIMIZED: Load routes and models first, then generate docs lazily
179
+
180
+
181
+ yield require("./loaders").load(); // ⚡ LAZY DOCS: Generate docs in background after startup to not block server
182
+
183
+ var docsCache = null;
184
+ var docsGenerating = false; // Generate docs asynchronously after startup
185
+
186
+ var generateDocsInBackground =
187
+ /*#__PURE__*/
188
+ function () {
189
+ var _ref = _asyncToGenerator(function* () {
190
+ if (docsCache || docsGenerating) return;
191
+ docsGenerating = true;
192
+
193
+ try {
194
+ console.log("Generating API documentation...");
195
+ docsCache = yield (0, _generator.default)();
196
+ console.log("API documentation generated successfully");
197
+ } catch (error) {
198
+ console.error("Error generating docs:", error);
199
+ docsCache = {
200
+ swagger: "2.0",
201
+ info: {
202
+ title: "API Docs",
203
+ version: "1.0.0"
204
+ },
205
+ paths: {},
206
+ definitions: {}
207
+ };
208
+ } finally {
209
+ docsGenerating = false;
210
+ }
211
+ });
212
+
213
+ return function generateDocsInBackground() {
214
+ return _ref.apply(this, arguments);
215
+ };
216
+ }(); // Start generating docs in background (non-blocking)
217
+
218
+
219
+ setTimeout(generateDocsInBackground, 100); // Middleware to serve docs - will wait if still generating
220
+
221
+ app.use(
222
+ /*#__PURE__*/
223
+ function () {
224
+ var _ref2 = _asyncToGenerator(function* (ctx, next) {
225
+ if (ctx.path === "/docs/spec" || ctx.path === "/docs/spec.json") {
226
+ // Wait for docs to be generated if not ready
227
+ while (docsGenerating && !docsCache) {
228
+ yield new Promise(resolve => setTimeout(resolve, 100));
229
+ }
230
+
231
+ if (!docsCache) {
232
+ yield generateDocsInBackground();
233
+ }
234
+
235
+ ctx.body = docsCache;
236
+ return;
237
+ }
238
+
239
+ yield next();
240
+ });
241
+
242
+ return function (_x, _x2) {
243
+ return _ref2.apply(this, arguments);
244
+ };
245
+ }());
180
246
  app.use((0, _koa2SwaggerUi.koaSwagger)({
181
247
  hideTopbar: true,
182
248
  title: "Spice JS",
183
249
  routePrefix: "/docs",
184
- // host at /swagger instead of default /docs
185
250
  swaggerOptions: {
186
- spec: yield (0, _generator.default)(),
251
+ url: "/docs/spec",
252
+ // Load spec from endpoint instead of inline
187
253
  deepLinking: true,
188
254
  displayRequestDuration: true,
189
255
  jsonEditor: true
190
256
  },
191
- exposeSpec: true
257
+ exposeSpec: false // We handle spec serving ourselves
258
+
192
259
  }));
193
- yield require("./loaders").load();
194
260
  return spice;
195
261
  } catch (e) {
196
262
  console.log(e.stack);
@@ -52,6 +52,7 @@ if (!Promise.allSettled) {
52
52
  }
53
53
 
54
54
  class SpiceModel {
55
+ // ⚡ Static caches for performance optimization
55
56
  constructor(args) {
56
57
  if (args === void 0) {
57
58
  args = {};
@@ -1330,6 +1331,54 @@ class SpiceModel {
1330
1331
  }
1331
1332
 
1332
1333
  return true;
1334
+ } // ⚡ OPTIMIZED: Cache defaults metadata per model type
1335
+
1336
+
1337
+ getDefaultsMetadata(type) {
1338
+ var cacheKey = this.type + "::" + type;
1339
+
1340
+ if (!SpiceModel._defaultsCache[cacheKey]) {
1341
+ var staticDefaults = {};
1342
+ var dynamicDefaults = []; // Pre-compute once per model type
1343
+
1344
+ for (var key in this.props) {
1345
+ var _this$props$key, _this$props$key$defau;
1346
+
1347
+ var def = (_this$props$key = this.props[key]) == null ? void 0 : (_this$props$key$defau = _this$props$key.defaults) == null ? void 0 : _this$props$key$defau[type];
1348
+
1349
+ if (def !== undefined) {
1350
+ if (_.isFunction(def)) {
1351
+ dynamicDefaults.push({
1352
+ key,
1353
+ fn: def
1354
+ });
1355
+ } else {
1356
+ staticDefaults[key] = def;
1357
+ }
1358
+ }
1359
+ }
1360
+
1361
+ SpiceModel._defaultsCache[cacheKey] = {
1362
+ staticDefaults,
1363
+ dynamicDefaults,
1364
+ hasDefaults: Object.keys(staticDefaults).length > 0 || dynamicDefaults.length > 0
1365
+ };
1366
+ }
1367
+
1368
+ return SpiceModel._defaultsCache[cacheKey];
1369
+ } // ⚡ OPTIMIZED: Cache hidden props per model type
1370
+
1371
+
1372
+ getHiddenProps() {
1373
+ if (!SpiceModel._hiddenPropsCache[this.type]) {
1374
+ SpiceModel._hiddenPropsCache[this.type] = Object.keys(this.props).filter(key => {
1375
+ var _this$props$key2;
1376
+
1377
+ return (_this$props$key2 = this.props[key]) == null ? void 0 : _this$props$key2.hide;
1378
+ });
1379
+ }
1380
+
1381
+ return SpiceModel._hiddenPropsCache[this.type];
1333
1382
  }
1334
1383
 
1335
1384
  mapToObject(data, Class, source_property, store_property, property) {
@@ -1587,33 +1636,42 @@ class SpiceModel {
1587
1636
 
1588
1637
  if (!originalIsArray) {
1589
1638
  data = [data];
1590
- } // Compute the defaults from properties using reduce.
1591
-
1592
-
1593
- var defaults = Object.keys(_this18.props).reduce((acc, key) => {
1594
- var _this18$props$key, _this18$props$key$def;
1595
-
1596
- var def = (_this18$props$key = _this18.props[key]) == null ? void 0 : (_this18$props$key$def = _this18$props$key.defaults) == null ? void 0 : _this18$props$key$def[type];
1597
-
1598
- if (def !== undefined) {
1599
- acc[key] = _.isFunction(def) ? def({
1600
- old_data: data,
1601
- new_data: old_data
1602
- }) : def;
1603
- }
1639
+ } // OPTIMIZED: Use cached defaults metadata instead of computing every time
1640
+
1641
+
1642
+ var {
1643
+ staticDefaults,
1644
+ dynamicDefaults,
1645
+ hasDefaults
1646
+ } = _this18.getDefaultsMetadata(type);
1647
+
1648
+ if (hasDefaults) {
1649
+ data = data.map(item => {
1650
+ // Apply static defaults first (fast - no function calls)
1651
+ var result = _.defaults({}, item, staticDefaults); // Only compute dynamic defaults if there are any
1652
+
1653
+
1654
+ for (var {
1655
+ key,
1656
+ fn
1657
+ } of dynamicDefaults) {
1658
+ if (result[key] === undefined) {
1659
+ result[key] = fn({
1660
+ old_data: data,
1661
+ new_data: old_data
1662
+ });
1663
+ }
1664
+ }
1604
1665
 
1605
- return acc;
1606
- }, {}); // Merge defaults into each object.
1666
+ return result;
1667
+ });
1668
+ } // If type is "read", clean the data by omitting certain props.
1607
1669
 
1608
- data = data.map(item => _.defaults(item, defaults)); // If type is "read", clean the data by omitting certain props.
1609
1670
 
1610
1671
  if (type === "read") {
1611
- // Collect hidden properties from schema.
1612
- var hiddenProps = Object.keys(_this18.props).filter(key => {
1613
- var _this18$props$key2;
1672
+ // OPTIMIZED: Use cached hidden props instead of computing every time
1673
+ var hiddenProps = _this18.getHiddenProps(); // Combine default props to remove.
1614
1674
 
1615
- return (_this18$props$key2 = _this18.props[key]) == null ? void 0 : _this18$props$key2.hide;
1616
- }); // Combine default props to remove.
1617
1675
 
1618
1676
  var propsToClean = ["deleted", "type", ...path_to_be_removed, ...hiddenProps];
1619
1677
  data = data.map(item => _.omit(item, propsToClean));
@@ -1630,4 +1688,6 @@ class SpiceModel {
1630
1688
 
1631
1689
  }
1632
1690
 
1633
- exports.default = SpiceModel;
1691
+ exports.default = SpiceModel;
1692
+ SpiceModel._defaultsCache = {};
1693
+ SpiceModel._hiddenPropsCache = {};