titanpl-sdk 1.0.9 → 1.5.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 +2 -0
- package/bin/run.js +16 -16
- package/package.json +38 -34
- package/templates/app/app.js +1 -4
- package/templates/server/Cargo.toml +22 -2
- package/templates/server/src/action_management.rs +29 -24
- package/templates/server/src/errors.rs +3 -1
- package/templates/server/src/extensions/builtin.rs +1038 -588
- package/templates/server/src/extensions/external.rs +338 -309
- package/templates/server/src/extensions/mod.rs +580 -326
- package/templates/server/src/extensions/titan_core.js +249 -22
- package/templates/server/src/fast_path.rs +719 -0
- package/templates/server/src/main.rs +409 -166
- package/templates/server/src/runtime.rs +284 -158
- package/templates/server/src/utils.rs +2 -2
- package/templates/titan/bundle.js +259 -267
- package/templates/titan/dev.js +46 -6
- package/templates/titan/error-box.js +277 -268
- package/templates/titan/titan.js +2 -2
- package/index.d.ts +0 -50
- package/templates/app/titan.d.ts +0 -87
package/README.md
CHANGED
|
@@ -24,6 +24,8 @@ It provides the necessary **Type Definitions** to make your IDE understand the g
|
|
|
24
24
|
|
|
25
25
|
> **Note:** The actual implementation of `t.log`, `t.fetch`, and other APIs are embedded directly into the [Titan Planet Binary](https://github.com/ezet-galaxy/titanpl). This SDK simply provides the "blueprints" (types) and a "sandbox" (test runner).
|
|
26
26
|
|
|
27
|
+
**Important Note:** Currently, Titan Planet and its entire package ecosystem are only for Windows. The Linux version is in development (dev only) for the new architecture and will be launched later.
|
|
28
|
+
|
|
27
29
|
---
|
|
28
30
|
|
|
29
31
|
## ✨ Features
|
package/bin/run.js
CHANGED
|
@@ -198,24 +198,24 @@ await import("${name}");
|
|
|
198
198
|
// Extension test harness for: ${name}
|
|
199
199
|
const ext = t["${name}"];
|
|
200
200
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
t.log("---------------------------------------------------");
|
|
202
|
+
t.log("Testing Extension: ${name}");
|
|
203
|
+
t.log("---------------------------------------------------");
|
|
204
204
|
|
|
205
205
|
if (!ext) {
|
|
206
206
|
console.log("ERROR: Extension '${name}' not found in global 't'.");
|
|
207
207
|
} else {
|
|
208
|
-
|
|
209
|
-
|
|
208
|
+
t.log("✓ Extension loaded successfully!");
|
|
209
|
+
t.log("✓ Available methods:", Object.keys(ext).join(", "));
|
|
210
210
|
|
|
211
211
|
// Try 'hello' if it exists
|
|
212
212
|
if (typeof ext.hello === 'function') {
|
|
213
213
|
console.log("\\nTesting ext.hello('Titan')...");
|
|
214
214
|
try {
|
|
215
215
|
const res = ext.hello("Titan");
|
|
216
|
-
|
|
216
|
+
t.log("✓ Result:", res);
|
|
217
217
|
} catch(e) {
|
|
218
|
-
|
|
218
|
+
t.log("✗ Error:", e.message);
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
221
|
|
|
@@ -224,25 +224,25 @@ if (!ext) {
|
|
|
224
224
|
console.log("\\nTesting ext.calc(10, 20)...");
|
|
225
225
|
try {
|
|
226
226
|
const res = ext.calc(10, 20);
|
|
227
|
-
|
|
227
|
+
t.log("✓ Result:", res);
|
|
228
228
|
} catch(e) {
|
|
229
|
-
|
|
229
|
+
t.log("✗ Error:", e.message);
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
234
|
+
t.log("---------------------------------------------------");
|
|
235
|
+
t.log("✓ Test complete!");
|
|
236
|
+
t.log("\\n📍 Routes:");
|
|
237
|
+
t.log(" GET http://localhost:3000/ → Test harness info");
|
|
238
|
+
t.log(" GET http://localhost:3000/test → Extension test results (JSON)");
|
|
239
|
+
t.log("---------------------------------------------------\\n");
|
|
240
240
|
|
|
241
241
|
// Create routes
|
|
242
242
|
t.get("/test").action("test");
|
|
243
243
|
t.get("/").reply("🚀 Extension Test Harness for ${name}\\n\\nVisit /test to see extension test results");
|
|
244
244
|
|
|
245
|
-
await t.start(3000, "Titan Extension Test Running!");
|
|
245
|
+
await t.start(3000, "Titan Extension Test Running!", 10, 16);
|
|
246
246
|
`;
|
|
247
247
|
fs.writeFileSync(appJsPath, testScript);
|
|
248
248
|
}
|
package/package.json
CHANGED
|
@@ -1,36 +1,40 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
2
|
+
"name": "titanpl-sdk",
|
|
3
|
+
"version": "1.5.0",
|
|
4
|
+
"description": "Development SDK for Titan Planet. Provides TypeScript type definitions for the global 't' runtime object and a 'lite' test-harness runtime for building and verifying extensions.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"types": "index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"titanpl-sdk": "./bin/run.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"bin/",
|
|
13
|
+
"templates/",
|
|
14
|
+
"titan",
|
|
15
|
+
"assets",
|
|
16
|
+
"index.js",
|
|
17
|
+
"index.d.ts",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"titan",
|
|
22
|
+
"titan-planet",
|
|
23
|
+
"titanpl-sdk",
|
|
24
|
+
"ezetgalaxy",
|
|
25
|
+
"types",
|
|
26
|
+
"typescript",
|
|
27
|
+
"intellisense",
|
|
28
|
+
"sdk",
|
|
29
|
+
"backend-sdk",
|
|
30
|
+
"extension-development"
|
|
31
|
+
],
|
|
32
|
+
"license": "ISC",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@titanpl/core": "1.4.0",
|
|
35
|
+
"@titanpl/node": "1.4.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@tgrv/microgravity": "latest"
|
|
39
|
+
}
|
|
36
40
|
}
|
package/templates/app/app.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
[package]
|
|
3
2
|
name = "titan-server"
|
|
4
3
|
version = "0.1.0"
|
|
@@ -11,7 +10,7 @@ reqwest = { version = "0.12.24", features = ["json", "rustls-tls", "gzip", "brot
|
|
|
11
10
|
serde = { version = "1.0.228", features = ["derive"] }
|
|
12
11
|
serde_json = "1.0.145"
|
|
13
12
|
thiserror = "2.0.17"
|
|
14
|
-
tokio = { version = "1.48.0", features = ["rt-multi-thread", "macros", "process"] }
|
|
13
|
+
tokio = { version = "1.48.0", features = ["rt-multi-thread", "macros", "process", "fs"] }
|
|
15
14
|
tower-http = { version = "0.6.7", features = ["cors"] }
|
|
16
15
|
tracing = "0.1.43"
|
|
17
16
|
tracing-subscriber = "0.3.22"
|
|
@@ -30,3 +29,24 @@ dashmap = "6.1.0"
|
|
|
30
29
|
bytes = "1.11.0"
|
|
31
30
|
smallvec = "1.15.1"
|
|
32
31
|
num_cpus = "1.17.0"
|
|
32
|
+
deadpool-postgres = "0.12"
|
|
33
|
+
tokio-postgres = "0.7"
|
|
34
|
+
|
|
35
|
+
# Performance: Global Allocator
|
|
36
|
+
mimalloc = { version = "0.1", default-features = false }
|
|
37
|
+
|
|
38
|
+
# Static Analysis: OXC (Zero runtime cost, used at startup)
|
|
39
|
+
oxc = { version = "0.108", features = ["semantic"] }
|
|
40
|
+
|
|
41
|
+
# Release Profile
|
|
42
|
+
[profile.release]
|
|
43
|
+
opt-level = 3
|
|
44
|
+
lto = "fat"
|
|
45
|
+
codegen-units = 1
|
|
46
|
+
panic = "abort"
|
|
47
|
+
strip = true
|
|
48
|
+
|
|
49
|
+
# Dev Profile
|
|
50
|
+
[profile.dev]
|
|
51
|
+
opt-level = 0
|
|
52
|
+
debug = 1
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
//! Action Management and Dynamic Routing
|
|
2
|
+
//!
|
|
3
|
+
//! Handles resolution of action directories, scanning for available actions,
|
|
4
|
+
//! and matching dynamic routes (e.g. `/users/:id`).
|
|
5
|
+
|
|
1
6
|
use std::collections::HashMap;
|
|
2
7
|
use std::env;
|
|
3
8
|
use std::path::{Path, PathBuf};
|
|
@@ -8,6 +13,7 @@ use serde_json::Value;
|
|
|
8
13
|
#[derive(Debug, Deserialize, Clone)]
|
|
9
14
|
pub struct RouteVal {
|
|
10
15
|
pub r#type: String,
|
|
16
|
+
#[serde(alias = "target")]
|
|
11
17
|
pub value: Value,
|
|
12
18
|
}
|
|
13
19
|
|
|
@@ -18,10 +24,7 @@ pub struct DynamicRoute {
|
|
|
18
24
|
pub action: String,
|
|
19
25
|
}
|
|
20
26
|
|
|
21
|
-
|
|
22
|
-
// ACTION DIRECTORY RESOLUTION
|
|
23
|
-
// -------------------------
|
|
24
|
-
|
|
27
|
+
/// Resolve the directory path where actions are stored.
|
|
25
28
|
pub fn resolve_actions_dir() -> PathBuf {
|
|
26
29
|
// Respect explicit override first
|
|
27
30
|
if let Ok(override_dir) = env::var("TITAN_ACTIONS_DIR") {
|
|
@@ -33,30 +36,36 @@ pub fn resolve_actions_dir() -> PathBuf {
|
|
|
33
36
|
return PathBuf::from("/app/actions");
|
|
34
37
|
}
|
|
35
38
|
|
|
36
|
-
// Try to walk up from the executing binary to discover `<...>/server/actions`
|
|
39
|
+
// Try to walk up from the executing binary to discover `<...>/server/src/actions`
|
|
37
40
|
if let Ok(exe) = std::env::current_exe() {
|
|
38
41
|
if let Some(parent) = exe.parent() {
|
|
39
42
|
if let Some(target_dir) = parent.parent() {
|
|
40
43
|
if let Some(server_dir) = target_dir.parent() {
|
|
41
|
-
let candidate = server_dir.join("actions");
|
|
44
|
+
let candidate = server_dir.join("src").join("actions");
|
|
42
45
|
if candidate.exists() {
|
|
43
46
|
return candidate;
|
|
44
47
|
}
|
|
48
|
+
let candidate2 = server_dir.join("actions");
|
|
49
|
+
if candidate2.exists() {
|
|
50
|
+
return candidate2;
|
|
51
|
+
}
|
|
45
52
|
}
|
|
46
53
|
}
|
|
47
54
|
}
|
|
48
55
|
}
|
|
49
56
|
|
|
50
|
-
// Fall back to local ./actions
|
|
51
|
-
PathBuf::from("./actions")
|
|
57
|
+
// Fall back to local ./src/actions
|
|
58
|
+
PathBuf::from("./src/actions")
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
/// Try to find the directory that contains compiled action bundles.
|
|
55
62
|
pub fn find_actions_dir(project_root: &PathBuf) -> Option<PathBuf> {
|
|
56
63
|
let candidates = [
|
|
64
|
+
project_root.join("server").join("src").join("actions"),
|
|
65
|
+
project_root.join("server").join("actions"),
|
|
57
66
|
project_root.join("app").join("actions"),
|
|
58
67
|
project_root.join("actions"),
|
|
59
|
-
|
|
68
|
+
|
|
60
69
|
project_root.join("..").join("server").join("actions"),
|
|
61
70
|
PathBuf::from("/app").join("actions"),
|
|
62
71
|
PathBuf::from("actions"),
|
|
@@ -71,8 +80,7 @@ pub fn find_actions_dir(project_root: &PathBuf) -> Option<PathBuf> {
|
|
|
71
80
|
None
|
|
72
81
|
}
|
|
73
82
|
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
/// Match a dynamic route against the current request path.
|
|
76
84
|
pub fn match_dynamic_route(
|
|
77
85
|
method: &str,
|
|
78
86
|
path: &str,
|
|
@@ -131,24 +139,20 @@ pub fn match_dynamic_route(
|
|
|
131
139
|
None
|
|
132
140
|
}
|
|
133
141
|
|
|
134
|
-
|
|
135
|
-
// ACTION SCANNING
|
|
136
|
-
// -------------------------
|
|
137
|
-
|
|
142
|
+
/// Scan the resolved actions directory and return a map of action names to file paths.
|
|
138
143
|
pub fn scan_actions(root: &PathBuf) -> HashMap<String, PathBuf> {
|
|
139
144
|
let mut map = HashMap::new();
|
|
140
145
|
|
|
141
|
-
// Locate actions dir
|
|
142
|
-
let
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
Some(d) => d,
|
|
148
|
-
None => return map,
|
|
146
|
+
// Locate actions dir - Priority: project root relative paths
|
|
147
|
+
let dir = match find_actions_dir(root) {
|
|
148
|
+
Some(d) => d,
|
|
149
|
+
None => {
|
|
150
|
+
let ad = resolve_actions_dir();
|
|
151
|
+
if ad.exists() { ad } else { return map; }
|
|
149
152
|
}
|
|
150
153
|
};
|
|
151
154
|
|
|
155
|
+
// Scanning actions
|
|
152
156
|
if let Ok(entries) = std::fs::read_dir(dir) {
|
|
153
157
|
for entry in entries.flatten() {
|
|
154
158
|
let path = entry.path();
|
|
@@ -162,9 +166,10 @@ pub fn scan_actions(root: &PathBuf) -> HashMap<String, PathBuf> {
|
|
|
162
166
|
let file_stem = path.file_stem().and_then(|s| s.to_str()).unwrap_or("");
|
|
163
167
|
if file_stem.is_empty() { continue; }
|
|
164
168
|
|
|
169
|
+
// Found action
|
|
165
170
|
map.insert(file_stem.to_string(), path);
|
|
166
171
|
}
|
|
167
172
|
}
|
|
168
173
|
|
|
169
174
|
map
|
|
170
|
-
}
|
|
175
|
+
}
|