@ezetgalaxy/titan 26.7.4 → 26.8.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 +88 -201
- package/index.js +552 -489
- package/package.json +6 -5
- package/templates/js/_gitignore +37 -0
- package/templates/{package.json → js/package.json} +4 -1
- package/templates/js/server/action_map.json +3 -0
- package/templates/js/server/actions/hello.jsbundle +48 -0
- package/templates/js/server/routes.json +16 -0
- package/templates/js/server/src/actions_rust/mod.rs +15 -0
- package/templates/{server → js/server}/src/extensions.rs +149 -17
- package/templates/{titan → js/titan}/bundle.js +22 -9
- package/templates/js/titan/dev.js +194 -0
- package/templates/{titan → js/titan}/titan.js +25 -1
- package/templates/rust/Dockerfile +66 -0
- package/templates/rust/_dockerignore +3 -0
- package/templates/rust/_gitignore +37 -0
- package/templates/rust/app/actions/hello.js +5 -0
- package/templates/rust/app/actions/rust_hello.rs +14 -0
- package/templates/rust/app/app.js +11 -0
- package/templates/rust/app/titan.d.ts +101 -0
- package/templates/rust/jsconfig.json +19 -0
- package/templates/rust/package.json +13 -0
- package/templates/rust/server/Cargo.lock +2869 -0
- package/templates/rust/server/Cargo.toml +27 -0
- package/templates/rust/server/action_map.json +3 -0
- package/templates/rust/server/actions/hello.jsbundle +47 -0
- package/templates/rust/server/routes.json +22 -0
- package/templates/rust/server/src/action_management.rs +131 -0
- package/templates/rust/server/src/actions_rust/mod.rs +19 -0
- package/templates/rust/server/src/actions_rust/rust_hello.rs +14 -0
- package/templates/rust/server/src/errors.rs +10 -0
- package/templates/rust/server/src/extensions.rs +989 -0
- package/templates/rust/server/src/main.rs +443 -0
- package/templates/rust/server/src/utils.rs +33 -0
- package/templates/rust/titan/bundle.js +157 -0
- package/templates/rust/titan/dev.js +194 -0
- package/templates/rust/titan/titan.js +122 -0
- package/titanpl-sdk/package.json +1 -1
- package/titanpl-sdk/templates/Dockerfile +4 -17
- package/titanpl-sdk/templates/server/src/extensions.rs +218 -423
- package/titanpl-sdk/templates/server/src/main.rs +68 -134
- package/scripts/make_dist.sh +0 -71
- package/templates/titan/dev.js +0 -144
- /package/templates/{Dockerfile → js/Dockerfile} +0 -0
- /package/templates/{.dockerignore → js/_dockerignore} +0 -0
- /package/templates/{app → js/app}/actions/hello.js +0 -0
- /package/templates/{app → js/app}/app.js +0 -0
- /package/templates/{app → js/app}/titan.d.ts +0 -0
- /package/templates/{jsconfig.json → js/jsconfig.json} +0 -0
- /package/templates/{server → js/server}/Cargo.lock +0 -0
- /package/templates/{server → js/server}/Cargo.toml +0 -0
- /package/templates/{server → js/server}/src/action_management.rs +0 -0
- /package/templates/{server → js/server}/src/errors.rs +0 -0
- /package/templates/{server → js/server}/src/main.rs +0 -0
- /package/templates/{server → js/server}/src/utils.rs +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
[package]
|
|
3
|
+
name = "titan-server"
|
|
4
|
+
version = "0.1.0"
|
|
5
|
+
edition = "2024"
|
|
6
|
+
|
|
7
|
+
[dependencies]
|
|
8
|
+
axum = "0.8.7"
|
|
9
|
+
dotenv = "0.15.0"
|
|
10
|
+
reqwest = { version = "0.12.24", features = ["json", "rustls-tls", "gzip", "brotli", "blocking"] }
|
|
11
|
+
serde = { version = "1.0.228", features = ["derive"] }
|
|
12
|
+
serde_json = "1.0.145"
|
|
13
|
+
thiserror = "2.0.17"
|
|
14
|
+
tokio = { version = "1.48.0", features = ["rt-multi-thread", "macros", "process"] }
|
|
15
|
+
tower-http = { version = "0.6.7", features = ["cors"] }
|
|
16
|
+
tracing = "0.1.43"
|
|
17
|
+
tracing-subscriber = "0.3.22"
|
|
18
|
+
anyhow = "1"
|
|
19
|
+
v8 = "0.106.0"
|
|
20
|
+
dotenvy = "0.15"
|
|
21
|
+
base64 = "0.21"
|
|
22
|
+
regex = "1.10"
|
|
23
|
+
bcrypt = "0.15"
|
|
24
|
+
jsonwebtoken = "9"
|
|
25
|
+
postgres = { version = "0.19", features = ["with-serde_json-1"] }
|
|
26
|
+
libloading = "0.8"
|
|
27
|
+
walkdir = "2"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const defineAction = (fn) => fn;
|
|
2
|
+
var __titan_exports = (() => {
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// app/actions/hello.js
|
|
22
|
+
var hello_exports = {};
|
|
23
|
+
__export(hello_exports, {
|
|
24
|
+
hello: () => hello
|
|
25
|
+
});
|
|
26
|
+
var hello = () => {
|
|
27
|
+
const valid = "hii";
|
|
28
|
+
t.log(valid);
|
|
29
|
+
};
|
|
30
|
+
return __toCommonJS(hello_exports);
|
|
31
|
+
})();
|
|
32
|
+
|
|
33
|
+
(function () {
|
|
34
|
+
const fn =
|
|
35
|
+
__titan_exports["hello"] ||
|
|
36
|
+
__titan_exports.default;
|
|
37
|
+
|
|
38
|
+
if (typeof fn !== "function") {
|
|
39
|
+
throw new Error("[Titan] Action 'hello' not found or not a function");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
globalThis["hello"] = function(request_arg) {
|
|
43
|
+
globalThis.req = request_arg;
|
|
44
|
+
return fn(request_arg);
|
|
45
|
+
};
|
|
46
|
+
})();
|
|
47
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"__config": {
|
|
3
|
+
"port": 3000
|
|
4
|
+
},
|
|
5
|
+
"routes": {
|
|
6
|
+
"GET:/rust": {
|
|
7
|
+
"type": "action",
|
|
8
|
+
"value": "rust_hello"
|
|
9
|
+
},
|
|
10
|
+
"GET:/": {
|
|
11
|
+
"type": "text",
|
|
12
|
+
"value": "Ready to land on Titan Planet 🚀"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"__dynamic_routes": [
|
|
16
|
+
{
|
|
17
|
+
"method": "GET",
|
|
18
|
+
"pattern": "/hello/:id",
|
|
19
|
+
"action": "hello"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
use std::env;
|
|
3
|
+
use std::path::{Path, PathBuf};
|
|
4
|
+
use serde::Deserialize;
|
|
5
|
+
use serde_json::Value;
|
|
6
|
+
|
|
7
|
+
/// Route configuration (loaded from routes.json)
|
|
8
|
+
#[derive(Debug, Deserialize, Clone)]
|
|
9
|
+
pub struct RouteVal {
|
|
10
|
+
pub r#type: String,
|
|
11
|
+
pub value: Value,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#[derive(Debug, Deserialize, Clone)]
|
|
15
|
+
pub struct DynamicRoute {
|
|
16
|
+
pub method: String,
|
|
17
|
+
pub pattern: String,
|
|
18
|
+
pub action: String,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// -------------------------
|
|
22
|
+
// ACTION DIRECTORY RESOLUTION
|
|
23
|
+
// -------------------------
|
|
24
|
+
|
|
25
|
+
pub fn resolve_actions_dir() -> PathBuf {
|
|
26
|
+
// Respect explicit override first
|
|
27
|
+
if let Ok(override_dir) = env::var("TITAN_ACTIONS_DIR") {
|
|
28
|
+
return PathBuf::from(override_dir);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Production container layout
|
|
32
|
+
if Path::new("/app/actions").exists() {
|
|
33
|
+
return PathBuf::from("/app/actions");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Try to walk up from the executing binary to discover `<...>/server/actions`
|
|
37
|
+
if let Ok(exe) = std::env::current_exe() {
|
|
38
|
+
if let Some(parent) = exe.parent() {
|
|
39
|
+
if let Some(target_dir) = parent.parent() {
|
|
40
|
+
if let Some(server_dir) = target_dir.parent() {
|
|
41
|
+
let candidate = server_dir.join("actions");
|
|
42
|
+
if candidate.exists() {
|
|
43
|
+
return candidate;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Fall back to local ./actions
|
|
51
|
+
PathBuf::from("./actions")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/// Try to find the directory that contains compiled action bundles.
|
|
55
|
+
pub fn find_actions_dir(project_root: &PathBuf) -> Option<PathBuf> {
|
|
56
|
+
let candidates = [
|
|
57
|
+
project_root.join("server").join("actions"),
|
|
58
|
+
project_root.join("actions"),
|
|
59
|
+
project_root.join("..").join("server").join("actions"),
|
|
60
|
+
PathBuf::from("/app").join("actions"),
|
|
61
|
+
PathBuf::from("actions"),
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
for p in &candidates {
|
|
65
|
+
if p.exists() && p.is_dir() {
|
|
66
|
+
return Some(p.clone());
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
None
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Dynamic Matcher (Core Logic)
|
|
74
|
+
|
|
75
|
+
pub fn match_dynamic_route(
|
|
76
|
+
method: &str,
|
|
77
|
+
path: &str,
|
|
78
|
+
routes: &[DynamicRoute],
|
|
79
|
+
) -> Option<(String, HashMap<String, String>)> {
|
|
80
|
+
let path_segments: Vec<&str> =
|
|
81
|
+
path.trim_matches('/').split('/').collect();
|
|
82
|
+
|
|
83
|
+
for route in routes {
|
|
84
|
+
if route.method != method {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let pattern_segments: Vec<&str> =
|
|
89
|
+
route.pattern.trim_matches('/').split('/').collect();
|
|
90
|
+
|
|
91
|
+
if pattern_segments.len() != path_segments.len() {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let mut params = HashMap::new();
|
|
96
|
+
let mut matched = true;
|
|
97
|
+
|
|
98
|
+
for (pat, val) in pattern_segments.iter().zip(path_segments.iter()) {
|
|
99
|
+
if pat.starts_with(':') {
|
|
100
|
+
let inner = &pat[1..];
|
|
101
|
+
|
|
102
|
+
let (name, ty) = inner
|
|
103
|
+
.split_once('<')
|
|
104
|
+
.map(|(n, t)| (n, t.trim_end_matches('>')))
|
|
105
|
+
.unwrap_or((inner, "string"));
|
|
106
|
+
|
|
107
|
+
let valid = match ty {
|
|
108
|
+
"number" => val.parse::<i64>().is_ok(),
|
|
109
|
+
"string" => true,
|
|
110
|
+
_ => false,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
if !valid {
|
|
114
|
+
matched = false;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
params.insert(name.to_string(), (*val).to_string());
|
|
119
|
+
} else if pat != val {
|
|
120
|
+
matched = false;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if matched {
|
|
126
|
+
return Some((route.action.clone(), params));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
None
|
|
131
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Auto-generated by Titan. Do not edit.
|
|
2
|
+
use axum::response::IntoResponse;
|
|
3
|
+
use axum::http::Request;
|
|
4
|
+
use axum::body::Body;
|
|
5
|
+
use std::future::Future;
|
|
6
|
+
use std::pin::Pin;
|
|
7
|
+
|
|
8
|
+
pub mod rust_hello;
|
|
9
|
+
|
|
10
|
+
pub type ActionFn = fn(Request<Body>) -> Pin<Box<dyn Future<Output = axum::response::Response> + Send>>;
|
|
11
|
+
|
|
12
|
+
pub fn get_action(name: &str) -> Option<ActionFn> {
|
|
13
|
+
match name {
|
|
14
|
+
"rust_hello" => Some(|req| Box::pin(async move {
|
|
15
|
+
rust_hello::run(req).await.into_response()
|
|
16
|
+
})),
|
|
17
|
+
_ => None
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
use crate::extensions::t;
|
|
2
|
+
use axum::{response::{IntoResponse, Json}, http::Request, body::Body};
|
|
3
|
+
use serde_json::json;
|
|
4
|
+
|
|
5
|
+
pub async fn run(_req: Request<Body>) -> impl IntoResponse {
|
|
6
|
+
let _token = t.jwt.sign(json!({"id": 1}), "secret", Some(json!({"expiresIn": "1h"}))).unwrap_or_default();
|
|
7
|
+
let decoded = t.jwt.verify(&_token, "secret").unwrap_or_default();
|
|
8
|
+
Json(json!({
|
|
9
|
+
"message": "Hello from Rust Action! 🦀",
|
|
10
|
+
"status": "blazing fast test",
|
|
11
|
+
"token": _token,
|
|
12
|
+
"decoded": decoded
|
|
13
|
+
}))
|
|
14
|
+
}
|