spice-js 2.6.70 → 2.6.72

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spice-js",
3
- "version": "2.6.70",
3
+ "version": "2.6.72",
4
4
  "description": "spice",
5
5
  "main": "build/index.js",
6
6
  "repository": {
@@ -1,23 +1,28 @@
1
1
  import path from "path";
2
2
  import _ from "lodash";
3
+
3
4
  try {
4
5
  let resources = ["models", "controllers", "schemas", "cache"];
5
- _.each(resources, async function (resource) {
6
+
7
+ for (const resource of resources) {
6
8
  let paths = path.join(spice.root_path, resource);
7
9
  spice[resource] = {};
8
- for (let file of require("fs").readdirSync(paths)) {
10
+
11
+ const files = require("fs").readdirSync(paths);
12
+
13
+ for (let file of files) {
9
14
  let file_name = file.split(".")[0];
10
- spice[resource][file_name.toLowerCase()] = (
11
- await import(path.join(paths, file))
12
- ).default;
13
- spice[resource][file_name] = (
14
- await import(path.join(paths, file))
15
- ).default;
16
- if (resource == "models") {
17
- new spice[resource][file_name]({});
18
- }
15
+ const imported = require(path.join(paths, file));
16
+ const moduleDefault = imported.default || imported;
17
+
18
+ // Only store once, create both references to same object
19
+ spice[resource][file_name] = moduleDefault;
20
+ spice[resource][file_name.toLowerCase()] = moduleDefault;
21
+
22
+ // ⚡ REMOVED: No longer instantiating models at startup
23
+ // Models will be instantiated when needed via `new spice.models[name]({})`
19
24
  }
20
- });
25
+ }
21
26
  } catch (error) {
22
27
  console.log("Error Happened", error);
23
28
  }
@@ -1,16 +1,42 @@
1
1
  import path from 'path';
2
+ import fs from 'fs';
3
+ import { promisify } from 'util';
2
4
 
5
+ const readdir = promisify(fs.readdir);
3
6
 
4
- spice.routers = {}
7
+ spice.routers = {};
5
8
 
6
- let paths = path.join(spice.root_path, 'routes');
7
- require('fs').readdirSync(paths).forEach(function (file) {
8
- if (file != 'index.js') {
9
- let router = require(path.join(paths, file));
10
- spice.routers[file.split('.')[0]] = router;
9
+ // OPTIMIZED: Async file operations for non-blocking route loading
10
+ async function loadRoutes() {
11
+ let paths = path.join(spice.root_path, 'routes');
12
+
13
+ try {
14
+ const files = await readdir(paths);
15
+
16
+ for (const file of files) {
17
+ if (file !== 'index.js' && file.endsWith('.js')) {
18
+ try {
19
+ let router = require(path.join(paths, file));
20
+
21
+ // Handle ESM default exports
22
+ if (router.default) {
23
+ router = router.default;
24
+ }
25
+
26
+ const routerName = file.split('.')[0];
27
+ spice.routers[routerName] = router;
11
28
 
12
- spice.app
13
- .use(spice.routers[file.split('.')[0]].routes())
14
- .use(spice.routers[file.split('.')[0]].allowedMethods());
29
+ spice.app
30
+ .use(spice.routers[routerName].routes())
31
+ .use(spice.routers[routerName].allowedMethods());
32
+ } catch (routeError) {
33
+ console.error(`Failed to load route ${file}:`, routeError.message);
34
+ }
35
+ }
36
+ }
37
+ } catch (error) {
38
+ console.error('Error loading routes:', error);
15
39
  }
16
- });
40
+ }
41
+
42
+ module.exports = loadRoutes;
@@ -1,16 +1,39 @@
1
1
  import path from "path";
2
2
  import fs from "fs";
3
- let paths = path.join(spice.root_path, "schema_extenders");
3
+ import { promisify } from "util";
4
+
5
+ const readdir = promisify(fs.readdir);
6
+
4
7
  spice.schema_extenders = {};
5
- if (fs.existsSync(paths)) {
6
- fs.readdirSync(paths).forEach(function (file) {
7
- if (path.extname(file) === ".js" && file !== "index.js") {
8
- try {
9
- let extender = require(path.join(paths, file));
10
- spice.schema_extenders[path.basename(file, ".js")] = extender;
11
- } catch (error) {
12
- console.error(`Failed to load ${file}:`, error);
8
+
9
+ // ⚡ OPTIMIZED: Async file operations for non-blocking schema extender loading
10
+ async function loadSchemaExtenders() {
11
+ let paths = path.join(spice.root_path, "schema_extenders");
12
+
13
+ if (fs.existsSync(paths)) {
14
+ try {
15
+ const files = await readdir(paths);
16
+
17
+ for (const file of files) {
18
+ if (path.extname(file) === ".js" && file !== "index.js") {
19
+ try {
20
+ let extender = require(path.join(paths, file));
21
+
22
+ // Handle ESM default exports
23
+ if (extender.default) {
24
+ extender = extender.default;
25
+ }
26
+
27
+ spice.schema_extenders[path.basename(file, ".js")] = extender;
28
+ } catch (error) {
29
+ console.error(`Failed to load schema extender ${file}:`, error.message);
30
+ }
31
+ }
13
32
  }
33
+ } catch (error) {
34
+ console.error("Error loading schema extenders:", error);
14
35
  }
15
- });
36
+ }
16
37
  }
38
+
39
+ module.exports = loadSchemaExtenders;
@@ -2,25 +2,44 @@
2
2
  * Created by chadfraser on 25/02/2017.
3
3
  */
4
4
  import path from 'path';
5
- module.exports = function () {
6
- return new Promise(function (resolve, reject) {
7
- try {
8
- let locations = [spice.module_root_path + '/val', spice.root_path + '/validators']
9
-
10
- for (let i of locations) {
11
- let files = require('fs').readdirSync(i);
12
- files.forEach(function (file) {
13
- if (file != 'index.js') {
14
- file.split('.')[0];
15
- require(path.join(i, file));
16
- console.log('Loading Validator', path.join(i, file));
5
+ import fs from 'fs';
6
+ import { promisify } from 'util';
7
+
8
+ const readdir = promisify(fs.readdir);
9
+
10
+ // OPTIMIZED: Async file operations for non-blocking validator loading
11
+ module.exports = async function () {
12
+ try {
13
+ let locations = [
14
+ spice.module_root_path + '/val',
15
+ spice.root_path + '/validators'
16
+ ];
17
+
18
+ for (let location of locations) {
19
+ // Check if directory exists before trying to read it
20
+ if (fs.existsSync(location)) {
21
+ try {
22
+ const files = await readdir(location);
23
+
24
+ for (const file of files) {
25
+ if (file !== 'index.js' && file.endsWith('.js')) {
26
+ try {
27
+ require(path.join(location, file));
28
+ console.log('Loading Validator', path.join(location, file));
29
+ } catch (validatorError) {
30
+ console.error(`Failed to load validator ${file}:`, validatorError.message);
31
+ }
32
+ }
17
33
  }
18
- });
34
+ } catch (error) {
35
+ console.log(`Error reading ${location}:`, error.message);
36
+ }
19
37
  }
20
- resolve({})
21
-
22
- } catch (e) {
23
- reject(e);
24
38
  }
25
- });
26
- }
39
+
40
+ return {};
41
+ } catch (e) {
42
+ console.error('Error in validation bootstrap:', e);
43
+ throw e;
44
+ }
45
+ };
package/src/index.js CHANGED
@@ -96,21 +96,68 @@ export default class Spice {
96
96
  /* app._io.on("connection", (sock) => {
97
97
  console.log("Connection Up", sock);
98
98
  }); */
99
+
100
+ // ⚡ OPTIMIZED: Load routes and models first, then generate docs lazily
101
+ await require("./loaders").load();
102
+
103
+ // ⚡ LAZY DOCS: Generate docs in background after startup to not block server
104
+ let docsCache = null;
105
+ let docsGenerating = false;
106
+
107
+ // Generate docs asynchronously after startup
108
+ const generateDocsInBackground = async () => {
109
+ if (docsCache || docsGenerating) return;
110
+ docsGenerating = true;
111
+ try {
112
+ console.log("Generating API documentation...");
113
+ docsCache = await docGen();
114
+ console.log("API documentation generated successfully");
115
+ } catch (error) {
116
+ console.error("Error generating docs:", error);
117
+ docsCache = {
118
+ swagger: "2.0",
119
+ info: { title: "API Docs", version: "1.0.0" },
120
+ paths: {},
121
+ definitions: {}
122
+ };
123
+ } finally {
124
+ docsGenerating = false;
125
+ }
126
+ };
127
+
128
+ // Start generating docs in background (non-blocking)
129
+ setTimeout(generateDocsInBackground, 100);
130
+
131
+ // Middleware to serve docs - will wait if still generating
132
+ app.use(async (ctx, next) => {
133
+ if (ctx.path === "/docs/spec" || ctx.path === "/docs/spec.json") {
134
+ // Wait for docs to be generated if not ready
135
+ while (docsGenerating && !docsCache) {
136
+ await new Promise(resolve => setTimeout(resolve, 100));
137
+ }
138
+ if (!docsCache) {
139
+ await generateDocsInBackground();
140
+ }
141
+ ctx.body = docsCache;
142
+ return;
143
+ }
144
+ await next();
145
+ });
146
+
99
147
  app.use(
100
148
  koaSwagger({
101
149
  hideTopbar: true,
102
150
  title: "Spice JS",
103
- routePrefix: "/docs", // host at /swagger instead of default /docs
151
+ routePrefix: "/docs",
104
152
  swaggerOptions: {
105
- spec: await docGen(),
153
+ url: "/docs/spec", // Load spec from endpoint instead of inline
106
154
  deepLinking: true,
107
155
  displayRequestDuration: true,
108
156
  jsonEditor: true,
109
157
  },
110
- exposeSpec: true,
158
+ exposeSpec: false, // We handle spec serving ourselves
111
159
  })
112
160
  );
113
- await require("./loaders").load();
114
161
 
115
162
  return spice;
116
163
  } catch (e) {