@ezetgalaxy/titan 26.7.5 → 26.8.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 +86 -200
- package/index.js +87 -23
- package/package.json +4 -3
- package/templates/js/_gitignore +37 -0
- package/templates/{package.json → js/package.json} +3 -0
- package/templates/{server → js/server}/actions/hello.jsbundle +4 -1
- package/templates/{server → js/server}/src/extensions.rs +149 -17
- package/templates/{server → js/server}/src/main.rs +1 -6
- package/templates/{titan → js/titan}/bundle.js +22 -9
- package/templates/js/titan/dev.js +258 -0
- package/templates/js/titan/titan.js +122 -0
- 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 +39 -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 +437 -0
- package/templates/rust/server/src/utils.rs +33 -0
- package/templates/rust/titan/bundle.js +157 -0
- package/templates/rust/titan/dev.js +266 -0
- package/templates/{titan → rust/titan}/titan.js +122 -98
- 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/templates/_gitignore +0 -25
- 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}/action_map.json +0 -0
- /package/templates/{server → js/server}/routes.json +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/utils.rs +0 -0
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
#![allow(unused)]
|
|
2
|
-
use
|
|
3
|
-
use jsonwebtoken::{DecodingKey, EncodingKey, Header, Validation, decode, encode};
|
|
2
|
+
use v8;
|
|
4
3
|
use reqwest::{
|
|
5
4
|
blocking::Client,
|
|
6
5
|
header::{HeaderMap, HeaderName, HeaderValue},
|
|
7
6
|
};
|
|
8
|
-
use serde_json::Value;
|
|
9
|
-
use std::path::PathBuf;
|
|
10
7
|
use std::sync::Once;
|
|
8
|
+
use std::path::PathBuf;
|
|
11
9
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
12
|
-
use
|
|
10
|
+
use serde_json::Value;
|
|
11
|
+
use jsonwebtoken::{encode, decode, Header, EncodingKey, DecodingKey, Validation};
|
|
12
|
+
use bcrypt::{hash, verify, DEFAULT_COST};
|
|
13
13
|
|
|
14
14
|
use crate::utils::{blue, gray, green, parse_expires_in};
|
|
15
|
-
use libloading::Library;
|
|
15
|
+
use libloading::{Library};
|
|
16
|
+
use walkdir::WalkDir;
|
|
17
|
+
use std::sync::Mutex;
|
|
16
18
|
use std::collections::HashMap;
|
|
17
19
|
use std::fs;
|
|
18
|
-
use std::sync::Mutex;
|
|
19
|
-
use walkdir::WalkDir;
|
|
20
20
|
|
|
21
21
|
// ----------------------------------------------------------------------------
|
|
22
22
|
// GLOBAL REGISTRY
|
|
@@ -25,7 +25,7 @@ use walkdir::WalkDir;
|
|
|
25
25
|
static REGISTRY: Mutex<Option<Registry>> = Mutex::new(None);
|
|
26
26
|
#[allow(dead_code)]
|
|
27
27
|
struct Registry {
|
|
28
|
-
_libs: Vec<Library>,
|
|
28
|
+
_libs: Vec<Library>,
|
|
29
29
|
modules: Vec<ModuleDef>,
|
|
30
30
|
natives: Vec<NativeFnEntry>, // Flattened list of all native functions
|
|
31
31
|
}
|
|
@@ -73,189 +73,81 @@ pub fn load_project_extensions(root: PathBuf) {
|
|
|
73
73
|
let mut libs = Vec::new();
|
|
74
74
|
let mut all_natives = Vec::new();
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
let nm_root = root.join("node_modules"); // Dev
|
|
84
|
-
let nm_parent = root.parent().map(|p| p.join("node_modules")); // Monorepo
|
|
85
|
-
|
|
86
|
-
// 1) Production
|
|
87
|
-
if ext_dir.exists() {
|
|
88
|
-
search_dirs.push(ext_dir);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// 2) Dev: project node_modules
|
|
92
|
-
if nm_root.exists() {
|
|
93
|
-
search_dirs.push(nm_root.clone());
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// 3) Dev monorepo: parent/node_modules
|
|
97
|
-
if let Some(nmp) = &nm_parent {
|
|
98
|
-
if nmp.exists() {
|
|
99
|
-
search_dirs.push(nmp.clone());
|
|
76
|
+
let mut node_modules = root.join("node_modules");
|
|
77
|
+
if !node_modules.exists() {
|
|
78
|
+
if let Some(parent) = root.parent() {
|
|
79
|
+
let parent_modules = parent.join("node_modules");
|
|
80
|
+
if parent_modules.exists() {
|
|
81
|
+
node_modules = parent_modules;
|
|
82
|
+
}
|
|
100
83
|
}
|
|
101
84
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Normalize and dedupe
|
|
109
|
-
search_dirs.sort();
|
|
110
|
-
search_dirs.dedup();
|
|
111
|
-
|
|
112
|
-
println!("{} Scanning extension directories:", blue("[Titan]"));
|
|
113
|
-
for d in &search_dirs {
|
|
114
|
-
println!(" • {}", d.display());
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// =====================================================
|
|
118
|
-
// 2. Walk and locate titan.json inside search paths
|
|
119
|
-
// =====================================================
|
|
120
|
-
for dir in &search_dirs {
|
|
121
|
-
if !dir.exists() {
|
|
122
|
-
println!(" {} Skipping non-existent directory: {}", crate::utils::yellow("⚠"), dir.display());
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
for entry in WalkDir::new(&dir)
|
|
127
|
-
.min_depth(1)
|
|
128
|
-
.max_depth(5) // Increased depth
|
|
129
|
-
.follow_links(true)
|
|
130
|
-
{
|
|
131
|
-
let entry = match entry {
|
|
132
|
-
Ok(e) => e,
|
|
133
|
-
Err(_) => continue,
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
// Only accept titan.json files
|
|
85
|
+
|
|
86
|
+
if node_modules.exists() {
|
|
87
|
+
for entry in WalkDir::new(&node_modules).follow_links(true).min_depth(1).max_depth(4) {
|
|
88
|
+
let entry = match entry { Ok(e) => e, Err(_) => continue };
|
|
137
89
|
if entry.file_type().is_file() && entry.file_name() == "titan.json" {
|
|
138
|
-
let
|
|
139
|
-
|
|
140
|
-
let config_content = match fs::read_to_string(path) {
|
|
141
|
-
Ok(c) => c,
|
|
142
|
-
Err(e) => {
|
|
143
|
-
println!("{} Failed to read {}: {}", crate::utils::red("[Titan]"), path.display(), e);
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
let config: TitanConfig = match serde_json::from_str(&config_content) {
|
|
149
|
-
Ok(c) => c,
|
|
150
|
-
Err(e) => {
|
|
151
|
-
println!("{} Failed to parse {}: {}", crate::utils::red("[Titan]"), path.display(), e);
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
let pkg_dir = path.parent().unwrap();
|
|
157
|
-
let mut mod_natives_map = HashMap::new();
|
|
158
|
-
|
|
159
|
-
// =====================================================
|
|
160
|
-
// 3. Load native extension (optional)
|
|
161
|
-
// =====================================================
|
|
162
|
-
if let Some(native_conf) = config.native {
|
|
163
|
-
let lib_path = pkg_dir.join(&native_conf.path);
|
|
164
|
-
|
|
165
|
-
unsafe {
|
|
166
|
-
match Library::new(&lib_path) {
|
|
167
|
-
Ok(lib) => {
|
|
168
|
-
for (fn_name, fn_conf) in native_conf.functions {
|
|
169
|
-
let sig = if fn_conf.parameters == ["f64", "f64"]
|
|
170
|
-
&& fn_conf.result == "f64"
|
|
171
|
-
{
|
|
172
|
-
Signature::F64TwoArgsRetF64
|
|
173
|
-
} else {
|
|
174
|
-
Signature::Unknown
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
if let Ok(symbol) = lib.get::<*const ()>(fn_conf.symbol.as_bytes())
|
|
178
|
-
{
|
|
179
|
-
let idx = all_natives.len();
|
|
180
|
-
all_natives.push(NativeFnEntry {
|
|
181
|
-
ptr: *symbol as usize,
|
|
182
|
-
sig,
|
|
183
|
-
});
|
|
184
|
-
mod_natives_map.insert(fn_name, idx);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
libs.push(lib);
|
|
188
|
-
}
|
|
189
|
-
Err(e) => println!(
|
|
190
|
-
"{} Failed to load native library {} ({})",
|
|
191
|
-
blue("[Titan]"),
|
|
192
|
-
lib_path.display(),
|
|
193
|
-
e
|
|
194
|
-
),
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// =====================================================
|
|
200
|
-
// 4. Load JS module file
|
|
201
|
-
// =====================================================
|
|
202
|
-
let js_path = pkg_dir.join(&config.main);
|
|
203
|
-
let js_content = match fs::read_to_string(&js_path) {
|
|
90
|
+
let dir = entry.path().parent().unwrap();
|
|
91
|
+
let config_content = match fs::read_to_string(entry.path()) {
|
|
204
92
|
Ok(c) => c,
|
|
205
|
-
Err(
|
|
206
|
-
println!("{} Failed to read JS main {} for extension {}: {}",
|
|
207
|
-
crate::utils::red("[Titan]"),
|
|
208
|
-
js_path.display(),
|
|
209
|
-
config.name,
|
|
210
|
-
e
|
|
211
|
-
);
|
|
212
|
-
continue;
|
|
213
|
-
}
|
|
93
|
+
Err(_) => continue,
|
|
214
94
|
};
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
95
|
+
let config: TitanConfig = match serde_json::from_str(&config_content) {
|
|
96
|
+
Ok(c) => c,
|
|
97
|
+
Err(_) => continue,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
let mut mod_natives_map = HashMap::new();
|
|
101
|
+
|
|
102
|
+
if let Some(native_conf) = config.native {
|
|
103
|
+
let lib_path = dir.join(&native_conf.path);
|
|
104
|
+
unsafe {
|
|
105
|
+
match Library::new(&lib_path) {
|
|
106
|
+
Ok(lib) => {
|
|
107
|
+
for (fn_name, fn_conf) in native_conf.functions {
|
|
108
|
+
let sig = if fn_conf.parameters.len() == 2
|
|
109
|
+
&& fn_conf.parameters[0] == "f64"
|
|
110
|
+
&& fn_conf.parameters[1] == "f64"
|
|
111
|
+
&& fn_conf.result == "f64" {
|
|
112
|
+
Signature::F64TwoArgsRetF64
|
|
113
|
+
} else {
|
|
114
|
+
Signature::Unknown
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
if let Ok(symbol) = lib.get::<*const ()>(fn_conf.symbol.as_bytes()) {
|
|
118
|
+
let idx = all_natives.len();
|
|
119
|
+
all_natives.push(NativeFnEntry {
|
|
120
|
+
ptr: *symbol as usize,
|
|
121
|
+
sig
|
|
122
|
+
});
|
|
123
|
+
mod_natives_map.insert(fn_name, idx);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
libs.push(lib);
|
|
127
|
+
},
|
|
128
|
+
Err(e) => println!("Failed to load extension library {}: {}", lib_path.display(), e),
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
let js_path = dir.join(&config.main);
|
|
134
|
+
let js_content = fs::read_to_string(js_path).unwrap_or_default();
|
|
135
|
+
|
|
136
|
+
modules.push(ModuleDef {
|
|
137
|
+
name: config.name.clone(),
|
|
138
|
+
js: js_content,
|
|
139
|
+
native_indices: mod_natives_map,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
println!("{} {} {}", blue("[Titan]"), green("Extension loaded:"), config.name);
|
|
228
143
|
}
|
|
229
144
|
}
|
|
230
145
|
}
|
|
231
146
|
|
|
232
|
-
|
|
233
|
-
// 5. Store registry globally
|
|
234
|
-
// =====================================================
|
|
235
|
-
if modules.is_empty() {
|
|
236
|
-
println!("{} {}", blue("[Titan]"), crate::utils::yellow("No extensions loaded."));
|
|
237
|
-
// Debug: list files in search dirs to assist debugging
|
|
238
|
-
for dir in &search_dirs {
|
|
239
|
-
if dir.exists() {
|
|
240
|
-
println!("{} Listing contents of {}:", blue("[Titan]"), dir.display());
|
|
241
|
-
for entry in WalkDir::new(dir).max_depth(5) {
|
|
242
|
-
if let Ok(e) = entry {
|
|
243
|
-
println!(" - {}", e.path().display());
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
} else {
|
|
247
|
-
println!("{} Directory not found: {}", blue("[Titan]"), dir.display());
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
*REGISTRY.lock().unwrap() = Some(Registry {
|
|
253
|
-
_libs: libs,
|
|
254
|
-
modules,
|
|
255
|
-
natives: all_natives,
|
|
256
|
-
});
|
|
147
|
+
*REGISTRY.lock().unwrap() = Some(Registry { _libs: libs, modules, natives: all_natives });
|
|
257
148
|
}
|
|
258
149
|
|
|
150
|
+
|
|
259
151
|
static V8_INIT: Once = Once::new();
|
|
260
152
|
|
|
261
153
|
pub fn init_v8() {
|
|
@@ -284,11 +176,7 @@ fn throw(scope: &mut v8::HandleScope, msg: &str) {
|
|
|
284
176
|
// NATIVE CALLBACKS
|
|
285
177
|
// ----------------------------------------------------------------------------
|
|
286
178
|
|
|
287
|
-
fn native_read(
|
|
288
|
-
scope: &mut v8::HandleScope,
|
|
289
|
-
args: v8::FunctionCallbackArguments,
|
|
290
|
-
mut retval: v8::ReturnValue,
|
|
291
|
-
) {
|
|
179
|
+
fn native_read(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue) {
|
|
292
180
|
let path_val = args.get(0);
|
|
293
181
|
// 1. Read argument
|
|
294
182
|
if !path_val.is_string() {
|
|
@@ -307,7 +195,7 @@ fn native_read(
|
|
|
307
195
|
let global = context.global(scope);
|
|
308
196
|
let root_key = v8_str(scope, "__titan_root");
|
|
309
197
|
let root_val = global.get(scope, root_key.into()).unwrap();
|
|
310
|
-
|
|
198
|
+
|
|
311
199
|
let root_str = if root_val.is_string() {
|
|
312
200
|
v8_to_string(scope, root_val)
|
|
313
201
|
} else {
|
|
@@ -338,18 +226,14 @@ fn native_read(
|
|
|
338
226
|
match std::fs::read_to_string(&target) {
|
|
339
227
|
Ok(content) => {
|
|
340
228
|
retval.set(v8_str(scope, &content).into());
|
|
341
|
-
}
|
|
229
|
+
},
|
|
342
230
|
Err(e) => {
|
|
343
231
|
throw(scope, &format!("t.read failed: {}", e));
|
|
344
232
|
}
|
|
345
233
|
}
|
|
346
234
|
}
|
|
347
235
|
|
|
348
|
-
fn native_log(
|
|
349
|
-
scope: &mut v8::HandleScope,
|
|
350
|
-
args: v8::FunctionCallbackArguments,
|
|
351
|
-
mut _retval: v8::ReturnValue,
|
|
352
|
-
) {
|
|
236
|
+
fn native_log(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut _retval: v8::ReturnValue) {
|
|
353
237
|
let context = scope.get_current_context();
|
|
354
238
|
let global = context.global(scope);
|
|
355
239
|
let action_key = v8_str(scope, "__titan_action");
|
|
@@ -360,38 +244,30 @@ fn native_log(
|
|
|
360
244
|
for i in 0..args.length() {
|
|
361
245
|
let val = args.get(i);
|
|
362
246
|
let mut appended = false;
|
|
363
|
-
|
|
247
|
+
|
|
364
248
|
// Try to JSON stringify objects so they are readable in logs
|
|
365
249
|
if val.is_object() && !val.is_function() {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
250
|
+
if let Some(json) = v8::json::stringify(scope, val) {
|
|
251
|
+
parts.push(json.to_rust_string_lossy(scope));
|
|
252
|
+
appended = true;
|
|
253
|
+
}
|
|
370
254
|
}
|
|
371
|
-
|
|
255
|
+
|
|
372
256
|
if !appended {
|
|
373
257
|
parts.push(v8_to_string(scope, val));
|
|
374
258
|
}
|
|
375
259
|
}
|
|
376
|
-
|
|
260
|
+
|
|
377
261
|
println!(
|
|
378
262
|
"{} {}",
|
|
379
263
|
blue("[Titan]"),
|
|
380
|
-
gray(&format!(
|
|
381
|
-
"\x1b[90mlog({})\x1b[0m\x1b[97m: {}\x1b[0m",
|
|
382
|
-
action_name,
|
|
383
|
-
parts.join(" ")
|
|
384
|
-
))
|
|
264
|
+
gray(&format!("\x1b[90mlog({})\x1b[0m\x1b[97m: {}\x1b[0m", action_name, parts.join(" ")))
|
|
385
265
|
);
|
|
386
266
|
}
|
|
387
267
|
|
|
388
|
-
fn native_fetch(
|
|
389
|
-
scope: &mut v8::HandleScope,
|
|
390
|
-
args: v8::FunctionCallbackArguments,
|
|
391
|
-
mut retval: v8::ReturnValue,
|
|
392
|
-
) {
|
|
268
|
+
fn native_fetch(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue) {
|
|
393
269
|
let url = v8_to_string(scope, args.get(0));
|
|
394
|
-
|
|
270
|
+
|
|
395
271
|
// Check for options (method, headers, body)
|
|
396
272
|
let mut method = "GET".to_string();
|
|
397
273
|
let mut body_str = None;
|
|
@@ -400,7 +276,7 @@ fn native_fetch(
|
|
|
400
276
|
let opts_val = args.get(1);
|
|
401
277
|
if opts_val.is_object() {
|
|
402
278
|
let opts_obj = opts_val.to_object(scope).unwrap();
|
|
403
|
-
|
|
279
|
+
|
|
404
280
|
// method
|
|
405
281
|
let m_key = v8_str(scope, "method");
|
|
406
282
|
if let Some(m_val) = opts_obj.get(scope, m_key.into()) {
|
|
@@ -408,18 +284,18 @@ fn native_fetch(
|
|
|
408
284
|
method = v8_to_string(scope, m_val);
|
|
409
285
|
}
|
|
410
286
|
}
|
|
411
|
-
|
|
287
|
+
|
|
412
288
|
// body
|
|
413
289
|
let b_key = v8_str(scope, "body");
|
|
414
290
|
if let Some(b_val) = opts_obj.get(scope, b_key.into()) {
|
|
415
291
|
if b_val.is_string() {
|
|
416
292
|
body_str = Some(v8_to_string(scope, b_val));
|
|
417
293
|
} else if b_val.is_object() {
|
|
418
|
-
|
|
419
|
-
|
|
294
|
+
let json_obj = v8::json::stringify(scope, b_val).unwrap();
|
|
295
|
+
body_str = Some(json_obj.to_rust_string_lossy(scope));
|
|
420
296
|
}
|
|
421
297
|
}
|
|
422
|
-
|
|
298
|
+
|
|
423
299
|
// headers
|
|
424
300
|
let h_key = v8_str(scope, "headers");
|
|
425
301
|
if let Some(h_val) = opts_obj.get(scope, h_key.into()) {
|
|
@@ -429,61 +305,57 @@ fn native_fetch(
|
|
|
429
305
|
for i in 0..keys.length() {
|
|
430
306
|
let key = keys.get_index(scope, i).unwrap();
|
|
431
307
|
let val = h_obj.get(scope, key).unwrap();
|
|
432
|
-
headers_vec.push((
|
|
308
|
+
headers_vec.push((
|
|
309
|
+
v8_to_string(scope, key),
|
|
310
|
+
v8_to_string(scope, val),
|
|
311
|
+
));
|
|
433
312
|
}
|
|
434
313
|
}
|
|
435
314
|
}
|
|
436
315
|
}
|
|
437
316
|
}
|
|
438
317
|
|
|
439
|
-
let client = Client::builder()
|
|
440
|
-
|
|
441
|
-
.tcp_nodelay(true)
|
|
442
|
-
.build()
|
|
443
|
-
.unwrap_or(Client::new());
|
|
444
|
-
|
|
318
|
+
let client = Client::builder().use_rustls_tls().tcp_nodelay(true).build().unwrap_or(Client::new());
|
|
319
|
+
|
|
445
320
|
let mut req = client.request(method.parse().unwrap_or(reqwest::Method::GET), &url);
|
|
446
|
-
|
|
321
|
+
|
|
447
322
|
for (k, v) in headers_vec {
|
|
448
|
-
if let (Ok(name), Ok(val)) = (
|
|
449
|
-
HeaderName::from_bytes(k.as_bytes()),
|
|
450
|
-
HeaderValue::from_str(&v),
|
|
451
|
-
) {
|
|
323
|
+
if let (Ok(name), Ok(val)) = (HeaderName::from_bytes(k.as_bytes()), HeaderValue::from_str(&v)) {
|
|
452
324
|
let mut map = HeaderMap::new();
|
|
453
325
|
map.insert(name, val);
|
|
454
326
|
req = req.headers(map);
|
|
455
327
|
}
|
|
456
328
|
}
|
|
457
|
-
|
|
329
|
+
|
|
458
330
|
if let Some(b) = body_str {
|
|
459
331
|
req = req.body(b);
|
|
460
332
|
}
|
|
461
|
-
|
|
333
|
+
|
|
462
334
|
let res = req.send();
|
|
463
|
-
|
|
335
|
+
|
|
464
336
|
let obj = v8::Object::new(scope);
|
|
465
337
|
match res {
|
|
466
338
|
Ok(r) => {
|
|
467
339
|
let status = r.status().as_u16();
|
|
468
340
|
let text = r.text().unwrap_or_default();
|
|
469
|
-
|
|
341
|
+
|
|
470
342
|
let status_key = v8_str(scope, "status");
|
|
471
343
|
let status_val = v8::Number::new(scope, status as f64);
|
|
472
344
|
obj.set(scope, status_key.into(), status_val.into());
|
|
473
|
-
|
|
345
|
+
|
|
474
346
|
let body_key = v8_str(scope, "body");
|
|
475
347
|
let body_val = v8_str(scope, &text);
|
|
476
348
|
obj.set(scope, body_key.into(), body_val.into());
|
|
477
|
-
|
|
349
|
+
|
|
478
350
|
let ok_key = v8_str(scope, "ok");
|
|
479
351
|
let ok_val = v8::Boolean::new(scope, true);
|
|
480
352
|
obj.set(scope, ok_key.into(), ok_val.into());
|
|
481
|
-
}
|
|
353
|
+
},
|
|
482
354
|
Err(e) => {
|
|
483
355
|
let ok_key = v8_str(scope, "ok");
|
|
484
356
|
let ok_val = v8::Boolean::new(scope, false);
|
|
485
357
|
obj.set(scope, ok_key.into(), ok_val.into());
|
|
486
|
-
|
|
358
|
+
|
|
487
359
|
let err_key = v8_str(scope, "error");
|
|
488
360
|
let err_val = v8_str(scope, &e.to_string());
|
|
489
361
|
obj.set(scope, err_key.into(), err_val.into());
|
|
@@ -492,46 +364,33 @@ fn native_fetch(
|
|
|
492
364
|
retval.set(obj.into());
|
|
493
365
|
}
|
|
494
366
|
|
|
495
|
-
fn native_jwt_sign(
|
|
496
|
-
scope: &mut v8::HandleScope,
|
|
497
|
-
args: v8::FunctionCallbackArguments,
|
|
498
|
-
mut retval: v8::ReturnValue,
|
|
499
|
-
) {
|
|
367
|
+
fn native_jwt_sign(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue) {
|
|
500
368
|
// payload, secret, options
|
|
501
369
|
let payload_val = args.get(0);
|
|
502
370
|
// Parse payload to serde_json::Map
|
|
503
|
-
let json_str = v8::json::stringify(scope, payload_val)
|
|
504
|
-
|
|
505
|
-
.to_rust_string_lossy(scope);
|
|
506
|
-
let mut payload: serde_json::Map<String, Value> =
|
|
507
|
-
serde_json::from_str(&json_str).unwrap_or_default();
|
|
371
|
+
let json_str = v8::json::stringify(scope, payload_val).unwrap().to_rust_string_lossy(scope);
|
|
372
|
+
let mut payload: serde_json::Map<String, Value> = serde_json::from_str(&json_str).unwrap_or_default();
|
|
508
373
|
|
|
509
374
|
let secret = v8_to_string(scope, args.get(1));
|
|
510
|
-
|
|
375
|
+
|
|
511
376
|
let opts_val = args.get(2);
|
|
512
377
|
if opts_val.is_object() {
|
|
513
378
|
let opts_obj = opts_val.to_object(scope).unwrap();
|
|
514
379
|
let exp_key = v8_str(scope, "expiresIn");
|
|
515
|
-
|
|
380
|
+
|
|
516
381
|
if let Some(val) = opts_obj.get(scope, exp_key.into()) {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
let now = SystemTime::now()
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
.as_secs();
|
|
530
|
-
payload.insert(
|
|
531
|
-
"exp".to_string(),
|
|
532
|
-
Value::Number(serde_json::Number::from(now + sec)),
|
|
533
|
-
);
|
|
534
|
-
}
|
|
382
|
+
let seconds = if val.is_number() {
|
|
383
|
+
Some(val.to_number(scope).unwrap().value() as u64)
|
|
384
|
+
} else if val.is_string() {
|
|
385
|
+
parse_expires_in(&v8_to_string(scope, val))
|
|
386
|
+
} else {
|
|
387
|
+
None
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
if let Some(sec) = seconds {
|
|
391
|
+
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
|
|
392
|
+
payload.insert("exp".to_string(), Value::Number(serde_json::Number::from(now + sec)));
|
|
393
|
+
}
|
|
535
394
|
}
|
|
536
395
|
}
|
|
537
396
|
|
|
@@ -547,41 +406,33 @@ fn native_jwt_sign(
|
|
|
547
406
|
}
|
|
548
407
|
}
|
|
549
408
|
|
|
550
|
-
fn native_jwt_verify(
|
|
551
|
-
scope: &mut v8::HandleScope,
|
|
552
|
-
args: v8::FunctionCallbackArguments,
|
|
553
|
-
mut retval: v8::ReturnValue,
|
|
554
|
-
) {
|
|
409
|
+
fn native_jwt_verify(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue) {
|
|
555
410
|
let token = v8_to_string(scope, args.get(0));
|
|
556
411
|
let secret = v8_to_string(scope, args.get(1));
|
|
557
|
-
|
|
412
|
+
|
|
558
413
|
let mut validation = Validation::default();
|
|
559
414
|
validation.validate_exp = true;
|
|
560
|
-
|
|
415
|
+
|
|
561
416
|
let data = decode::<Value>(
|
|
562
417
|
&token,
|
|
563
418
|
&DecodingKey::from_secret(secret.as_bytes()),
|
|
564
419
|
&validation,
|
|
565
420
|
);
|
|
566
|
-
|
|
421
|
+
|
|
567
422
|
match data {
|
|
568
423
|
Ok(d) => {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}
|
|
424
|
+
// Convert claim back to V8 object via JSON
|
|
425
|
+
let json_str = serde_json::to_string(&d.claims).unwrap();
|
|
426
|
+
let v8_json_str = v8_str(scope, &json_str);
|
|
427
|
+
if let Some(val) = v8::json::parse(scope, v8_json_str) {
|
|
428
|
+
retval.set(val);
|
|
429
|
+
}
|
|
430
|
+
},
|
|
576
431
|
Err(e) => throw(scope, &format!("Invalid or expired JWT: {}", e)),
|
|
577
432
|
}
|
|
578
433
|
}
|
|
579
434
|
|
|
580
|
-
fn native_password_hash(
|
|
581
|
-
scope: &mut v8::HandleScope,
|
|
582
|
-
args: v8::FunctionCallbackArguments,
|
|
583
|
-
mut retval: v8::ReturnValue,
|
|
584
|
-
) {
|
|
435
|
+
fn native_password_hash(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue) {
|
|
585
436
|
let pw = v8_to_string(scope, args.get(0));
|
|
586
437
|
match hash(pw, DEFAULT_COST) {
|
|
587
438
|
Ok(h) => retval.set(v8_str(scope, &h).into()),
|
|
@@ -589,23 +440,15 @@ fn native_password_hash(
|
|
|
589
440
|
}
|
|
590
441
|
}
|
|
591
442
|
|
|
592
|
-
fn native_password_verify(
|
|
593
|
-
scope: &mut v8::HandleScope,
|
|
594
|
-
args: v8::FunctionCallbackArguments,
|
|
595
|
-
mut retval: v8::ReturnValue,
|
|
596
|
-
) {
|
|
443
|
+
fn native_password_verify(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue) {
|
|
597
444
|
let pw = v8_to_string(scope, args.get(0));
|
|
598
445
|
let hash_str = v8_to_string(scope, args.get(1));
|
|
599
|
-
|
|
446
|
+
|
|
600
447
|
let ok = verify(pw, &hash_str).unwrap_or(false);
|
|
601
448
|
retval.set(v8::Boolean::new(scope, ok).into());
|
|
602
449
|
}
|
|
603
450
|
|
|
604
|
-
fn native_define_action(
|
|
605
|
-
_scope: &mut v8::HandleScope,
|
|
606
|
-
args: v8::FunctionCallbackArguments,
|
|
607
|
-
mut retval: v8::ReturnValue,
|
|
608
|
-
) {
|
|
451
|
+
fn native_define_action(_scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue) {
|
|
609
452
|
retval.set(args.get(0));
|
|
610
453
|
}
|
|
611
454
|
|
|
@@ -615,17 +458,13 @@ fn native_define_action(
|
|
|
615
458
|
|
|
616
459
|
// generic wrappers could go here if needed
|
|
617
460
|
|
|
618
|
-
fn native_invoke_extension(
|
|
619
|
-
scope: &mut v8::HandleScope,
|
|
620
|
-
args: v8::FunctionCallbackArguments,
|
|
621
|
-
mut retval: v8::ReturnValue,
|
|
622
|
-
) {
|
|
461
|
+
fn native_invoke_extension(scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue) {
|
|
623
462
|
let fn_idx = args.get(0).to_integer(scope).unwrap().value() as usize;
|
|
624
463
|
|
|
625
464
|
// Get pointer from registry
|
|
626
465
|
let mut ptr = 0;
|
|
627
466
|
let mut sig = Signature::Unknown;
|
|
628
|
-
|
|
467
|
+
|
|
629
468
|
if let Ok(guard) = REGISTRY.lock() {
|
|
630
469
|
if let Some(registry) = &*guard {
|
|
631
470
|
if let Some(entry) = registry.natives.get(fn_idx) {
|
|
@@ -634,39 +473,33 @@ fn native_invoke_extension(
|
|
|
634
473
|
}
|
|
635
474
|
}
|
|
636
475
|
}
|
|
637
|
-
|
|
476
|
+
|
|
638
477
|
if ptr == 0 {
|
|
639
|
-
|
|
640
|
-
|
|
478
|
+
throw(scope, "Native function not found");
|
|
479
|
+
return;
|
|
641
480
|
}
|
|
642
481
|
|
|
643
482
|
match sig {
|
|
644
483
|
Signature::F64TwoArgsRetF64 => {
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
.value();
|
|
655
|
-
|
|
656
|
-
unsafe {
|
|
657
|
-
let func: extern "C" fn(f64, f64) -> f64 = std::mem::transmute(ptr);
|
|
658
|
-
let res = func(a, b);
|
|
659
|
-
retval.set(v8::Number::new(scope, res).into());
|
|
660
|
-
}
|
|
661
|
-
}
|
|
484
|
+
let a = args.get(1).to_number(scope).unwrap_or(v8::Number::new(scope, 0.0)).value();
|
|
485
|
+
let b = args.get(2).to_number(scope).unwrap_or(v8::Number::new(scope, 0.0)).value();
|
|
486
|
+
|
|
487
|
+
unsafe {
|
|
488
|
+
let func: extern "C" fn(f64, f64) -> f64 = std::mem::transmute(ptr);
|
|
489
|
+
let res = func(a, b);
|
|
490
|
+
retval.set(v8::Number::new(scope, res).into());
|
|
491
|
+
}
|
|
492
|
+
},
|
|
662
493
|
_ => throw(scope, "Unsupported signature"),
|
|
663
494
|
}
|
|
664
495
|
}
|
|
665
496
|
|
|
497
|
+
|
|
666
498
|
// ----------------------------------------------------------------------------
|
|
667
499
|
// INJECTOR
|
|
668
500
|
// ----------------------------------------------------------------------------
|
|
669
501
|
|
|
502
|
+
|
|
670
503
|
pub fn inject_extensions(scope: &mut v8::HandleScope, global: v8::Local<v8::Object>) {
|
|
671
504
|
// Ensure globalThis reference
|
|
672
505
|
let gt_key = v8_str(scope, "globalThis");
|
|
@@ -675,15 +508,13 @@ pub fn inject_extensions(scope: &mut v8::HandleScope, global: v8::Local<v8::Obje
|
|
|
675
508
|
let t_obj = v8::Object::new(scope);
|
|
676
509
|
let t_key = v8_str(scope, "t");
|
|
677
510
|
// Use create_data_property to guarantee definition
|
|
678
|
-
global
|
|
679
|
-
.create_data_property(scope, t_key.into(), t_obj.into())
|
|
680
|
-
.unwrap();
|
|
511
|
+
global.create_data_property(scope, t_key.into(), t_obj.into()).unwrap();
|
|
681
512
|
|
|
682
513
|
// defineAction (identity function for clean typing)
|
|
683
514
|
let def_fn = v8::Function::new(scope, native_define_action).unwrap();
|
|
684
515
|
let def_key = v8_str(scope, "defineAction");
|
|
685
516
|
global.set(scope, def_key.into(), def_fn.into());
|
|
686
|
-
|
|
517
|
+
|
|
687
518
|
// t.read
|
|
688
519
|
let read_fn = v8::Function::new(scope, native_read).unwrap();
|
|
689
520
|
let read_key = v8_str(scope, "read");
|
|
@@ -693,7 +524,7 @@ pub fn inject_extensions(scope: &mut v8::HandleScope, global: v8::Local<v8::Obje
|
|
|
693
524
|
let log_fn = v8::Function::new(scope, native_log).unwrap();
|
|
694
525
|
let log_key = v8_str(scope, "log");
|
|
695
526
|
t_obj.set(scope, log_key.into(), log_fn.into());
|
|
696
|
-
|
|
527
|
+
|
|
697
528
|
// t.fetch
|
|
698
529
|
let fetch_fn = v8::Function::new(scope, native_fetch).unwrap();
|
|
699
530
|
let fetch_key = v8_str(scope, "fetch");
|
|
@@ -703,12 +534,12 @@ pub fn inject_extensions(scope: &mut v8::HandleScope, global: v8::Local<v8::Obje
|
|
|
703
534
|
let jwt_obj = v8::Object::new(scope);
|
|
704
535
|
let sign_fn = v8::Function::new(scope, native_jwt_sign).unwrap();
|
|
705
536
|
let verify_fn = v8::Function::new(scope, native_jwt_verify).unwrap();
|
|
706
|
-
|
|
537
|
+
|
|
707
538
|
let sign_key = v8_str(scope, "sign");
|
|
708
539
|
jwt_obj.set(scope, sign_key.into(), sign_fn.into());
|
|
709
540
|
let verify_key = v8_str(scope, "verify");
|
|
710
541
|
jwt_obj.set(scope, verify_key.into(), verify_fn.into());
|
|
711
|
-
|
|
542
|
+
|
|
712
543
|
let jwt_key = v8_str(scope, "jwt");
|
|
713
544
|
t_obj.set(scope, jwt_key.into(), jwt_obj.into());
|
|
714
545
|
|
|
@@ -716,15 +547,16 @@ pub fn inject_extensions(scope: &mut v8::HandleScope, global: v8::Local<v8::Obje
|
|
|
716
547
|
let pw_obj = v8::Object::new(scope);
|
|
717
548
|
let hash_fn = v8::Function::new(scope, native_password_hash).unwrap();
|
|
718
549
|
let pw_verify_fn = v8::Function::new(scope, native_password_verify).unwrap();
|
|
719
|
-
|
|
550
|
+
|
|
720
551
|
let hash_key = v8_str(scope, "hash");
|
|
721
552
|
pw_obj.set(scope, hash_key.into(), hash_fn.into());
|
|
722
553
|
let pw_verify_key = v8_str(scope, "verify");
|
|
723
554
|
pw_obj.set(scope, pw_verify_key.into(), pw_verify_fn.into());
|
|
724
|
-
|
|
555
|
+
|
|
725
556
|
let pw_key = v8_str(scope, "password");
|
|
726
557
|
t_obj.set(scope, pw_key.into(), pw_obj.into());
|
|
727
558
|
|
|
559
|
+
|
|
728
560
|
// Inject __titan_invoke_native
|
|
729
561
|
let invoke_fn = v8::Function::new(scope, native_invoke_extension).unwrap();
|
|
730
562
|
let invoke_key = v8_str(scope, "__titan_invoke_native");
|
|
@@ -742,97 +574,60 @@ pub fn inject_extensions(scope: &mut v8::HandleScope, global: v8::Local<v8::Obje
|
|
|
742
574
|
};
|
|
743
575
|
|
|
744
576
|
for module in modules {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
let text = msg.get(&mut *tc).to_rust_string_lossy(&mut *tc);
|
|
800
|
-
println!(
|
|
801
|
-
"{} {} {} -> {}",
|
|
802
|
-
crate::utils::blue("[Titan]"),
|
|
803
|
-
crate::utils::red("Error running extension"),
|
|
804
|
-
module.name,
|
|
805
|
-
text
|
|
806
|
-
);
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
} else {
|
|
811
|
-
// Runtime error during script run
|
|
812
|
-
if let Some(msg) = tc.message() {
|
|
813
|
-
let text = msg.get(&mut *tc).to_rust_string_lossy(&mut *tc);
|
|
814
|
-
println!(
|
|
815
|
-
"{} {} {} -> {}",
|
|
816
|
-
crate::utils::blue("[Titan]"),
|
|
817
|
-
crate::utils::red("Error evaluating extension wrapper"),
|
|
818
|
-
module.name,
|
|
819
|
-
text
|
|
820
|
-
);
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
} else {
|
|
824
|
-
// Compile error
|
|
825
|
-
if let Some(msg) = tc.message() {
|
|
826
|
-
let text = msg.get(&mut *tc).to_rust_string_lossy(&mut *tc);
|
|
827
|
-
println!(
|
|
828
|
-
"{} {} {} -> {}",
|
|
829
|
-
crate::utils::blue("[Titan]"),
|
|
830
|
-
crate::utils::red("Syntax Error in extension"),
|
|
831
|
-
module.name,
|
|
832
|
-
text
|
|
833
|
-
);
|
|
834
|
-
}
|
|
835
|
-
}
|
|
577
|
+
let mod_obj = v8::Object::new(scope);
|
|
578
|
+
|
|
579
|
+
// Generate JS wrappers
|
|
580
|
+
for (fn_name, &idx) in &module.native_indices {
|
|
581
|
+
let code = format!("(function(a, b) {{ return __titan_invoke_native({}, a, b); }})", idx);
|
|
582
|
+
let source = v8_str(scope, &code);
|
|
583
|
+
if let Some(script) = v8::Script::compile(scope, source, None) {
|
|
584
|
+
if let Some(val) = script.run(scope) {
|
|
585
|
+
let key = v8_str(scope, fn_name);
|
|
586
|
+
mod_obj.set(scope, key.into(), val);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Inject t.<module_name>
|
|
592
|
+
let mod_key = v8_str(scope, &module.name);
|
|
593
|
+
t_obj.set(scope, mod_key.into(), mod_obj.into());
|
|
594
|
+
|
|
595
|
+
// Set context for logging
|
|
596
|
+
let action_key = v8_str(scope, "__titan_action");
|
|
597
|
+
let action_val = v8_str(scope, &module.name);
|
|
598
|
+
global.set(scope, action_key.into(), action_val.into());
|
|
599
|
+
|
|
600
|
+
// Execute JS
|
|
601
|
+
// Wrap in IIFE passing 't' to ensure visibility
|
|
602
|
+
let wrapped_js = format!("(function(t) {{ {} }})", module.js);
|
|
603
|
+
let source = v8_str(scope, &wrapped_js);
|
|
604
|
+
let tc = &mut v8::TryCatch::new(scope);
|
|
605
|
+
|
|
606
|
+
if let Some(script) = v8::Script::compile(tc, source, None) {
|
|
607
|
+
if let Some(func_val) = script.run(tc) {
|
|
608
|
+
// func_val is the function. Call it with [t_obj]
|
|
609
|
+
if let Ok(func) = v8::Local::<v8::Function>::try_from(func_val) {
|
|
610
|
+
let receiver = v8::undefined(&mut *tc).into();
|
|
611
|
+
let args = [t_obj.into()];
|
|
612
|
+
// Pass tc (which is a scope)
|
|
613
|
+
if func.call(&mut *tc, receiver, &args).is_none() {
|
|
614
|
+
println!("{} {}", crate::utils::blue("[Titan]"), crate::utils::red("Extension Execution Failed"));
|
|
615
|
+
if let Some(msg) = tc.message() {
|
|
616
|
+
let text = msg.get(&mut *tc).to_rust_string_lossy(&mut *tc);
|
|
617
|
+
println!("{} {}", crate::utils::red("Error details:"), text);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
} else {
|
|
622
|
+
let msg = tc.message().unwrap();
|
|
623
|
+
let text = msg.get(&mut *tc).to_rust_string_lossy(&mut *tc);
|
|
624
|
+
println!("{} {} {}", crate::utils::blue("[Titan]"), crate::utils::red("Extension JS Error:"), text);
|
|
625
|
+
}
|
|
626
|
+
} else {
|
|
627
|
+
let msg = tc.message().unwrap();
|
|
628
|
+
let text = msg.get(&mut *tc).to_rust_string_lossy(&mut *tc);
|
|
629
|
+
println!("{} {} {}", crate::utils::blue("[Titan]"), crate::utils::red("Extension Compile Error:"), text);
|
|
630
|
+
}
|
|
836
631
|
}
|
|
837
632
|
|
|
838
633
|
// t.db (Stub for now)
|