te.js 2.0.3 → 2.1.1

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 (68) hide show
  1. package/README.md +197 -187
  2. package/auto-docs/analysis/handler-analyzer.js +58 -58
  3. package/auto-docs/analysis/source-resolver.js +101 -101
  4. package/auto-docs/constants.js +37 -37
  5. package/auto-docs/docs-llm/index.js +7 -0
  6. package/auto-docs/{llm → docs-llm}/prompts.js +222 -222
  7. package/auto-docs/{llm → docs-llm}/provider.js +132 -187
  8. package/auto-docs/index.js +146 -146
  9. package/auto-docs/openapi/endpoint-processor.js +277 -277
  10. package/auto-docs/openapi/generator.js +107 -107
  11. package/auto-docs/openapi/level3.js +131 -131
  12. package/auto-docs/openapi/spec-builders.js +244 -244
  13. package/auto-docs/ui/docs-ui.js +186 -186
  14. package/auto-docs/utils/logger.js +17 -17
  15. package/auto-docs/utils/strip-usage.js +10 -10
  16. package/cli/docs-command.js +315 -315
  17. package/cli/fly-command.js +71 -71
  18. package/cli/index.js +56 -56
  19. package/database/index.js +165 -165
  20. package/database/mongodb.js +146 -146
  21. package/database/redis.js +201 -201
  22. package/docs/README.md +36 -36
  23. package/docs/ammo.md +362 -362
  24. package/docs/api-reference.md +490 -489
  25. package/docs/auto-docs.md +216 -215
  26. package/docs/cli.md +152 -152
  27. package/docs/configuration.md +275 -233
  28. package/docs/database.md +390 -391
  29. package/docs/error-handling.md +438 -417
  30. package/docs/file-uploads.md +333 -334
  31. package/docs/getting-started.md +214 -215
  32. package/docs/middleware.md +355 -356
  33. package/docs/rate-limiting.md +393 -394
  34. package/docs/routing.md +302 -302
  35. package/package.json +62 -62
  36. package/rate-limit/algorithms/fixed-window.js +141 -141
  37. package/rate-limit/algorithms/sliding-window.js +147 -147
  38. package/rate-limit/algorithms/token-bucket.js +115 -115
  39. package/rate-limit/base.js +165 -165
  40. package/rate-limit/index.js +147 -147
  41. package/rate-limit/storage/base.js +104 -104
  42. package/rate-limit/storage/memory.js +101 -101
  43. package/rate-limit/storage/redis.js +88 -88
  44. package/server/ammo/body-parser.js +220 -220
  45. package/server/ammo/dispatch-helper.js +103 -103
  46. package/server/ammo/enhancer.js +57 -57
  47. package/server/ammo.js +454 -356
  48. package/server/endpoint.js +97 -74
  49. package/server/error.js +9 -9
  50. package/server/errors/code-context.js +125 -0
  51. package/server/errors/llm-error-service.js +140 -0
  52. package/server/files/helper.js +33 -33
  53. package/server/files/uploader.js +143 -143
  54. package/server/handler.js +158 -113
  55. package/server/target.js +185 -175
  56. package/server/targets/middleware-validator.js +22 -22
  57. package/server/targets/path-validator.js +21 -21
  58. package/server/targets/registry.js +160 -160
  59. package/server/targets/shoot-validator.js +21 -21
  60. package/te.js +428 -363
  61. package/utils/auto-register.js +17 -17
  62. package/utils/configuration.js +64 -64
  63. package/utils/errors-llm-config.js +84 -0
  64. package/utils/request-logger.js +43 -43
  65. package/utils/status-codes.js +82 -82
  66. package/utils/tejas-entrypoint-html.js +18 -18
  67. package/auto-docs/llm/index.js +0 -6
  68. package/auto-docs/llm/parse.js +0 -88
@@ -1,71 +1,71 @@
1
- /**
2
- * `tejas fly` — start the Tejas server by running the user's entry point.
3
- * Entry point is resolved in order: CLI arg → tejas.config.json "entry" → package.json "main" → index.js → app.js → server.js
4
- */
5
-
6
- import path from 'node:path';
7
- import fs from 'node:fs';
8
- import { spawn } from 'node:child_process';
9
- import { loadConfigFile } from '../utils/configuration.js';
10
-
11
- const CONVENTION_FILES = ['index.js', 'app.js', 'server.js'];
12
-
13
- function resolveEntryPoint(cliArg) {
14
- const cwd = process.cwd();
15
-
16
- if (cliArg) {
17
- const candidate = path.isAbsolute(cliArg) ? cliArg : path.join(cwd, cliArg);
18
- if (fs.existsSync(candidate)) return candidate;
19
- throw new Error(`Entry file not found: ${cliArg}`);
20
- }
21
-
22
- const config = loadConfigFile();
23
- if (config.entry) {
24
- const candidate = path.join(cwd, config.entry);
25
- if (fs.existsSync(candidate)) return candidate;
26
- throw new Error(`Entry file from tejas.config.json not found: ${config.entry}`);
27
- }
28
-
29
- try {
30
- const pkgPath = path.join(cwd, 'package.json');
31
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
32
- if (pkg.main) {
33
- const candidate = path.join(cwd, pkg.main);
34
- if (fs.existsSync(candidate)) return candidate;
35
- throw new Error(`Entry file from package.json "main" not found: ${pkg.main}`);
36
- }
37
- } catch (err) {
38
- if (err.code === 'ENOENT') {
39
- // no package.json, continue to convention
40
- } else {
41
- throw err;
42
- }
43
- }
44
-
45
- for (const name of CONVENTION_FILES) {
46
- const candidate = path.join(cwd, name);
47
- if (fs.existsSync(candidate)) return candidate;
48
- }
49
-
50
- throw new Error(
51
- `Could not resolve entry point. Set "entry" in tejas.config.json, "main" in package.json, pass a file (tejas fly <file>), or add index.js, app.js, or server.js in ${cwd}`,
52
- );
53
- }
54
-
55
- /**
56
- * Resolves the entry point and spawns the server process. Exits with the child's exit code.
57
- */
58
- export function runFlyCommand() {
59
- const cliArg = process.argv[3]; // tejas fly [file]
60
- const entryFile = resolveEntryPoint(cliArg);
61
-
62
- const child = spawn(process.execPath, [entryFile], {
63
- stdio: 'inherit',
64
- cwd: process.cwd(),
65
- env: process.env,
66
- });
67
-
68
- child.on('exit', (code, signal) => {
69
- process.exit(code ?? (signal ? 1 : 0));
70
- });
71
- }
1
+ /**
2
+ * `tejas fly` — start the Tejas server by running the user's entry point.
3
+ * Entry point is resolved in order: CLI arg → tejas.config.json "entry" → package.json "main" → index.js → app.js → server.js
4
+ */
5
+
6
+ import path from 'node:path';
7
+ import fs from 'node:fs';
8
+ import { spawn } from 'node:child_process';
9
+ import { loadConfigFile } from '../utils/configuration.js';
10
+
11
+ const CONVENTION_FILES = ['index.js', 'app.js', 'server.js'];
12
+
13
+ function resolveEntryPoint(cliArg) {
14
+ const cwd = process.cwd();
15
+
16
+ if (cliArg) {
17
+ const candidate = path.isAbsolute(cliArg) ? cliArg : path.join(cwd, cliArg);
18
+ if (fs.existsSync(candidate)) return candidate;
19
+ throw new Error(`Entry file not found: ${cliArg}`);
20
+ }
21
+
22
+ const config = loadConfigFile();
23
+ if (config.entry) {
24
+ const candidate = path.join(cwd, config.entry);
25
+ if (fs.existsSync(candidate)) return candidate;
26
+ throw new Error(`Entry file from tejas.config.json not found: ${config.entry}`);
27
+ }
28
+
29
+ try {
30
+ const pkgPath = path.join(cwd, 'package.json');
31
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
32
+ if (pkg.main) {
33
+ const candidate = path.join(cwd, pkg.main);
34
+ if (fs.existsSync(candidate)) return candidate;
35
+ throw new Error(`Entry file from package.json "main" not found: ${pkg.main}`);
36
+ }
37
+ } catch (err) {
38
+ if (err.code === 'ENOENT') {
39
+ // no package.json, continue to convention
40
+ } else {
41
+ throw err;
42
+ }
43
+ }
44
+
45
+ for (const name of CONVENTION_FILES) {
46
+ const candidate = path.join(cwd, name);
47
+ if (fs.existsSync(candidate)) return candidate;
48
+ }
49
+
50
+ throw new Error(
51
+ `Could not resolve entry point. Set "entry" in tejas.config.json, "main" in package.json, pass a file (tejas fly <file>), or add index.js, app.js, or server.js in ${cwd}`,
52
+ );
53
+ }
54
+
55
+ /**
56
+ * Resolves the entry point and spawns the server process. Exits with the child's exit code.
57
+ */
58
+ export function runFlyCommand() {
59
+ const cliArg = process.argv[3]; // tejas fly [file]
60
+ const entryFile = resolveEntryPoint(cliArg);
61
+
62
+ const child = spawn(process.execPath, [entryFile], {
63
+ stdio: 'inherit',
64
+ cwd: process.cwd(),
65
+ env: process.env,
66
+ });
67
+
68
+ child.on('exit', (code, signal) => {
69
+ process.exit(code ?? (signal ? 1 : 0));
70
+ });
71
+ }
package/cli/index.js CHANGED
@@ -1,57 +1,57 @@
1
1
  #!/usr/bin/env node
2
-
3
- /**
4
- * CLI entry point for te.js (tejas).
5
- * Usage: tejas fly [file] | tejas generate:docs [--ci] | tejas docs:on-push
6
- */
7
-
8
- import { runDocsCommand, runDocsCommandCI, runDocsOnPush } from './docs-command.js';
9
- import { runFlyCommand } from './fly-command.js';
10
-
11
- const command = process.argv[2];
12
- const ciFlag = process.argv.includes('--ci');
13
-
14
- if (command === 'fly') {
15
- try {
16
- runFlyCommand();
17
- } catch (err) {
18
- console.error(err?.message ?? err);
19
- process.exit(1);
20
- }
21
- } else if (command === 'docs:on-push') {
22
- runDocsOnPush().catch((err) => {
23
- console.error(err?.message ?? err);
24
- process.exit(1);
25
- });
26
- } else if (command === 'generate:docs') {
27
- if (ciFlag) {
28
- runDocsCommandCI().catch((err) => {
29
- console.error(err?.message ?? err);
30
- process.exit(1);
31
- });
32
- } else {
33
- runDocsCommand().catch((err) => {
34
- console.error(err?.message ?? err);
35
- process.exit(1);
36
- });
37
- }
38
- } else {
39
- console.log(`
40
- tejas - te.js framework CLI
41
-
42
- Usage: tejas <command> [options]
43
-
44
- Commands:
45
- fly [file] Start the Tejas server
46
- generate:docs [--ci] OpenAPI documentation generator (interactive or CI mode)
47
- docs:on-push Generate docs when pushing to production branch (use in pre-push hook)
48
-
49
- Examples:
50
- tejas fly
51
- tejas fly index.js
52
- tejas generate:docs
53
- tejas generate:docs --ci
54
- tejas docs:on-push
55
- `);
56
- process.exit(command ? 1 : 0);
57
- }
2
+
3
+ /**
4
+ * CLI entry point for te.js (tejas).
5
+ * Usage: tejas fly [file] | tejas generate:docs [--ci] | tejas docs:on-push
6
+ */
7
+
8
+ import { runDocsCommand, runDocsCommandCI, runDocsOnPush } from './docs-command.js';
9
+ import { runFlyCommand } from './fly-command.js';
10
+
11
+ const command = process.argv[2];
12
+ const ciFlag = process.argv.includes('--ci');
13
+
14
+ if (command === 'fly') {
15
+ try {
16
+ runFlyCommand();
17
+ } catch (err) {
18
+ console.error(err?.message ?? err);
19
+ process.exit(1);
20
+ }
21
+ } else if (command === 'docs:on-push') {
22
+ runDocsOnPush().catch((err) => {
23
+ console.error(err?.message ?? err);
24
+ process.exit(1);
25
+ });
26
+ } else if (command === 'generate:docs') {
27
+ if (ciFlag) {
28
+ runDocsCommandCI().catch((err) => {
29
+ console.error(err?.message ?? err);
30
+ process.exit(1);
31
+ });
32
+ } else {
33
+ runDocsCommand().catch((err) => {
34
+ console.error(err?.message ?? err);
35
+ process.exit(1);
36
+ });
37
+ }
38
+ } else {
39
+ console.log(`
40
+ tejas - te.js framework CLI
41
+
42
+ Usage: tejas <command> [options]
43
+
44
+ Commands:
45
+ fly [file] Start the Tejas server
46
+ generate:docs [--ci] OpenAPI documentation generator (interactive or CI mode)
47
+ docs:on-push Generate docs when pushing to production branch (use in pre-push hook)
48
+
49
+ Examples:
50
+ tejas fly
51
+ tejas fly index.js
52
+ tejas generate:docs
53
+ tejas generate:docs --ci
54
+ tejas docs:on-push
55
+ `);
56
+ process.exit(command ? 1 : 0);
57
+ }
package/database/index.js CHANGED
@@ -1,165 +1,165 @@
1
- import redis from './redis.js';
2
- import mongodb from './mongodb.js';
3
- import TejError from '../server/error.js';
4
- import TejLogger from 'tej-logger';
5
-
6
- const logger = new TejLogger('DatabaseManager');
7
-
8
- class DatabaseManager {
9
- static #instance = null;
10
- static #isInitializing = false;
11
-
12
- // Enhanced connection tracking with metadata
13
- #connections = new Map();
14
- #initializingConnections = new Map();
15
-
16
- // Helper method for sleeping
17
- async #sleep(ms) {
18
- return new Promise((resolve) => setTimeout(resolve, ms));
19
- }
20
-
21
- constructor() {
22
- if (DatabaseManager.#instance) {
23
- return DatabaseManager.#instance;
24
- }
25
-
26
- if (!DatabaseManager.#isInitializing) {
27
- throw new TejError(
28
- 500,
29
- 'Use DatabaseManager.getInstance() to get the instance',
30
- );
31
- }
32
-
33
- DatabaseManager.#isInitializing = false;
34
- DatabaseManager.#instance = this;
35
- }
36
-
37
- static getInstance() {
38
- if (!DatabaseManager.#instance) {
39
- DatabaseManager.#isInitializing = true;
40
- DatabaseManager.#instance = new DatabaseManager();
41
- }
42
- return DatabaseManager.#instance;
43
- }
44
-
45
- async initializeConnection(dbType, config) {
46
- const key = dbType.toLowerCase();
47
-
48
- // If a connection already exists for this config, return it
49
- if (this.#connections.has(key)) {
50
- return this.#connections.get(key).client;
51
- }
52
-
53
- // Set initializing flag
54
- this.#initializingConnections.set(key, true);
55
-
56
- let client;
57
- try {
58
- switch (key) {
59
- case 'redis':
60
- client = await redis.createConnection({
61
- isCluster: config.isCluster || false,
62
- options: config || {},
63
- });
64
- break;
65
- case 'mongodb':
66
- client = await mongodb.createConnection(config);
67
- break;
68
- default:
69
- throw new TejError(400, `Unsupported database type: ${dbType}`);
70
- }
71
-
72
- this.#connections.set(key, {
73
- type: dbType,
74
- client,
75
- config,
76
- });
77
-
78
- // Clear initializing flag
79
- this.#initializingConnections.delete(key);
80
-
81
- return client;
82
- } catch (error) {
83
- // Clear initializing flag on error
84
- this.#initializingConnections.delete(key);
85
- logger.error(`Failed to initialize ${dbType} connection:`, error);
86
- throw error;
87
- }
88
- }
89
-
90
- getConnection(dbType) {
91
- const key = dbType.toLowerCase();
92
- const connection = this.#connections.get(key);
93
- if (!connection) {
94
- throw new TejError(
95
- 404,
96
- `No connection found for ${dbType} with given config`,
97
- );
98
- }
99
- return connection.client;
100
- }
101
-
102
- async closeConnection(dbType, config) {
103
- const key = dbType.toLowerCase();
104
- if (!this.#connections.has(key)) {
105
- return;
106
- }
107
-
108
- try {
109
- const connection = this.#connections.get(key);
110
- switch (key) {
111
- case 'redis':
112
- await redis.closeConnection(connection.client);
113
- break;
114
- case 'mongodb':
115
- await mongodb.closeConnection(connection.client);
116
- break;
117
- }
118
-
119
- this.#connections.delete(key);
120
- } catch (error) {
121
- logger.error(`Error closing ${dbType} connection:`, error);
122
- throw error;
123
- }
124
- }
125
-
126
- /**
127
- * Close all database connections
128
- * @returns {Promise<void>}
129
- */
130
- async closeAllConnections() {
131
- const closePromises = [];
132
- for (const [key, connection] of this.#connections) {
133
- closePromises.push(
134
- this.closeConnection(connection.type, connection.config),
135
- );
136
- }
137
- await Promise.all(closePromises);
138
- this.#connections.clear();
139
- }
140
-
141
- /**
142
- * Get all active connections
143
- * @returns {Map<string, {type: string, client: any, config: Object}>}
144
- */
145
- getActiveConnections() {
146
- return new Map(this.#connections);
147
- }
148
-
149
- /**
150
- * Check if a connection exists or is being initialized
151
- * @param {string} dbType - Type of database
152
- * @param {Object} config - Database configuration
153
- * @returns {{ exists: boolean, initializing: boolean }}
154
- */
155
- hasConnection(dbType, config) {
156
- const key = dbType.toLowerCase();
157
- return {
158
- exists: this.#connections.has(key),
159
- initializing: this.#initializingConnections.has(key),
160
- };
161
- }
162
- }
163
-
164
- const dbManager = DatabaseManager.getInstance();
165
- export default dbManager;
1
+ import redis from './redis.js';
2
+ import mongodb from './mongodb.js';
3
+ import TejError from '../server/error.js';
4
+ import TejLogger from 'tej-logger';
5
+
6
+ const logger = new TejLogger('DatabaseManager');
7
+
8
+ class DatabaseManager {
9
+ static #instance = null;
10
+ static #isInitializing = false;
11
+
12
+ // Enhanced connection tracking with metadata
13
+ #connections = new Map();
14
+ #initializingConnections = new Map();
15
+
16
+ // Helper method for sleeping
17
+ async #sleep(ms) {
18
+ return new Promise((resolve) => setTimeout(resolve, ms));
19
+ }
20
+
21
+ constructor() {
22
+ if (DatabaseManager.#instance) {
23
+ return DatabaseManager.#instance;
24
+ }
25
+
26
+ if (!DatabaseManager.#isInitializing) {
27
+ throw new TejError(
28
+ 500,
29
+ 'Use DatabaseManager.getInstance() to get the instance',
30
+ );
31
+ }
32
+
33
+ DatabaseManager.#isInitializing = false;
34
+ DatabaseManager.#instance = this;
35
+ }
36
+
37
+ static getInstance() {
38
+ if (!DatabaseManager.#instance) {
39
+ DatabaseManager.#isInitializing = true;
40
+ DatabaseManager.#instance = new DatabaseManager();
41
+ }
42
+ return DatabaseManager.#instance;
43
+ }
44
+
45
+ async initializeConnection(dbType, config) {
46
+ const key = dbType.toLowerCase();
47
+
48
+ // If a connection already exists for this config, return it
49
+ if (this.#connections.has(key)) {
50
+ return this.#connections.get(key).client;
51
+ }
52
+
53
+ // Set initializing flag
54
+ this.#initializingConnections.set(key, true);
55
+
56
+ let client;
57
+ try {
58
+ switch (key) {
59
+ case 'redis':
60
+ client = await redis.createConnection({
61
+ isCluster: config.isCluster || false,
62
+ options: config || {},
63
+ });
64
+ break;
65
+ case 'mongodb':
66
+ client = await mongodb.createConnection(config);
67
+ break;
68
+ default:
69
+ throw new TejError(400, `Unsupported database type: ${dbType}`);
70
+ }
71
+
72
+ this.#connections.set(key, {
73
+ type: dbType,
74
+ client,
75
+ config,
76
+ });
77
+
78
+ // Clear initializing flag
79
+ this.#initializingConnections.delete(key);
80
+
81
+ return client;
82
+ } catch (error) {
83
+ // Clear initializing flag on error
84
+ this.#initializingConnections.delete(key);
85
+ logger.error(`Failed to initialize ${dbType} connection:`, error);
86
+ throw error;
87
+ }
88
+ }
89
+
90
+ getConnection(dbType) {
91
+ const key = dbType.toLowerCase();
92
+ const connection = this.#connections.get(key);
93
+ if (!connection) {
94
+ throw new TejError(
95
+ 404,
96
+ `No connection found for ${dbType} with given config`,
97
+ );
98
+ }
99
+ return connection.client;
100
+ }
101
+
102
+ async closeConnection(dbType, config) {
103
+ const key = dbType.toLowerCase();
104
+ if (!this.#connections.has(key)) {
105
+ return;
106
+ }
107
+
108
+ try {
109
+ const connection = this.#connections.get(key);
110
+ switch (key) {
111
+ case 'redis':
112
+ await redis.closeConnection(connection.client);
113
+ break;
114
+ case 'mongodb':
115
+ await mongodb.closeConnection(connection.client);
116
+ break;
117
+ }
118
+
119
+ this.#connections.delete(key);
120
+ } catch (error) {
121
+ logger.error(`Error closing ${dbType} connection:`, error);
122
+ throw error;
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Close all database connections
128
+ * @returns {Promise<void>}
129
+ */
130
+ async closeAllConnections() {
131
+ const closePromises = [];
132
+ for (const [key, connection] of this.#connections) {
133
+ closePromises.push(
134
+ this.closeConnection(connection.type, connection.config),
135
+ );
136
+ }
137
+ await Promise.all(closePromises);
138
+ this.#connections.clear();
139
+ }
140
+
141
+ /**
142
+ * Get all active connections
143
+ * @returns {Map<string, {type: string, client: any, config: Object}>}
144
+ */
145
+ getActiveConnections() {
146
+ return new Map(this.#connections);
147
+ }
148
+
149
+ /**
150
+ * Check if a connection exists or is being initialized
151
+ * @param {string} dbType - Type of database
152
+ * @param {Object} config - Database configuration
153
+ * @returns {{ exists: boolean, initializing: boolean }}
154
+ */
155
+ hasConnection(dbType, config) {
156
+ const key = dbType.toLowerCase();
157
+ return {
158
+ exists: this.#connections.has(key),
159
+ initializing: this.#initializingConnections.has(key),
160
+ };
161
+ }
162
+ }
163
+
164
+ const dbManager = DatabaseManager.getInstance();
165
+ export default dbManager;