@ezetgalaxy/titan 26.9.0 → 26.9.2
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 +39 -17
- package/index.js +227 -120
- package/package.json +17 -5
- package/templates/{js → common}/app/titan.d.ts +1 -1
- package/templates/{rust → rust-js}/package.json +1 -1
- package/templates/rust-ts/app/actions/hello.ts +10 -4
- package/templates/rust-ts/app/app.ts +1 -1
- package/templates/rust-ts/titan/bundle.js +15 -9
- package/templates/rust-ts/titan/dev.js +2 -2
- package/templates/rust-ts/titan/runtime.d.ts +1 -0
- package/templates/rust-ts/titan/runtime.js +1 -0
- package/templates/rust-ts/titan/titan.d.ts +117 -0
- package/templates/rust-ts/titan/titan.js +95 -95
- package/templates/ts/app/actions/hello.ts +2 -0
- package/templates/ts/app/app.ts +1 -1
- package/templates/ts/titan/builder.js +121 -0
- package/templates/ts/titan/bundle.js +9 -11
- package/templates/ts/titan/dev.js +2 -2
- package/templates/ts/titan/runtime.d.ts +1 -0
- package/templates/ts/titan/runtime.js +1 -0
- package/templates/ts/titan/titan.d.ts +117 -0
- package/templates/ts/titan/titan.js +95 -95
- package/titanpl-sdk/README.md +4 -4
- package/titanpl-sdk/bin/run.js +74 -77
- package/titanpl-sdk/package.json +1 -1
- package/templates/rust/Dockerfile +0 -66
- package/templates/rust/_dockerignore +0 -3
- package/templates/rust/_gitignore +0 -38
- package/templates/rust/app/titan.d.ts +0 -101
- package/templates/rust-ts/Dockerfile +0 -66
- package/templates/rust-ts/_dockerignore +0 -3
- package/templates/rust-ts/_gitignore +0 -38
- package/templates/rust-ts/app/titan.d.ts +0 -101
- package/templates/ts/Dockerfile +0 -66
- package/templates/ts/_dockerignore +0 -3
- package/templates/ts/_gitignore +0 -38
- package/templates/ts/app/titan.d.ts +0 -102
- /package/templates/{js → common}/Dockerfile +0 -0
- /package/templates/{js → common}/_dockerignore +0 -0
- /package/templates/{js → common}/_gitignore +0 -0
- /package/templates/{rust → rust-js}/app/actions/hello.js +0 -0
- /package/templates/{rust → rust-js}/app/actions/rust_hello.rs +0 -0
- /package/templates/{rust → rust-js}/app/app.js +0 -0
- /package/templates/{rust → rust-js}/jsconfig.json +0 -0
- /package/templates/{rust → rust-js}/server/Cargo.lock +0 -0
- /package/templates/{rust → rust-js}/server/Cargo.toml +0 -0
- /package/templates/{rust → rust-js}/server/src/action_management.rs +0 -0
- /package/templates/{rust → rust-js}/server/src/errors.rs +0 -0
- /package/templates/{rust → rust-js}/server/src/extensions.rs +0 -0
- /package/templates/{rust → rust-js}/server/src/main.rs +0 -0
- /package/templates/{rust → rust-js}/server/src/utils.rs +0 -0
- /package/templates/{rust → rust-js}/titan/bundle.js +0 -0
- /package/templates/{rust → rust-js}/titan/dev.js +0 -0
- /package/templates/{rust → rust-js}/titan/titan.js +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ezetgalaxy/titan",
|
|
3
|
-
"version": "26.9.
|
|
3
|
+
"version": "26.9.2",
|
|
4
4
|
"description": "Titan Planet is a JavaScript-first backend framework that embeds JS actions into a Rust + Axum server and ships as a single native binary. Routes are compiled to static metadata; only actions run in the embedded JS runtime. No Node.js. No event loop in production.",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "ezetgalaxy",
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
"files": [
|
|
14
14
|
"index.js",
|
|
15
15
|
"templates/",
|
|
16
|
-
"titan",
|
|
17
16
|
"titanpl-sdk",
|
|
18
17
|
"README.md"
|
|
19
18
|
],
|
|
@@ -43,13 +42,26 @@
|
|
|
43
42
|
"super-backend"
|
|
44
43
|
],
|
|
45
44
|
"scripts": {
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
45
|
+
"init": "rm -rf build && node index.js init build",
|
|
46
|
+
"build": "cd build && node ../index.js build",
|
|
47
|
+
"dev": "cd build && node ../index.js dev",
|
|
48
|
+
"start": "cd build && node ../index.js start",
|
|
49
|
+
"help": "cd build && node ../index.js help",
|
|
50
|
+
"update": "cd build && node ../index.js update",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"test:watch": "vitest",
|
|
53
|
+
"test:coverage": "vitest run --coverage",
|
|
54
|
+
"test:cov": "vitest run --coverage",
|
|
55
|
+
"test:ui": "vitest --ui"
|
|
49
56
|
},
|
|
50
57
|
"dependencies": {
|
|
51
58
|
"chokidar": "^5.0.0",
|
|
52
59
|
"esbuild": "^0.27.2",
|
|
53
60
|
"prompts": "^2.4.2"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@vitest/coverage-v8": "^4.0.17",
|
|
64
|
+
"@vitest/ui": "^4.0.17",
|
|
65
|
+
"vitest": "^4.0.17"
|
|
54
66
|
}
|
|
55
67
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
message: `Hello from Titan ${req.body.name}`,
|
|
4
|
-
};
|
|
1
|
+
interface HelloResponse {
|
|
2
|
+
message: string;
|
|
5
3
|
}
|
|
4
|
+
|
|
5
|
+
import { defineAction } from "../../titan/runtime";
|
|
6
|
+
|
|
7
|
+
export const hello = defineAction((req): HelloResponse => {
|
|
8
|
+
return {
|
|
9
|
+
message: `Hello from Titan ${req.body.name || "World"}`,
|
|
10
|
+
};
|
|
11
|
+
});
|
|
@@ -2,19 +2,19 @@ import fs from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import esbuild from "esbuild";
|
|
4
4
|
|
|
5
|
-
const root = process.cwd();
|
|
6
|
-
const actionsDir = path.join(root, "app", "actions");
|
|
7
|
-
const outDir = path.join(root, "server", "actions");
|
|
8
|
-
const rustOutDir = path.join(root, "server", "src", "actions_rust");
|
|
9
|
-
|
|
10
5
|
export async function bundle() {
|
|
6
|
+
const root = process.cwd();
|
|
7
|
+
const actionsDir = path.join(root, "app", "actions");
|
|
8
|
+
const outDir = path.join(root, "server", "actions");
|
|
9
|
+
const rustOutDir = path.join(root, "server", "src", "actions_rust");
|
|
10
|
+
|
|
11
11
|
const start = Date.now();
|
|
12
|
-
await bundleJs();
|
|
13
|
-
await bundleRust();
|
|
12
|
+
await bundleJs(actionsDir, outDir);
|
|
13
|
+
await bundleRust(rustOutDir, actionsDir);
|
|
14
14
|
// console.log(`[Titan] Bundle finished in ${((Date.now() - start) / 1000).toFixed(2)}s`);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
async function bundleJs() {
|
|
17
|
+
async function bundleJs(actionsDir, outDir) {
|
|
18
18
|
// console.log("[Titan] Bundling JS actions...");
|
|
19
19
|
|
|
20
20
|
fs.mkdirSync(outDir, { recursive: true });
|
|
@@ -77,9 +77,15 @@ async function bundleJs() {
|
|
|
77
77
|
// console.log("[Titan] JS Bundling finished.");
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
export async function bundleRust() {
|
|
80
|
+
export async function bundleRust(rustOutDir, actionsDir) {
|
|
81
81
|
// console.log("[Titan] Bundling Rust actions...");
|
|
82
82
|
|
|
83
|
+
// Fallback if called directly (though typically called via bundle)
|
|
84
|
+
const root = process.cwd();
|
|
85
|
+
if (!actionsDir) actionsDir = path.join(root, "app", "actions");
|
|
86
|
+
if (!rustOutDir) rustOutDir = path.join(root, "server", "src", "actions_rust");
|
|
87
|
+
|
|
88
|
+
|
|
83
89
|
if (!fs.existsSync(rustOutDir)) {
|
|
84
90
|
fs.mkdirSync(rustOutDir, { recursive: true });
|
|
85
91
|
}
|
|
@@ -231,11 +231,11 @@ async function rebuild() {
|
|
|
231
231
|
bundle: true,
|
|
232
232
|
platform: "node",
|
|
233
233
|
format: "esm",
|
|
234
|
-
|
|
234
|
+
external: ["fs", "path", "esbuild", "chokidar", "typescript"],
|
|
235
235
|
logLevel: "silent"
|
|
236
236
|
});
|
|
237
237
|
|
|
238
|
-
execSync(`node "${compiledApp}"`, { stdio: "
|
|
238
|
+
execSync(`node "${compiledApp}"`, { stdio: "inherit" });
|
|
239
239
|
} else {
|
|
240
240
|
execSync("node app/app.js", { stdio: "ignore" });
|
|
241
241
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function defineAction<Req = any, Res = any>(handler: (req: Req) => Res): (req: Req) => Res;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const defineAction = (handler) => handler;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
|
|
2
|
+
// -- Module Definitions (for imports from "titan") --
|
|
3
|
+
|
|
4
|
+
export interface RouteHandler {
|
|
5
|
+
reply(value: any): void;
|
|
6
|
+
action(name: string): void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface TitanBuilder {
|
|
10
|
+
get(route: string): RouteHandler;
|
|
11
|
+
post(route: string): RouteHandler;
|
|
12
|
+
log(module: string, msg: string): void;
|
|
13
|
+
start(port?: number, msg?: string): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// The default export from titan.js is the Builder
|
|
17
|
+
declare const builder: TitanBuilder;
|
|
18
|
+
export default builder;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Define a Titan Action with type inference.
|
|
22
|
+
*/
|
|
23
|
+
export declare function defineAction<T>(actionFn: (req: TitanRequest) => T): (req: TitanRequest) => T;
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
// -- Global Definitions (Runtime Environment) --
|
|
27
|
+
|
|
28
|
+
declare global {
|
|
29
|
+
/**
|
|
30
|
+
* The Titan Request Object passed to actions.
|
|
31
|
+
*/
|
|
32
|
+
interface TitanRequest {
|
|
33
|
+
body: any;
|
|
34
|
+
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
35
|
+
path: string;
|
|
36
|
+
headers: {
|
|
37
|
+
host?: string;
|
|
38
|
+
"content-type"?: string;
|
|
39
|
+
"user-agent"?: string;
|
|
40
|
+
authorization?: string;
|
|
41
|
+
[key: string]: string | undefined;
|
|
42
|
+
};
|
|
43
|
+
params: Record<string, string>;
|
|
44
|
+
query: Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface DbConnection {
|
|
48
|
+
/**
|
|
49
|
+
* Execute a SQL query.
|
|
50
|
+
* @param sql The SQL query string.
|
|
51
|
+
* @param params (Optional) Parameters for the query ($1, $2, etc).
|
|
52
|
+
*/
|
|
53
|
+
query(sql: string, params?: any[]): any[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Global defineAction (available without import in runtime, though imports are preferred in TS)
|
|
58
|
+
*/
|
|
59
|
+
function defineAction<T>(actionFn: (req: TitanRequest) => T): (req: TitanRequest) => T;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Global Request Object
|
|
63
|
+
* Available automatically in actions.
|
|
64
|
+
*/
|
|
65
|
+
var req: TitanRequest;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Titan Runtime Utilities
|
|
69
|
+
* (Available globally in the runtime, e.g. inside actions)
|
|
70
|
+
*/
|
|
71
|
+
const t: {
|
|
72
|
+
/**
|
|
73
|
+
* Log messages to the server console with Titan formatting.
|
|
74
|
+
*/
|
|
75
|
+
log(...args: any[]): void;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Read a file contents as string.
|
|
79
|
+
* @param path Relative path to the file from project root.
|
|
80
|
+
*/
|
|
81
|
+
read(path: string): string;
|
|
82
|
+
|
|
83
|
+
fetch(url: string, options?: {
|
|
84
|
+
method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
85
|
+
headers?: Record<string, string>;
|
|
86
|
+
body?: string | object;
|
|
87
|
+
}): {
|
|
88
|
+
ok: boolean;
|
|
89
|
+
status?: number;
|
|
90
|
+
body?: string;
|
|
91
|
+
error?: string;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
jwt: {
|
|
95
|
+
sign(
|
|
96
|
+
payload: object,
|
|
97
|
+
secret: string,
|
|
98
|
+
options?: { expiresIn?: string | number }
|
|
99
|
+
): string;
|
|
100
|
+
verify(token: string, secret: string): any;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
password: {
|
|
104
|
+
hash(password: string): string;
|
|
105
|
+
verify(password: string, hash: string): boolean;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
db: {
|
|
109
|
+
connect(url: string): DbConnection;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Titan Validator (Zod-compatible)
|
|
114
|
+
*/
|
|
115
|
+
valid: any;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { bundle } from "./bundle.js";
|
|
1
2
|
import fs from "fs";
|
|
2
3
|
import path from "path";
|
|
3
|
-
|
|
4
|
+
|
|
5
|
+
export * from "./runtime.js";
|
|
4
6
|
|
|
5
7
|
const cyan = (t) => `\x1b[36m${t}\x1b[0m`;
|
|
6
8
|
const green = (t) => `\x1b[32m${t}\x1b[0m`;
|
|
@@ -10,34 +12,33 @@ const dynamicRoutes = {};
|
|
|
10
12
|
const actionMap = {};
|
|
11
13
|
|
|
12
14
|
function addRoute(method, route) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
};
|
|
15
|
+
const key = `${method.toUpperCase()}:${route}`;
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
reply(value) {
|
|
19
|
+
routes[key] = {
|
|
20
|
+
type: typeof value === "object" ? "json" : "text",
|
|
21
|
+
value
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
action(name) {
|
|
26
|
+
if (route.includes(":")) {
|
|
27
|
+
if (!dynamicRoutes[method]) dynamicRoutes[method] = [];
|
|
28
|
+
dynamicRoutes[method].push({
|
|
29
|
+
method: method.toUpperCase(),
|
|
30
|
+
pattern: route,
|
|
31
|
+
action: name
|
|
32
|
+
});
|
|
33
|
+
} else {
|
|
34
|
+
routes[key] = {
|
|
35
|
+
type: "action",
|
|
36
|
+
value: name
|
|
37
|
+
};
|
|
38
|
+
actionMap[key] = name;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
/**
|
|
@@ -50,73 +51,72 @@ function addRoute(method, route) {
|
|
|
50
51
|
* Titan App Builder
|
|
51
52
|
*/
|
|
52
53
|
const t = {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Define a GET route
|
|
56
|
+
* @param {string} route
|
|
57
|
+
* @returns {RouteHandler}
|
|
58
|
+
*/
|
|
59
|
+
get(route) {
|
|
60
|
+
return addRoute("GET", route);
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Define a POST route
|
|
65
|
+
* @param {string} route
|
|
66
|
+
* @returns {RouteHandler}
|
|
67
|
+
*/
|
|
68
|
+
post(route) {
|
|
69
|
+
return addRoute("POST", route);
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
log(module, msg) {
|
|
73
|
+
console.log(`[\x1b[35m${module}\x1b[0m] ${msg}`);
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Start the Titan Server
|
|
78
|
+
* @param {number} [port=3000]
|
|
79
|
+
* @param {string} [msg=""]
|
|
80
|
+
*/
|
|
81
|
+
async start(port = 3000, msg = "") {
|
|
82
|
+
try {
|
|
83
|
+
console.log(cyan("[Titan] Preparing runtime..."));
|
|
84
|
+
await bundle();
|
|
85
|
+
|
|
86
|
+
const base = path.join(process.cwd(), "server");
|
|
87
|
+
if (!fs.existsSync(base)) {
|
|
88
|
+
fs.mkdirSync(base, { recursive: true });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const routesPath = path.join(base, "routes.json");
|
|
92
|
+
const actionMapPath = path.join(base, "action_map.json");
|
|
93
|
+
|
|
94
|
+
fs.writeFileSync(
|
|
95
|
+
routesPath,
|
|
96
|
+
JSON.stringify(
|
|
97
|
+
{
|
|
98
|
+
__config: { port },
|
|
99
|
+
routes,
|
|
100
|
+
__dynamic_routes: Object.values(dynamicRoutes).flat()
|
|
101
|
+
},
|
|
102
|
+
null,
|
|
103
|
+
2
|
|
104
|
+
)
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
fs.writeFileSync(
|
|
108
|
+
actionMapPath,
|
|
109
|
+
JSON.stringify(actionMap, null, 2)
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
console.log(green("✔ Titan metadata written successfully"));
|
|
113
|
+
if (msg) console.log(cyan(msg));
|
|
114
|
+
|
|
115
|
+
} catch (e) {
|
|
116
|
+
console.error(`\x1b[31m[Titan] Build Error: ${e.message}\x1b[0m`);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
117
119
|
}
|
|
118
|
-
}
|
|
119
120
|
};
|
|
120
121
|
|
|
121
|
-
|
|
122
122
|
export default t;
|
package/templates/ts/app/app.ts
CHANGED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { bundle } from "./bundle.js";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
const cyan = (t) => `\x1b[36m${t}\x1b[0m`;
|
|
6
|
+
const green = (t) => `\x1b[32m${t}\x1b[0m`;
|
|
7
|
+
|
|
8
|
+
const routes = {};
|
|
9
|
+
const dynamicRoutes = {};
|
|
10
|
+
const actionMap = {};
|
|
11
|
+
|
|
12
|
+
function addRoute(method, route) {
|
|
13
|
+
const key = `${method.toUpperCase()}:${route}`;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
reply(value) {
|
|
18
|
+
routes[key] = {
|
|
19
|
+
type: typeof value === "object" ? "json" : "text",
|
|
20
|
+
value
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
action(name) {
|
|
25
|
+
if (route.includes(":")) {
|
|
26
|
+
if (!dynamicRoutes[method]) dynamicRoutes[method] = [];
|
|
27
|
+
dynamicRoutes[method].push({
|
|
28
|
+
method: method.toUpperCase(),
|
|
29
|
+
pattern: route,
|
|
30
|
+
action: name
|
|
31
|
+
});
|
|
32
|
+
} else {
|
|
33
|
+
routes[key] = {
|
|
34
|
+
type: "action",
|
|
35
|
+
value: name
|
|
36
|
+
};
|
|
37
|
+
actionMap[key] = name;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @typedef {Object} RouteHandler
|
|
45
|
+
* @property {(value: any) => void} reply - Send a direct response
|
|
46
|
+
* @property {(name: string) => void} action - Bind to a server-side action
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Titan App Builder
|
|
51
|
+
*/
|
|
52
|
+
const t = {
|
|
53
|
+
/**
|
|
54
|
+
* Define a GET route
|
|
55
|
+
* @param {string} route
|
|
56
|
+
* @returns {RouteHandler}
|
|
57
|
+
*/
|
|
58
|
+
get(route) {
|
|
59
|
+
return addRoute("GET", route);
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Define a POST route
|
|
64
|
+
* @param {string} route
|
|
65
|
+
* @returns {RouteHandler}
|
|
66
|
+
*/
|
|
67
|
+
post(route) {
|
|
68
|
+
return addRoute("POST", route);
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
log(module, msg) {
|
|
72
|
+
console.log(`[\x1b[35m${module}\x1b[0m] ${msg}`);
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Start the Titan Server
|
|
77
|
+
* @param {number} [port=3000]
|
|
78
|
+
* @param {string} [msg=""]
|
|
79
|
+
*/
|
|
80
|
+
async start(port = 3000, msg = "") {
|
|
81
|
+
try {
|
|
82
|
+
console.log(cyan("[Titan] Preparing runtime..."));
|
|
83
|
+
await bundle();
|
|
84
|
+
|
|
85
|
+
const base = path.join(process.cwd(), "server");
|
|
86
|
+
if (!fs.existsSync(base)) {
|
|
87
|
+
fs.mkdirSync(base, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const routesPath = path.join(base, "routes.json");
|
|
91
|
+
const actionMapPath = path.join(base, "action_map.json");
|
|
92
|
+
|
|
93
|
+
fs.writeFileSync(
|
|
94
|
+
routesPath,
|
|
95
|
+
JSON.stringify(
|
|
96
|
+
{
|
|
97
|
+
__config: { port },
|
|
98
|
+
routes,
|
|
99
|
+
__dynamic_routes: Object.values(dynamicRoutes).flat()
|
|
100
|
+
},
|
|
101
|
+
null,
|
|
102
|
+
2
|
|
103
|
+
)
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
fs.writeFileSync(
|
|
107
|
+
actionMapPath,
|
|
108
|
+
JSON.stringify(actionMap, null, 2)
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
console.log(green("✔ Titan metadata written successfully"));
|
|
112
|
+
if (msg) console.log(cyan(msg));
|
|
113
|
+
|
|
114
|
+
} catch (e) {
|
|
115
|
+
console.error(`\x1b[31m[Titan] Build Error: ${e.message}\x1b[0m`);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export default t;
|
|
@@ -2,27 +2,25 @@ import fs from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import esbuild from "esbuild";
|
|
4
4
|
|
|
5
|
-
const root = process.cwd();
|
|
6
|
-
const actionsDir = path.join(root, "app", "actions");
|
|
7
|
-
const outDir = path.join(root, "server", "actions");
|
|
8
|
-
|
|
9
5
|
export async function bundle() {
|
|
6
|
+
const root = process.cwd();
|
|
7
|
+
const actionsDir = path.join(root, "app", "actions");
|
|
8
|
+
const outDir = path.join(root, "server", "actions");
|
|
9
|
+
|
|
10
10
|
const start = Date.now();
|
|
11
|
-
await bundleJs();
|
|
11
|
+
await bundleJs(actionsDir, outDir);
|
|
12
12
|
// console.log(`[Titan] Bundle finished in ${((Date.now() - start) / 1000).toFixed(2)}s`);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
async function bundleJs() {
|
|
15
|
+
async function bundleJs(actionsDir, outDir) {
|
|
16
16
|
// console.log("[Titan] Bundling JS actions...");
|
|
17
17
|
|
|
18
18
|
fs.mkdirSync(outDir, { recursive: true });
|
|
19
19
|
|
|
20
20
|
// Clean old bundles
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
fs.unlinkSync(path.join(outDir, file));
|
|
25
|
-
}
|
|
21
|
+
const oldFiles = fs.readdirSync(outDir);
|
|
22
|
+
for (const file of oldFiles) {
|
|
23
|
+
fs.unlinkSync(path.join(outDir, file));
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
const files = fs.readdirSync(actionsDir).filter(f => f.endsWith(".js") || f.endsWith(".ts"));
|
|
@@ -231,11 +231,11 @@ async function rebuild() {
|
|
|
231
231
|
bundle: true,
|
|
232
232
|
platform: "node",
|
|
233
233
|
format: "esm",
|
|
234
|
-
|
|
234
|
+
external: ["fs", "path", "esbuild", "chokidar", "typescript"],
|
|
235
235
|
logLevel: "silent"
|
|
236
236
|
});
|
|
237
237
|
|
|
238
|
-
execSync(`node "${compiledApp}"`, { stdio: "
|
|
238
|
+
execSync(`node "${compiledApp}"`, { stdio: "inherit" });
|
|
239
239
|
} else {
|
|
240
240
|
execSync("node app/app.js", { stdio: "ignore" });
|
|
241
241
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function defineAction<Req = any, Res = any>(handler: (req: Req) => Res): (req: Req) => Res;
|