@ezetgalaxy/titan 26.9.0 → 26.9.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.
- package/README.md +22 -12
- package/index.js +57 -15
- package/package.json +1 -2
- 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/titan.d.ts +117 -0
- package/templates/rust-ts/titan/titan.js +95 -95
- package/templates/ts/Dockerfile +16 -42
- 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.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/app/titan.d.ts +0 -101
- package/templates/ts/app/titan.d.ts +0 -102
- /package/templates/{rust → rust-js}/Dockerfile +0 -0
- /package/templates/{rust → rust-js}/_dockerignore +0 -0
- /package/templates/{rust → rust-js}/_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-ts → rust-js}/app/titan.d.ts +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/README.md
CHANGED
|
@@ -76,7 +76,7 @@ titan dev
|
|
|
76
76
|
|
|
77
77
|
You'll see the Titan Dev Server spin up:
|
|
78
78
|
```
|
|
79
|
-
Titan Planet v26.9.
|
|
79
|
+
Titan Planet v26.9.1 [ Dev Mode ]
|
|
80
80
|
|
|
81
81
|
Type: Rust + TS Actions
|
|
82
82
|
Hot Reload: Enabled
|
|
@@ -93,34 +93,45 @@ You'll see the Titan Dev Server spin up:
|
|
|
93
93
|
|
|
94
94
|
Titan is unique because it allows you to write endpoints in **JavaScript, TypeScript, and Rust** within the same project.
|
|
95
95
|
|
|
96
|
+
| Feature | Status | Notes |
|
|
97
|
+
| :--- | :--- | :--- |
|
|
98
|
+
| **Standard JavaScript** | ✅ Stable | Production Ready |
|
|
99
|
+
| **Standard TypeScript** | 🚧 Beta | **Ready for Dev**, Production Under Testing |
|
|
100
|
+
| **Rust + JS (Hybrid)** | 🧪 Experimental | **Dev Only**, Production Under Testing |
|
|
101
|
+
| **Rust + TS (Hybrid)** | 🧪 Experimental | **Dev Only**, Production Under Testing |
|
|
102
|
+
|
|
96
103
|
### 🔵 TypeScript Actions (`app/actions/hello.ts`)
|
|
97
104
|
Fully typed, strict, and auto-compiled.
|
|
105
|
+
|
|
98
106
|
```typescript
|
|
99
|
-
import {
|
|
107
|
+
import { defineAction } from "../../titan/titan";
|
|
108
|
+
|
|
109
|
+
interface HelloResponse {
|
|
110
|
+
message: string;
|
|
111
|
+
user_name: string;
|
|
112
|
+
}
|
|
100
113
|
|
|
101
|
-
|
|
114
|
+
// "defineAction" provides automatic type inference for "req"
|
|
115
|
+
export const hello = defineAction((req): HelloResponse => {
|
|
102
116
|
t.log("Handling request with strict types...");
|
|
103
|
-
|
|
104
|
-
// Type checking allows safe property access
|
|
105
|
-
const user = req.body as { name: string };
|
|
106
|
-
|
|
117
|
+
|
|
107
118
|
return {
|
|
108
119
|
message: "Hello from TypeScript!",
|
|
109
|
-
user_name:
|
|
120
|
+
user_name: req.body.name || "Guest"
|
|
110
121
|
};
|
|
111
|
-
}
|
|
122
|
+
});
|
|
112
123
|
```
|
|
113
124
|
|
|
114
125
|
### 🟡 JavaScript Actions (`app/actions/hello.js`)
|
|
115
126
|
Perfect for business logic, rapid prototyping, and IO-bound tasks.
|
|
116
127
|
```javascript
|
|
117
|
-
export
|
|
128
|
+
export const hello = defineAction((req) => {
|
|
118
129
|
t.log("Handling user request...");
|
|
119
130
|
return {
|
|
120
131
|
message: "Hello from JavaScript!",
|
|
121
132
|
user_id: req.params.id
|
|
122
133
|
};
|
|
123
|
-
}
|
|
134
|
+
});
|
|
124
135
|
```
|
|
125
136
|
|
|
126
137
|
### 🔴 Rust Actions (Beta)
|
|
@@ -212,4 +223,3 @@ Titan is **not** a Node.js framework. It is a Rust server that speaks JavaScript
|
|
|
212
223
|
* Strict TypeScript Support
|
|
213
224
|
* Native Rust Performance
|
|
214
225
|
* Zero-Config Cloud Deployment
|
|
215
|
-
|
package/index.js
CHANGED
|
@@ -107,7 +107,7 @@ function help() {
|
|
|
107
107
|
console.log(`
|
|
108
108
|
${bold(cyan("Titan Planet"))} v${TITAN_VERSION}
|
|
109
109
|
|
|
110
|
-
${green("titan init <project>")} Create new Titan project
|
|
110
|
+
${green("titan init <project> [-t <template>]")} Create new Titan project
|
|
111
111
|
${green("titan create ext <name>")} Create new Titan extension
|
|
112
112
|
${green("titan dev")} Dev mode (hot reload)
|
|
113
113
|
${green("titan build")} Build production Rust server
|
|
@@ -188,7 +188,7 @@ async function initProject(name, templateName) {
|
|
|
188
188
|
const arch = archRes.value;
|
|
189
189
|
|
|
190
190
|
if (lang === 'js') {
|
|
191
|
-
selectedTemplate = arch === 'standard' ? 'js' : 'rust';
|
|
191
|
+
selectedTemplate = arch === 'standard' ? 'js' : 'rust-js';
|
|
192
192
|
} else {
|
|
193
193
|
selectedTemplate = arch === 'standard' ? 'ts' : 'rust-ts';
|
|
194
194
|
}
|
|
@@ -289,7 +289,7 @@ async function devServer() {
|
|
|
289
289
|
/* -------------------------------------------------------
|
|
290
290
|
* BUILD
|
|
291
291
|
* ----------------------------------------------------- */
|
|
292
|
-
function buildProd() {
|
|
292
|
+
async function buildProd() {
|
|
293
293
|
console.log(cyan("Titan: Building production output..."));
|
|
294
294
|
|
|
295
295
|
const root = process.cwd();
|
|
@@ -298,11 +298,34 @@ function buildProd() {
|
|
|
298
298
|
const actionsOut = path.join(serverDir, "actions");
|
|
299
299
|
|
|
300
300
|
// BASIC CHECKS
|
|
301
|
-
if (!fs.existsSync(appJs)) {
|
|
302
|
-
console.log(red("ERROR: app/app.js not found."));
|
|
301
|
+
if (!fs.existsSync(appJs) && !fs.existsSync(path.join(root, "app", "app.ts"))) {
|
|
302
|
+
console.log(red("ERROR: app/app.js or app/app.ts not found."));
|
|
303
303
|
process.exit(1);
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
+
// COMPILE TYPESCRIPT IF NEEDED
|
|
307
|
+
if (fs.existsSync(path.join(root, "tsconfig.json"))) {
|
|
308
|
+
console.log(cyan("→ Compiling TypeScript..."));
|
|
309
|
+
try {
|
|
310
|
+
// We use esbuild for speed and consistency with dev mode
|
|
311
|
+
const { buildSync } = await import("esbuild");
|
|
312
|
+
buildSync({
|
|
313
|
+
entryPoints: [path.join(root, "app", "app.ts")],
|
|
314
|
+
outfile: appJs,
|
|
315
|
+
bundle: true,
|
|
316
|
+
platform: "node",
|
|
317
|
+
format: "esm",
|
|
318
|
+
external: ["fs", "path", "esbuild", "chokidar", "typescript"],
|
|
319
|
+
packages: "external",
|
|
320
|
+
});
|
|
321
|
+
console.log(green("✔ TypeScript compiled"));
|
|
322
|
+
} catch (e) {
|
|
323
|
+
console.log(red("ERROR: Failed to compile TypeScript."));
|
|
324
|
+
console.error(e);
|
|
325
|
+
process.exit(1);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
306
329
|
// ----------------------------------------------------
|
|
307
330
|
// 1) BUILD METADATA + BUNDLE ACTIONS (ONE TIME ONLY)
|
|
308
331
|
// ----------------------------------------------------
|
|
@@ -330,23 +353,42 @@ function buildProd() {
|
|
|
330
353
|
// 2) BUILD RUST BINARY
|
|
331
354
|
// ----------------------------------------------------
|
|
332
355
|
console.log(cyan("→ Building Rust release binary..."));
|
|
333
|
-
execSync("cargo build --release", {
|
|
334
|
-
cwd: serverDir,
|
|
335
|
-
stdio: "inherit"
|
|
336
|
-
});
|
|
337
356
|
|
|
338
|
-
|
|
357
|
+
// Only build rust if it's a rust project (check Cargo.toml)
|
|
358
|
+
if (fs.existsSync(path.join(serverDir, "Cargo.toml"))) {
|
|
359
|
+
execSync("cargo build --release", {
|
|
360
|
+
cwd: serverDir,
|
|
361
|
+
stdio: "inherit"
|
|
362
|
+
});
|
|
363
|
+
console.log(green("✔ Titan production build complete!"));
|
|
364
|
+
} else {
|
|
365
|
+
console.log(green("✔ Titan production build complete (pure JS/TS)!"));
|
|
366
|
+
}
|
|
339
367
|
}
|
|
340
368
|
|
|
341
369
|
/* -------------------------------------------------------
|
|
342
370
|
* START
|
|
343
371
|
* ----------------------------------------------------- */
|
|
344
|
-
function startProd() {
|
|
372
|
+
async function startProd() {
|
|
345
373
|
const isWin = process.platform === "win32";
|
|
346
374
|
const bin = isWin ? "titan-server.exe" : "titan-server";
|
|
375
|
+
const root = process.cwd();
|
|
376
|
+
|
|
377
|
+
const exe = path.join(root, "server", "target", "release", bin);
|
|
378
|
+
|
|
379
|
+
if (fs.existsSync(exe)) {
|
|
380
|
+
execSync(`"${exe}"`, { stdio: "inherit" });
|
|
381
|
+
} else {
|
|
382
|
+
// Fallback to pure node start if no rust binary
|
|
383
|
+
const appJs = path.join(root, "app", "app.js");
|
|
384
|
+
// Actually, typically we run the bundled/compiled app if we don't have rust server?
|
|
385
|
+
// But wait, the pure TS template runs `node .titan/app.js` in Docker.
|
|
386
|
+
// But locally `titan start` relies on `app/app.js` being compiled?
|
|
387
|
+
// In `buildProd` above we compiled to `app/app.js`.
|
|
388
|
+
// Let's check for `.titan/app.js` which is dev artifact? No, use the prod build artifact.
|
|
389
|
+
execSync(`node "${appJs}"`, { stdio: "inherit" });
|
|
390
|
+
}
|
|
347
391
|
|
|
348
|
-
const exe = path.join(process.cwd(), "server", "target", "release", bin);
|
|
349
|
-
execSync(`"${exe}"`, { stdio: "inherit" });
|
|
350
392
|
}
|
|
351
393
|
|
|
352
394
|
/* -------------------------------------------------------
|
|
@@ -586,8 +628,8 @@ if (cmd === "create" && args[1] === "ext") {
|
|
|
586
628
|
break;
|
|
587
629
|
}
|
|
588
630
|
case "dev": devServer(); break;
|
|
589
|
-
case "build": buildProd(); break;
|
|
590
|
-
case "start": startProd(); break;
|
|
631
|
+
case "build": await buildProd(); break;
|
|
632
|
+
case "start": await startProd(); break;
|
|
591
633
|
case "update": updateTitan(); break;
|
|
592
634
|
case "--version":
|
|
593
635
|
case "-v":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ezetgalaxy/titan",
|
|
3
|
-
"version": "26.9.
|
|
3
|
+
"version": "26.9.1",
|
|
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
|
],
|
|
@@ -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/titan";
|
|
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,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 const defineAction = (handler) => handler;
|
|
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;
|