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/build/bootstrap/map.js +17 -29
- package/build/bootstrap/routes.js +45 -9
- package/build/bootstrap/schema_extenders.js +38 -9
- package/build/bootstrap/validation.js +38 -25
- package/build/index.js +72 -6
- package/build/models/SpiceModel.js +214 -49
- package/bun.lock +2281 -0
- package/package.json +1 -1
- package/src/bootstrap/map.js +17 -12
- package/src/bootstrap/routes.js +36 -10
- package/src/bootstrap/schema_extenders.js +33 -10
- package/src/bootstrap/validation.js +38 -19
- package/src/index.js +51 -4
- package/src/models/SpiceModel.js +202 -78
package/package.json
CHANGED
package/src/bootstrap/map.js
CHANGED
|
@@ -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
|
-
|
|
6
|
+
|
|
7
|
+
for (const resource of resources) {
|
|
6
8
|
let paths = path.join(spice.root_path, resource);
|
|
7
9
|
spice[resource] = {};
|
|
8
|
-
|
|
10
|
+
|
|
11
|
+
const files = require("fs").readdirSync(paths);
|
|
12
|
+
|
|
13
|
+
for (let file of files) {
|
|
9
14
|
let file_name = file.split(".")[0];
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
|
|
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
|
}
|
package/src/bootstrap/routes.js
CHANGED
|
@@ -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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
3
|
+
import { promisify } from "util";
|
|
4
|
+
|
|
5
|
+
const readdir = promisify(fs.readdir);
|
|
6
|
+
|
|
4
7
|
spice.schema_extenders = {};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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",
|
|
151
|
+
routePrefix: "/docs",
|
|
104
152
|
swaggerOptions: {
|
|
105
|
-
|
|
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:
|
|
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) {
|