kastrick 1.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.
- package/README.md +38 -0
- package/examples/01-hello-world/api/hello.ts +19 -0
- package/examples/02-users-api/README.md +39 -0
- package/examples/02-users-api/api/users/[id].ts +80 -0
- package/examples/02-users-api/api/users/index.ts +50 -0
- package/examples/03-configuration/README.md +39 -0
- package/examples/03-configuration/kastrick.config.json +22 -0
- package/examples/03-configuration/tsconfig.json +20 -0
- package/examples/README.md +48 -0
- package/lib/cli/compile.d.ts +5 -0
- package/lib/cli/compile.d.ts.map +1 -0
- package/lib/cli/compile.js +25 -0
- package/lib/cli/compile.js.map +1 -0
- package/lib/cli/dev.d.ts +5 -0
- package/lib/cli/dev.d.ts.map +1 -0
- package/lib/cli/dev.js +79 -0
- package/lib/cli/dev.js.map +1 -0
- package/lib/cli/index.d.ts +3 -0
- package/lib/cli/index.d.ts.map +1 -0
- package/lib/cli/index.js +63 -0
- package/lib/cli/index.js.map +1 -0
- package/lib/cli/serve.d.ts +5 -0
- package/lib/cli/serve.d.ts.map +1 -0
- package/lib/cli/serve.js +106 -0
- package/lib/cli/serve.js.map +1 -0
- package/lib/core/compiler.d.ts +29 -0
- package/lib/core/compiler.d.ts.map +1 -0
- package/lib/core/compiler.js +153 -0
- package/lib/core/compiler.js.map +1 -0
- package/lib/core/router.d.ts +31 -0
- package/lib/core/router.d.ts.map +1 -0
- package/lib/core/router.js +106 -0
- package/lib/core/router.js.map +1 -0
- package/lib/core/scanner.d.ts +29 -0
- package/lib/core/scanner.d.ts.map +1 -0
- package/lib/core/scanner.js +88 -0
- package/lib/core/scanner.js.map +1 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +35 -0
- package/lib/index.js.map +1 -0
- package/lib/server/expressServer.d.ts +28 -0
- package/lib/server/expressServer.d.ts.map +1 -0
- package/lib/server/expressServer.js +96 -0
- package/lib/server/expressServer.js.map +1 -0
- package/package.json +34 -0
- package/src/cli/compile.ts +27 -0
- package/src/cli/dev.ts +49 -0
- package/src/cli/index.ts +64 -0
- package/src/cli/serve.ts +81 -0
- package/src/core/compiler.ts +147 -0
- package/src/core/router.ts +88 -0
- package/src/core/scanner.ts +72 -0
- package/src/index.ts +38 -0
- package/src/server/expressServer.ts +107 -0
- package/templates/tsconfig.json +20 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
|
|
4
|
+
export interface FileInfo {
|
|
5
|
+
filePath: string;
|
|
6
|
+
relativePath: string;
|
|
7
|
+
name: string;
|
|
8
|
+
isDirectory: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ApiFile {
|
|
12
|
+
path: string;
|
|
13
|
+
relativePath: string;
|
|
14
|
+
content?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Scanner - scans the /api folder and extracts file structure
|
|
19
|
+
*/
|
|
20
|
+
export class Scanner {
|
|
21
|
+
private apiDir: string;
|
|
22
|
+
|
|
23
|
+
constructor(rootDir: string = process.cwd()) {
|
|
24
|
+
this.apiDir = path.join(rootDir, "api");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Check if api folder exists
|
|
29
|
+
*/
|
|
30
|
+
apiDirExists(): boolean {
|
|
31
|
+
return fs.existsSync(this.apiDir);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Recursively scan /api folder
|
|
36
|
+
*/
|
|
37
|
+
scanApiFolder(): ApiFile[] {
|
|
38
|
+
if (!this.apiDirExists()) {
|
|
39
|
+
console.warn(`ā ļø No /api folder found at ${this.apiDir}`);
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const files: ApiFile[] = [];
|
|
44
|
+
this.scanDirectory(this.apiDir, "", files);
|
|
45
|
+
return files;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private scanDirectory(dir: string, relativePrefix: string, files: ApiFile[]): void {
|
|
49
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
50
|
+
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
if (entry.name.startsWith(".")) continue;
|
|
53
|
+
|
|
54
|
+
const fullPath = path.join(dir, entry.name);
|
|
55
|
+
const relativePath = path.join(relativePrefix, entry.name);
|
|
56
|
+
|
|
57
|
+
if (entry.isDirectory()) {
|
|
58
|
+
this.scanDirectory(fullPath, relativePath, files);
|
|
59
|
+
} else if (this.isApiFile(entry.name)) {
|
|
60
|
+
files.push({
|
|
61
|
+
path: fullPath,
|
|
62
|
+
relativePath: relativePath,
|
|
63
|
+
content: fs.readFileSync(fullPath, "utf-8"),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private isApiFile(filename: string): boolean {
|
|
70
|
+
return /\.(js|ts)$/.test(filename) && !filename.endsWith(".d.ts");
|
|
71
|
+
}
|
|
72
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Kastrick API Logic Package
|
|
2
|
+
// Main entry point
|
|
3
|
+
|
|
4
|
+
export interface ApiResponse<T> {
|
|
5
|
+
success: boolean;
|
|
6
|
+
data?: T;
|
|
7
|
+
error?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class ApiHandler {
|
|
11
|
+
constructor(private baseUrl: string) {}
|
|
12
|
+
|
|
13
|
+
async request<T>(endpoint: string, options?: RequestInit): Promise<ApiResponse<T>> {
|
|
14
|
+
try {
|
|
15
|
+
const response = await fetch(`${this.baseUrl}${endpoint}`, options);
|
|
16
|
+
const data: any = await response.json();
|
|
17
|
+
|
|
18
|
+
if (!response.ok) {
|
|
19
|
+
return {
|
|
20
|
+
success: false,
|
|
21
|
+
error: (data?.error || 'Request failed') as string,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
success: true,
|
|
27
|
+
data: data as T,
|
|
28
|
+
};
|
|
29
|
+
} catch (error) {
|
|
30
|
+
return {
|
|
31
|
+
success: false,
|
|
32
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default ApiHandler;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { ApiRoute, Router } from "../core/router";
|
|
4
|
+
import { ApiFile } from "../core/scanner";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Express Server - Dev server for local API testing
|
|
8
|
+
*/
|
|
9
|
+
export class ExpressServer {
|
|
10
|
+
private app: express.Application;
|
|
11
|
+
private port: number;
|
|
12
|
+
private router: Router;
|
|
13
|
+
private loadedModules: Map<string, any> = new Map();
|
|
14
|
+
|
|
15
|
+
constructor(port: number = 3000) {
|
|
16
|
+
this.app = express();
|
|
17
|
+
this.port = port;
|
|
18
|
+
this.router = new Router();
|
|
19
|
+
this.setupMiddleware();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private setupMiddleware(): void {
|
|
23
|
+
this.app.use(express.json());
|
|
24
|
+
this.app.use(express.urlencoded({ extended: true }));
|
|
25
|
+
|
|
26
|
+
// Simple logging middleware
|
|
27
|
+
this.app.use((req, res, next) => {
|
|
28
|
+
console.log(`š” ${req.method} ${req.path}`);
|
|
29
|
+
next();
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Register routes from API files
|
|
35
|
+
*/
|
|
36
|
+
registerRoutes(files: ApiFile[]): void {
|
|
37
|
+
const routes = this.router.generateRoutes(files);
|
|
38
|
+
|
|
39
|
+
for (const route of routes) {
|
|
40
|
+
const method = route.method.toLowerCase() as keyof express.Application;
|
|
41
|
+
const filePath = route.file;
|
|
42
|
+
const content = files.find((f) => f.relativePath === filePath)?.content || "";
|
|
43
|
+
|
|
44
|
+
this.app[method](route.path, this.createHandler(filePath, route.method, content));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log(`š” Registered ${routes.length} routes`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private createHandler(filePath: string, method: string, content: string) {
|
|
51
|
+
return async (req: express.Request, res: express.Response) => {
|
|
52
|
+
try {
|
|
53
|
+
// Parse and execute handler
|
|
54
|
+
const fn = this.parseHandler(content, method);
|
|
55
|
+
if (!fn) {
|
|
56
|
+
return res.status(404).json({ error: `${method} handler not found` });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const result = await fn(req, { params: req.params });
|
|
60
|
+
res.status(result.status || 200).json(result.body !== undefined ? result.body : result);
|
|
61
|
+
} catch (err: any) {
|
|
62
|
+
console.error(`ā Handler error in ${filePath}:`, err.message);
|
|
63
|
+
res.status(500).json({ error: err.message || "Internal server error" });
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private parseHandler(content: string, method: string): any {
|
|
69
|
+
try {
|
|
70
|
+
// Extract the function from the file content
|
|
71
|
+
const moduleExports: any = {};
|
|
72
|
+
|
|
73
|
+
// Create a minimal module context
|
|
74
|
+
const module = { exports: moduleExports };
|
|
75
|
+
const exportFn = (key: string, fn: any) => {
|
|
76
|
+
moduleExports[key] = fn;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Execute the file content in a controlled context
|
|
80
|
+
const code = `(function(exports, require, module, __filename, __dirname) { ${content} return module.exports; })`;
|
|
81
|
+
const fn = eval(code);
|
|
82
|
+
const result = fn(moduleExports, require, module, "", "");
|
|
83
|
+
|
|
84
|
+
return result[method];
|
|
85
|
+
} catch (err) {
|
|
86
|
+
console.error("Error parsing handler:", err);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Start the dev server
|
|
93
|
+
*/
|
|
94
|
+
start(): void {
|
|
95
|
+
this.app.listen(this.port, () => {
|
|
96
|
+
console.log(`\nš Kastrick dev server running on http://localhost:${this.port}\n`);
|
|
97
|
+
console.log(`š Watching for changes in /api folder...\n`);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get Express app instance
|
|
103
|
+
*/
|
|
104
|
+
getApp(): express.Application {
|
|
105
|
+
return this.app;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"types": ["node"],
|
|
7
|
+
"outDir": "./output",
|
|
8
|
+
"rootDir": "./api",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"declaration": true,
|
|
15
|
+
"sourceMap": false,
|
|
16
|
+
"noEmit": false
|
|
17
|
+
},
|
|
18
|
+
"include": ["api"],
|
|
19
|
+
"exclude": ["node_modules", "output"]
|
|
20
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"types": ["node"],
|
|
7
|
+
"outDir": "./lib",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"declaration": true,
|
|
15
|
+
"declarationMap": true,
|
|
16
|
+
"sourceMap": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src"],
|
|
19
|
+
"exclude": ["node_modules"]
|
|
20
|
+
}
|