@ezetgalaxy/titan 26.8.2 → 26.9.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 +65 -25
- package/index.js +62 -15
- package/package.json +2 -2
- package/templates/extension/README.md +104 -104
- package/templates/extension/index.js +27 -27
- package/templates/extension/jsconfig.json +12 -12
- package/templates/extension/native/Cargo.toml +9 -9
- package/templates/extension/native/src/lib.rs +5 -5
- package/templates/extension/package.json +20 -20
- package/templates/extension/titan.json +17 -17
- package/templates/js/Dockerfile +66 -66
- package/templates/js/_dockerignore +3 -3
- package/templates/js/_gitignore +1 -0
- package/templates/js/app/actions/hello.js +5 -5
- package/templates/js/app/titan.d.ts +87 -87
- package/templates/js/jsconfig.json +18 -18
- package/templates/js/server/src/action_management.rs +131 -131
- package/templates/js/server/src/errors.rs +10 -10
- package/templates/js/server/src/extensions.rs +989 -989
- package/templates/js/server/src/utils.rs +33 -33
- package/templates/js/titan/bundle.js +78 -78
- package/templates/js/titan/dev.js +35 -3
- package/templates/js/titan/titan.js +122 -122
- package/templates/rust/Dockerfile +66 -66
- package/templates/rust/_dockerignore +3 -3
- package/templates/rust/_gitignore +1 -0
- package/templates/rust/app/actions/hello.js +5 -5
- package/templates/rust/app/actions/rust_hello.rs +14 -14
- package/templates/rust/app/titan.d.ts +101 -101
- package/templates/rust/jsconfig.json +18 -18
- package/templates/rust/server/src/action_management.rs +131 -131
- package/templates/rust/server/src/errors.rs +10 -10
- package/templates/rust/server/src/extensions.rs +989 -989
- package/templates/rust/server/src/utils.rs +33 -33
- package/templates/rust/titan/dev.js +36 -12
- package/templates/rust-ts/Dockerfile +66 -0
- package/templates/rust-ts/_dockerignore +3 -0
- package/templates/rust-ts/_gitignore +38 -0
- package/templates/rust-ts/app/actions/hello.ts +5 -0
- package/templates/rust-ts/app/actions/rust_hello.rs +14 -0
- package/templates/rust-ts/app/app.ts +11 -0
- package/templates/rust-ts/app/titan.d.ts +101 -0
- package/templates/rust-ts/package.json +14 -0
- package/templates/rust-ts/server/Cargo.lock +2869 -0
- package/templates/rust-ts/server/Cargo.toml +39 -0
- package/templates/rust-ts/server/src/action_management.rs +131 -0
- package/templates/rust-ts/server/src/errors.rs +51 -0
- package/templates/rust-ts/server/src/extensions.rs +989 -0
- package/templates/rust-ts/server/src/main.rs +468 -0
- package/templates/rust-ts/server/src/utils.rs +33 -0
- package/templates/rust-ts/titan/bundle.js +157 -0
- package/templates/rust-ts/titan/dev.js +402 -0
- package/templates/rust-ts/titan/titan.js +122 -0
- package/templates/rust-ts/tsconfig.json +21 -0
- package/templates/ts/Dockerfile +66 -0
- package/templates/ts/_dockerignore +3 -0
- package/templates/ts/_gitignore +38 -0
- package/templates/ts/app/actions/hello.ts +9 -0
- package/templates/ts/app/app.ts +10 -0
- package/templates/ts/app/titan.d.ts +102 -0
- package/templates/ts/package.json +26 -0
- package/templates/ts/server/Cargo.lock +2869 -0
- package/templates/ts/server/Cargo.toml +27 -0
- package/templates/ts/server/src/action_management.rs +131 -0
- package/templates/ts/server/src/errors.rs +51 -0
- package/templates/ts/server/src/extensions.rs +989 -0
- package/templates/ts/server/src/main.rs +437 -0
- package/templates/ts/server/src/utils.rs +33 -0
- package/templates/ts/titan/bundle.js +78 -0
- package/templates/ts/titan/dev.js +402 -0
- package/templates/ts/titan/titan.js +122 -0
- package/templates/ts/tsconfig.json +16 -0
- package/titanpl-sdk/README.md +109 -109
- package/titanpl-sdk/bin/run.js +254 -254
- package/titanpl-sdk/index.d.ts +46 -46
- package/titanpl-sdk/index.js +5 -5
- package/titanpl-sdk/package.json +32 -32
- package/titanpl-sdk/templates/.dockerignore +3 -3
- package/titanpl-sdk/templates/Dockerfile +53 -53
- package/titanpl-sdk/templates/app/actions/hello.js +5 -5
- package/titanpl-sdk/templates/app/titan.d.ts +87 -87
- package/titanpl-sdk/templates/jsconfig.json +18 -18
- package/titanpl-sdk/templates/server/src/action_management.rs +131 -131
- package/titanpl-sdk/templates/server/src/errors.rs +10 -10
- package/titanpl-sdk/templates/server/src/extensions.rs +640 -640
- package/titanpl-sdk/templates/server/src/utils.rs +33 -33
- package/titanpl-sdk/templates/titan/bundle.js +65 -65
- package/titanpl-sdk/templates/titan/dev.js +113 -113
- package/titanpl-sdk/templates/titan/titan.js +98 -98
- package/templates/js/server/action_map.json +0 -3
- package/templates/js/server/actions/hello.jsbundle +0 -48
- package/templates/js/server/routes.json +0 -16
- package/templates/rust/server/action_map.json +0 -3
- package/templates/rust/server/actions/hello.jsbundle +0 -47
- package/templates/rust/server/routes.json +0 -22
- package/templates/rust/server/src/actions_rust/mod.rs +0 -19
- package/templates/rust/server/src/actions_rust/rust_hello.rs +0 -14
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
pub fn blue(s: &str) -> String {
|
|
2
|
-
format!("\x1b[38;5;39m{}\x1b[0m", s)
|
|
3
|
-
}
|
|
4
|
-
pub fn white(s: &str) -> String {
|
|
5
|
-
format!("\x1b[39m{}\x1b[0m", s)
|
|
6
|
-
}
|
|
7
|
-
pub fn yellow(s: &str) -> String {
|
|
8
|
-
format!("\x1b[33m{}\x1b[0m", s)
|
|
9
|
-
}
|
|
10
|
-
pub fn green(s: &str) -> String {
|
|
11
|
-
format!("\x1b[32m{}\x1b[0m", s)
|
|
12
|
-
}
|
|
13
|
-
pub fn gray(s: &str) -> String {
|
|
14
|
-
format!("\x1b[90m{}\x1b[0m", s)
|
|
15
|
-
}
|
|
16
|
-
pub fn red(s: &str) -> String {
|
|
17
|
-
format!("\x1b[31m{}\x1b[0m", s)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
pub fn parse_expires_in(value: &str) -> Option<u64> {
|
|
21
|
-
let (num, unit) = value.split_at(value.len() - 1);
|
|
22
|
-
let n: u64 = num.parse().ok()?;
|
|
23
|
-
|
|
24
|
-
match unit {
|
|
25
|
-
"s" => Some(n),
|
|
26
|
-
"m" => Some(n * 60),
|
|
27
|
-
"h" => Some(n * 60 * 60),
|
|
28
|
-
"d" => Some(n * 60 * 60 * 24),
|
|
29
|
-
_ => None,
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
1
|
+
pub fn blue(s: &str) -> String {
|
|
2
|
+
format!("\x1b[38;5;39m{}\x1b[0m", s)
|
|
3
|
+
}
|
|
4
|
+
pub fn white(s: &str) -> String {
|
|
5
|
+
format!("\x1b[39m{}\x1b[0m", s)
|
|
6
|
+
}
|
|
7
|
+
pub fn yellow(s: &str) -> String {
|
|
8
|
+
format!("\x1b[33m{}\x1b[0m", s)
|
|
9
|
+
}
|
|
10
|
+
pub fn green(s: &str) -> String {
|
|
11
|
+
format!("\x1b[32m{}\x1b[0m", s)
|
|
12
|
+
}
|
|
13
|
+
pub fn gray(s: &str) -> String {
|
|
14
|
+
format!("\x1b[90m{}\x1b[0m", s)
|
|
15
|
+
}
|
|
16
|
+
pub fn red(s: &str) -> String {
|
|
17
|
+
format!("\x1b[31m{}\x1b[0m", s)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
pub fn parse_expires_in(value: &str) -> Option<u64> {
|
|
21
|
+
let (num, unit) = value.split_at(value.len() - 1);
|
|
22
|
+
let n: u64 = num.parse().ok()?;
|
|
23
|
+
|
|
24
|
+
match unit {
|
|
25
|
+
"s" => Some(n),
|
|
26
|
+
"m" => Some(n * 60),
|
|
27
|
+
"h" => Some(n * 60 * 60),
|
|
28
|
+
"d" => Some(n * 60 * 60 * 24),
|
|
29
|
+
_ => None,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import esbuild from "esbuild";
|
|
4
|
-
|
|
5
|
-
const root = process.cwd();
|
|
6
|
-
const actionsDir = path.join(root, "app", "actions");
|
|
7
|
-
const outDir = path.join(root, "server", "actions");
|
|
8
|
-
|
|
9
|
-
export async function bundle() {
|
|
10
|
-
const start = Date.now();
|
|
11
|
-
await bundleJs();
|
|
12
|
-
// console.log(`[Titan] Bundle finished in ${((Date.now() - start) / 1000).toFixed(2)}s`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async function bundleJs() {
|
|
16
|
-
// console.log("[Titan] Bundling JS actions...");
|
|
17
|
-
|
|
18
|
-
fs.mkdirSync(outDir, { recursive: true });
|
|
19
|
-
|
|
20
|
-
// Clean old bundles
|
|
21
|
-
if (fs.existsSync(outDir)) {
|
|
22
|
-
const oldFiles = fs.readdirSync(outDir);
|
|
23
|
-
for (const file of oldFiles) {
|
|
24
|
-
fs.unlinkSync(path.join(outDir, file));
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const files = fs.readdirSync(actionsDir).filter(f => f.endsWith(".js") || f.endsWith(".ts"));
|
|
29
|
-
if (files.length === 0) return;
|
|
30
|
-
|
|
31
|
-
// console.log(`[Titan] Bundling ${files.length} JS actions...`);
|
|
32
|
-
|
|
33
|
-
for (const file of files) {
|
|
34
|
-
const actionName = path.basename(file, path.extname(file));
|
|
35
|
-
|
|
36
|
-
const entry = path.join(actionsDir, file);
|
|
37
|
-
|
|
38
|
-
// Rust runtime expects `.jsbundle` extension — consistent with previous design
|
|
39
|
-
const outfile = path.join(outDir, actionName + ".jsbundle");
|
|
40
|
-
|
|
41
|
-
// console.log(`[Titan] Bundling ${entry} → ${outfile}`);
|
|
42
|
-
|
|
43
|
-
await esbuild.build({
|
|
44
|
-
entryPoints: [entry],
|
|
45
|
-
outfile,
|
|
46
|
-
bundle: true,
|
|
47
|
-
format: "iife",
|
|
48
|
-
globalName: "__titan_exports",
|
|
49
|
-
platform: "neutral",
|
|
50
|
-
target: "es2020",
|
|
51
|
-
logLevel: "silent",
|
|
52
|
-
banner: {
|
|
53
|
-
js: "const defineAction = (fn) => fn;"
|
|
54
|
-
},
|
|
55
|
-
|
|
56
|
-
footer: {
|
|
57
|
-
js: `
|
|
58
|
-
(function () {
|
|
59
|
-
const fn =
|
|
60
|
-
__titan_exports["${actionName}"] ||
|
|
61
|
-
__titan_exports.default;
|
|
62
|
-
|
|
63
|
-
if (typeof fn !== "function") {
|
|
64
|
-
throw new Error("[Titan] Action '${actionName}' not found or not a function");
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
globalThis["${actionName}"] = function(request_arg) {
|
|
68
|
-
globalThis.req = request_arg;
|
|
69
|
-
return fn(request_arg);
|
|
70
|
-
};
|
|
71
|
-
})();
|
|
72
|
-
`
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// console.log("[Titan] JS Bundling finished.");
|
|
78
|
-
}
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import esbuild from "esbuild";
|
|
4
|
+
|
|
5
|
+
const root = process.cwd();
|
|
6
|
+
const actionsDir = path.join(root, "app", "actions");
|
|
7
|
+
const outDir = path.join(root, "server", "actions");
|
|
8
|
+
|
|
9
|
+
export async function bundle() {
|
|
10
|
+
const start = Date.now();
|
|
11
|
+
await bundleJs();
|
|
12
|
+
// console.log(`[Titan] Bundle finished in ${((Date.now() - start) / 1000).toFixed(2)}s`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function bundleJs() {
|
|
16
|
+
// console.log("[Titan] Bundling JS actions...");
|
|
17
|
+
|
|
18
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
19
|
+
|
|
20
|
+
// Clean old bundles
|
|
21
|
+
if (fs.existsSync(outDir)) {
|
|
22
|
+
const oldFiles = fs.readdirSync(outDir);
|
|
23
|
+
for (const file of oldFiles) {
|
|
24
|
+
fs.unlinkSync(path.join(outDir, file));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const files = fs.readdirSync(actionsDir).filter(f => f.endsWith(".js") || f.endsWith(".ts"));
|
|
29
|
+
if (files.length === 0) return;
|
|
30
|
+
|
|
31
|
+
// console.log(`[Titan] Bundling ${files.length} JS actions...`);
|
|
32
|
+
|
|
33
|
+
for (const file of files) {
|
|
34
|
+
const actionName = path.basename(file, path.extname(file));
|
|
35
|
+
|
|
36
|
+
const entry = path.join(actionsDir, file);
|
|
37
|
+
|
|
38
|
+
// Rust runtime expects `.jsbundle` extension — consistent with previous design
|
|
39
|
+
const outfile = path.join(outDir, actionName + ".jsbundle");
|
|
40
|
+
|
|
41
|
+
// console.log(`[Titan] Bundling ${entry} → ${outfile}`);
|
|
42
|
+
|
|
43
|
+
await esbuild.build({
|
|
44
|
+
entryPoints: [entry],
|
|
45
|
+
outfile,
|
|
46
|
+
bundle: true,
|
|
47
|
+
format: "iife",
|
|
48
|
+
globalName: "__titan_exports",
|
|
49
|
+
platform: "neutral",
|
|
50
|
+
target: "es2020",
|
|
51
|
+
logLevel: "silent",
|
|
52
|
+
banner: {
|
|
53
|
+
js: "const defineAction = (fn) => fn;"
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
footer: {
|
|
57
|
+
js: `
|
|
58
|
+
(function () {
|
|
59
|
+
const fn =
|
|
60
|
+
__titan_exports["${actionName}"] ||
|
|
61
|
+
__titan_exports.default;
|
|
62
|
+
|
|
63
|
+
if (typeof fn !== "function") {
|
|
64
|
+
throw new Error("[Titan] Action '${actionName}' not found or not a function");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
globalThis["${actionName}"] = function(request_arg) {
|
|
68
|
+
globalThis.req = request_arg;
|
|
69
|
+
return fn(request_arg);
|
|
70
|
+
};
|
|
71
|
+
})();
|
|
72
|
+
`
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// console.log("[Titan] JS Bundling finished.");
|
|
78
|
+
}
|
|
@@ -3,7 +3,6 @@ import { spawn, execSync } from "child_process";
|
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import fs from "fs";
|
|
6
|
-
import { bundle } from "./bundle.js";
|
|
7
6
|
|
|
8
7
|
// Required for __dirname in ES modules
|
|
9
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -39,12 +38,20 @@ function getTitanVersion() {
|
|
|
39
38
|
cur = path.join(cur, "..");
|
|
40
39
|
}
|
|
41
40
|
} catch (e2) { }
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
// Fallback to calling tit --version
|
|
44
|
+
const output = execSync("tit --version", { encoding: "utf-8" }).trim();
|
|
45
|
+
const match = output.match(/v(\d+\.\d+\.\d+)/);
|
|
46
|
+
if (match) return match[1];
|
|
47
|
+
} catch (e3) { }
|
|
42
48
|
}
|
|
43
49
|
return "0.1.0";
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
let serverProcess = null;
|
|
47
53
|
let isKilling = false;
|
|
54
|
+
let isFirstBoot = true;
|
|
48
55
|
|
|
49
56
|
// ... (killServer same as before)
|
|
50
57
|
async function killServer() {
|
|
@@ -156,7 +163,24 @@ async function startRustServer(retryCount = 0) {
|
|
|
156
163
|
isReady = true;
|
|
157
164
|
clearTimeout(slowTimer);
|
|
158
165
|
stopSpinner(true, "Your app is now orbiting Titan Planet");
|
|
159
|
-
|
|
166
|
+
|
|
167
|
+
if (isFirstBoot) {
|
|
168
|
+
process.stdout.write(stdoutBuffer);
|
|
169
|
+
isFirstBoot = false;
|
|
170
|
+
} else {
|
|
171
|
+
// On subsequent reloads, only print non-banner lines from the buffer
|
|
172
|
+
const lines = stdoutBuffer.split("\n");
|
|
173
|
+
for (const line of lines) {
|
|
174
|
+
const isBanner = line.includes("Titan server running") ||
|
|
175
|
+
line.includes("████████╗") ||
|
|
176
|
+
line.includes("╚══") ||
|
|
177
|
+
line.includes(" ██║") ||
|
|
178
|
+
line.includes(" ╚═╝");
|
|
179
|
+
if (!isBanner && line.trim()) {
|
|
180
|
+
process.stdout.write(line + "\n");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
160
184
|
stdoutBuffer = "";
|
|
161
185
|
}
|
|
162
186
|
} else {
|
|
@@ -203,7 +227,15 @@ async function startDev() {
|
|
|
203
227
|
hasRust = fs.readdirSync(actionsDir).some(f => f.endsWith(".rs"));
|
|
204
228
|
}
|
|
205
229
|
|
|
206
|
-
const
|
|
230
|
+
const isTs = fs.existsSync(path.join(root, "tsconfig.json")) ||
|
|
231
|
+
fs.existsSync(path.join(root, "app", "app.ts"));
|
|
232
|
+
|
|
233
|
+
let mode = "";
|
|
234
|
+
if (hasRust) {
|
|
235
|
+
mode = isTs ? "Rust + TS Actions" : "Rust + JS Actions";
|
|
236
|
+
} else {
|
|
237
|
+
mode = isTs ? "TS Actions" : "JS Actions";
|
|
238
|
+
}
|
|
207
239
|
const version = getTitanVersion();
|
|
208
240
|
|
|
209
241
|
console.clear();
|
|
@@ -1,122 +1,122 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { bundle } from "./bundle.js";
|
|
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
|
-
|
|
122
|
-
export default t;
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { bundle } from "./bundle.js";
|
|
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
|
+
|
|
122
|
+
export default t;
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
# ================================================================
|
|
2
|
-
# STAGE 1 — Build Titan (JS → Rust)
|
|
3
|
-
# ================================================================
|
|
4
|
-
FROM rust:1.91.1 AS builder
|
|
5
|
-
|
|
6
|
-
# Install Node for Titan CLI + bundler
|
|
7
|
-
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
|
8
|
-
&& apt-get install -y nodejs
|
|
9
|
-
|
|
10
|
-
# Install Titan CLI (latest)
|
|
11
|
-
RUN npm install -g @ezetgalaxy/titan@latest
|
|
12
|
-
|
|
13
|
-
WORKDIR /app
|
|
14
|
-
|
|
15
|
-
# Copy project files
|
|
16
|
-
COPY . .
|
|
17
|
-
|
|
18
|
-
# Install JS dependencies (needed for Titan DSL + bundler)
|
|
19
|
-
RUN npm install
|
|
20
|
-
|
|
21
|
-
SHELL ["/bin/bash", "-c"]
|
|
22
|
-
|
|
23
|
-
# Extract Titan extensions into .ext
|
|
24
|
-
RUN mkdir -p /app/.ext && \
|
|
25
|
-
find /app/node_modules -maxdepth 5 -type f -name "titan.json" -print0 | \
|
|
26
|
-
while IFS= read -r -d '' file; do \
|
|
27
|
-
pkg_dir="$(dirname "$file")"; \
|
|
28
|
-
pkg_name="$(basename "$pkg_dir")"; \
|
|
29
|
-
echo "Copying Titan extension: $pkg_name from $pkg_dir"; \
|
|
30
|
-
cp -r "$pkg_dir" "/app/.ext/$pkg_name"; \
|
|
31
|
-
done && \
|
|
32
|
-
echo "Extensions in .ext:" && \
|
|
33
|
-
ls -R /app/.ext
|
|
34
|
-
|
|
35
|
-
# Build Titan metadata + bundle JS actions
|
|
36
|
-
RUN titan build
|
|
37
|
-
|
|
38
|
-
# Build Rust binary
|
|
39
|
-
RUN cd server && cargo build --release
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
# ================================================================
|
|
44
|
-
# STAGE 2 — Runtime Image (Lightweight)
|
|
45
|
-
# ================================================================
|
|
46
|
-
FROM debian:stable-slim
|
|
47
|
-
|
|
48
|
-
WORKDIR /app
|
|
49
|
-
|
|
50
|
-
# Copy Rust binary from builder stage
|
|
51
|
-
COPY --from=builder /app/server/target/release/titan-server ./titan-server
|
|
52
|
-
|
|
53
|
-
# Copy Titan routing metadata
|
|
54
|
-
COPY --from=builder /app/server/routes.json ./routes.json
|
|
55
|
-
COPY --from=builder /app/server/action_map.json ./action_map.json
|
|
56
|
-
|
|
57
|
-
# Copy Titan JS bundles
|
|
58
|
-
RUN mkdir -p /app/actions
|
|
59
|
-
COPY --from=builder /app/server/actions /app/actions
|
|
60
|
-
|
|
61
|
-
# Copy only Titan extensions
|
|
62
|
-
COPY --from=builder /app/.ext ./.ext
|
|
63
|
-
|
|
64
|
-
EXPOSE 3000
|
|
65
|
-
|
|
66
|
-
CMD ["./titan-server"]
|
|
1
|
+
# ================================================================
|
|
2
|
+
# STAGE 1 — Build Titan (JS → Rust)
|
|
3
|
+
# ================================================================
|
|
4
|
+
FROM rust:1.91.1 AS builder
|
|
5
|
+
|
|
6
|
+
# Install Node for Titan CLI + bundler
|
|
7
|
+
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
|
8
|
+
&& apt-get install -y nodejs
|
|
9
|
+
|
|
10
|
+
# Install Titan CLI (latest)
|
|
11
|
+
RUN npm install -g @ezetgalaxy/titan@latest
|
|
12
|
+
|
|
13
|
+
WORKDIR /app
|
|
14
|
+
|
|
15
|
+
# Copy project files
|
|
16
|
+
COPY . .
|
|
17
|
+
|
|
18
|
+
# Install JS dependencies (needed for Titan DSL + bundler)
|
|
19
|
+
RUN npm install
|
|
20
|
+
|
|
21
|
+
SHELL ["/bin/bash", "-c"]
|
|
22
|
+
|
|
23
|
+
# Extract Titan extensions into .ext
|
|
24
|
+
RUN mkdir -p /app/.ext && \
|
|
25
|
+
find /app/node_modules -maxdepth 5 -type f -name "titan.json" -print0 | \
|
|
26
|
+
while IFS= read -r -d '' file; do \
|
|
27
|
+
pkg_dir="$(dirname "$file")"; \
|
|
28
|
+
pkg_name="$(basename "$pkg_dir")"; \
|
|
29
|
+
echo "Copying Titan extension: $pkg_name from $pkg_dir"; \
|
|
30
|
+
cp -r "$pkg_dir" "/app/.ext/$pkg_name"; \
|
|
31
|
+
done && \
|
|
32
|
+
echo "Extensions in .ext:" && \
|
|
33
|
+
ls -R /app/.ext
|
|
34
|
+
|
|
35
|
+
# Build Titan metadata + bundle JS actions
|
|
36
|
+
RUN titan build
|
|
37
|
+
|
|
38
|
+
# Build Rust binary
|
|
39
|
+
RUN cd server && cargo build --release
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# ================================================================
|
|
44
|
+
# STAGE 2 — Runtime Image (Lightweight)
|
|
45
|
+
# ================================================================
|
|
46
|
+
FROM debian:stable-slim
|
|
47
|
+
|
|
48
|
+
WORKDIR /app
|
|
49
|
+
|
|
50
|
+
# Copy Rust binary from builder stage
|
|
51
|
+
COPY --from=builder /app/server/target/release/titan-server ./titan-server
|
|
52
|
+
|
|
53
|
+
# Copy Titan routing metadata
|
|
54
|
+
COPY --from=builder /app/server/routes.json ./routes.json
|
|
55
|
+
COPY --from=builder /app/server/action_map.json ./action_map.json
|
|
56
|
+
|
|
57
|
+
# Copy Titan JS bundles
|
|
58
|
+
RUN mkdir -p /app/actions
|
|
59
|
+
COPY --from=builder /app/server/actions /app/actions
|
|
60
|
+
|
|
61
|
+
# Copy only Titan extensions
|
|
62
|
+
COPY --from=builder /app/.ext ./.ext
|
|
63
|
+
|
|
64
|
+
EXPOSE 3000
|
|
65
|
+
|
|
66
|
+
CMD ["./titan-server"]
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
node_modules
|
|
2
|
-
npm-debug.log
|
|
3
|
-
.git
|
|
1
|
+
node_modules
|
|
2
|
+
npm-debug.log
|
|
3
|
+
.git
|