titanpl 6.0.0 → 7.0.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.
Files changed (227) hide show
  1. package/package.json +2 -6
  2. package/packages/cli/index.js +25 -11
  3. package/packages/cli/package.json +4 -4
  4. package/packages/cli/src/commands/build-ext.js +157 -0
  5. package/packages/cli/src/commands/build.js +12 -0
  6. package/packages/cli/src/commands/create.js +160 -0
  7. package/packages/cli/src/commands/init.js +5 -11
  8. package/packages/cli/src/commands/run-ext.js +104 -0
  9. package/{titanpl-sdk → packages/core-source}/LICENSE +1 -1
  10. package/packages/core-source/README.md +128 -0
  11. package/packages/core-source/V8_SERIALIZATION.md +125 -0
  12. package/packages/core-source/configure.js +50 -0
  13. package/packages/core-source/globals.d.ts +2238 -0
  14. package/packages/core-source/index.d.ts +515 -0
  15. package/packages/core-source/index.js +639 -0
  16. package/packages/core-source/jsconfig.json +12 -0
  17. package/packages/core-source/mkctx.config.json +7 -0
  18. package/packages/core-source/native/Cargo.lock +1559 -0
  19. package/packages/core-source/native/Cargo.toml +30 -0
  20. package/packages/core-source/native/src/crypto_impl.rs +139 -0
  21. package/packages/core-source/native/src/lib.rs +702 -0
  22. package/packages/core-source/native/src/storage_impl.rs +73 -0
  23. package/packages/core-source/native/src/v8_impl.rs +93 -0
  24. package/packages/core-source/package-lock.json +1464 -0
  25. package/packages/core-source/package.json +53 -0
  26. package/packages/core-source/tests/buffer.test.js +78 -0
  27. package/packages/core-source/tests/cookies.test.js +117 -0
  28. package/packages/core-source/tests/crypto.test.js +142 -0
  29. package/packages/core-source/tests/fs.test.js +176 -0
  30. package/packages/core-source/tests/ls.test.js +149 -0
  31. package/packages/core-source/tests/net.test.js +84 -0
  32. package/packages/core-source/tests/os.test.js +81 -0
  33. package/packages/core-source/tests/path.test.js +102 -0
  34. package/packages/core-source/tests/response.test.js +146 -0
  35. package/packages/core-source/tests/session.test.js +110 -0
  36. package/packages/core-source/tests/setup.js +325 -0
  37. package/packages/core-source/tests/time.test.js +57 -0
  38. package/packages/core-source/tests/url.test.js +82 -0
  39. package/packages/core-source/titan-ext.d.ts +2 -0
  40. package/packages/core-source/titan.json +9 -0
  41. package/packages/core-source/vitest.config.js +8 -0
  42. package/packages/engine-darwin-arm64/README.md +0 -2
  43. package/packages/engine-darwin-arm64/package.json +1 -1
  44. package/packages/engine-linux-x64/README.md +0 -2
  45. package/packages/engine-linux-x64/package.json +1 -1
  46. package/packages/engine-win32-x64/README.md +0 -1
  47. package/packages/engine-win32-x64/bin/titan-server.exe +0 -0
  48. package/packages/engine-win32-x64/package.json +1 -1
  49. package/packages/native/README.md +0 -1
  50. package/packages/native/index.d.ts +25 -4
  51. package/packages/native/index.js +7 -0
  52. package/packages/native/package.json +2 -2
  53. package/packages/native/t.native.d.ts +167 -2
  54. package/packages/packet/index.js +103 -94
  55. package/packages/packet/package.json +1 -1
  56. package/packages/route/package.json +1 -1
  57. package/packages/sdk/index.js +2 -0
  58. package/packages/sdk/package.json +18 -0
  59. package/packages/sdk/test/index.js +120 -0
  60. package/templates/common/_tanfig.json +19 -13
  61. package/templates/extension/index.d.ts +26 -22
  62. package/templates/extension/index.js +15 -15
  63. package/templates/extension/native/Cargo.toml +5 -3
  64. package/templates/extension/native/src/lib.rs +2 -3
  65. package/templates/extension/package.json +10 -20
  66. package/templates/extension/titan.json +5 -16
  67. package/templates/extension/utils/registerExtension.js +44 -0
  68. package/templates/js/package.json +8 -8
  69. package/templates/rust-js/package.json +5 -5
  70. package/templates/rust-ts/package.json +5 -5
  71. package/templates/ts/package.json +8 -8
  72. package/packages/packet/node_modules/typescript/LICENSE.txt +0 -55
  73. package/packages/packet/node_modules/typescript/README.md +0 -50
  74. package/packages/packet/node_modules/typescript/SECURITY.md +0 -41
  75. package/packages/packet/node_modules/typescript/ThirdPartyNoticeText.txt +0 -193
  76. package/packages/packet/node_modules/typescript/bin/tsc +0 -2
  77. package/packages/packet/node_modules/typescript/bin/tsserver +0 -2
  78. package/packages/packet/node_modules/typescript/lib/_tsc.js +0 -133818
  79. package/packages/packet/node_modules/typescript/lib/_tsserver.js +0 -659
  80. package/packages/packet/node_modules/typescript/lib/_typingsInstaller.js +0 -222
  81. package/packages/packet/node_modules/typescript/lib/cs/diagnosticMessages.generated.json +0 -2122
  82. package/packages/packet/node_modules/typescript/lib/de/diagnosticMessages.generated.json +0 -2122
  83. package/packages/packet/node_modules/typescript/lib/es/diagnosticMessages.generated.json +0 -2122
  84. package/packages/packet/node_modules/typescript/lib/fr/diagnosticMessages.generated.json +0 -2122
  85. package/packages/packet/node_modules/typescript/lib/it/diagnosticMessages.generated.json +0 -2122
  86. package/packages/packet/node_modules/typescript/lib/ja/diagnosticMessages.generated.json +0 -2122
  87. package/packages/packet/node_modules/typescript/lib/ko/diagnosticMessages.generated.json +0 -2122
  88. package/packages/packet/node_modules/typescript/lib/lib.d.ts +0 -22
  89. package/packages/packet/node_modules/typescript/lib/lib.decorators.d.ts +0 -384
  90. package/packages/packet/node_modules/typescript/lib/lib.decorators.legacy.d.ts +0 -22
  91. package/packages/packet/node_modules/typescript/lib/lib.dom.asynciterable.d.ts +0 -41
  92. package/packages/packet/node_modules/typescript/lib/lib.dom.d.ts +0 -39429
  93. package/packages/packet/node_modules/typescript/lib/lib.dom.iterable.d.ts +0 -571
  94. package/packages/packet/node_modules/typescript/lib/lib.es2015.collection.d.ts +0 -147
  95. package/packages/packet/node_modules/typescript/lib/lib.es2015.core.d.ts +0 -597
  96. package/packages/packet/node_modules/typescript/lib/lib.es2015.d.ts +0 -28
  97. package/packages/packet/node_modules/typescript/lib/lib.es2015.generator.d.ts +0 -77
  98. package/packages/packet/node_modules/typescript/lib/lib.es2015.iterable.d.ts +0 -605
  99. package/packages/packet/node_modules/typescript/lib/lib.es2015.promise.d.ts +0 -81
  100. package/packages/packet/node_modules/typescript/lib/lib.es2015.proxy.d.ts +0 -128
  101. package/packages/packet/node_modules/typescript/lib/lib.es2015.reflect.d.ts +0 -144
  102. package/packages/packet/node_modules/typescript/lib/lib.es2015.symbol.d.ts +0 -46
  103. package/packages/packet/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts +0 -326
  104. package/packages/packet/node_modules/typescript/lib/lib.es2016.array.include.d.ts +0 -116
  105. package/packages/packet/node_modules/typescript/lib/lib.es2016.d.ts +0 -21
  106. package/packages/packet/node_modules/typescript/lib/lib.es2016.full.d.ts +0 -23
  107. package/packages/packet/node_modules/typescript/lib/lib.es2016.intl.d.ts +0 -31
  108. package/packages/packet/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts +0 -21
  109. package/packages/packet/node_modules/typescript/lib/lib.es2017.d.ts +0 -26
  110. package/packages/packet/node_modules/typescript/lib/lib.es2017.date.d.ts +0 -31
  111. package/packages/packet/node_modules/typescript/lib/lib.es2017.full.d.ts +0 -23
  112. package/packages/packet/node_modules/typescript/lib/lib.es2017.intl.d.ts +0 -44
  113. package/packages/packet/node_modules/typescript/lib/lib.es2017.object.d.ts +0 -49
  114. package/packages/packet/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts +0 -135
  115. package/packages/packet/node_modules/typescript/lib/lib.es2017.string.d.ts +0 -45
  116. package/packages/packet/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts +0 -53
  117. package/packages/packet/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts +0 -77
  118. package/packages/packet/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts +0 -53
  119. package/packages/packet/node_modules/typescript/lib/lib.es2018.d.ts +0 -24
  120. package/packages/packet/node_modules/typescript/lib/lib.es2018.full.d.ts +0 -24
  121. package/packages/packet/node_modules/typescript/lib/lib.es2018.intl.d.ts +0 -83
  122. package/packages/packet/node_modules/typescript/lib/lib.es2018.promise.d.ts +0 -30
  123. package/packages/packet/node_modules/typescript/lib/lib.es2018.regexp.d.ts +0 -37
  124. package/packages/packet/node_modules/typescript/lib/lib.es2019.array.d.ts +0 -79
  125. package/packages/packet/node_modules/typescript/lib/lib.es2019.d.ts +0 -24
  126. package/packages/packet/node_modules/typescript/lib/lib.es2019.full.d.ts +0 -24
  127. package/packages/packet/node_modules/typescript/lib/lib.es2019.intl.d.ts +0 -23
  128. package/packages/packet/node_modules/typescript/lib/lib.es2019.object.d.ts +0 -33
  129. package/packages/packet/node_modules/typescript/lib/lib.es2019.string.d.ts +0 -37
  130. package/packages/packet/node_modules/typescript/lib/lib.es2019.symbol.d.ts +0 -24
  131. package/packages/packet/node_modules/typescript/lib/lib.es2020.bigint.d.ts +0 -765
  132. package/packages/packet/node_modules/typescript/lib/lib.es2020.d.ts +0 -27
  133. package/packages/packet/node_modules/typescript/lib/lib.es2020.date.d.ts +0 -42
  134. package/packages/packet/node_modules/typescript/lib/lib.es2020.full.d.ts +0 -24
  135. package/packages/packet/node_modules/typescript/lib/lib.es2020.intl.d.ts +0 -474
  136. package/packages/packet/node_modules/typescript/lib/lib.es2020.number.d.ts +0 -28
  137. package/packages/packet/node_modules/typescript/lib/lib.es2020.promise.d.ts +0 -47
  138. package/packages/packet/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts +0 -99
  139. package/packages/packet/node_modules/typescript/lib/lib.es2020.string.d.ts +0 -44
  140. package/packages/packet/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts +0 -41
  141. package/packages/packet/node_modules/typescript/lib/lib.es2021.d.ts +0 -23
  142. package/packages/packet/node_modules/typescript/lib/lib.es2021.full.d.ts +0 -24
  143. package/packages/packet/node_modules/typescript/lib/lib.es2021.intl.d.ts +0 -166
  144. package/packages/packet/node_modules/typescript/lib/lib.es2021.promise.d.ts +0 -48
  145. package/packages/packet/node_modules/typescript/lib/lib.es2021.string.d.ts +0 -33
  146. package/packages/packet/node_modules/typescript/lib/lib.es2021.weakref.d.ts +0 -78
  147. package/packages/packet/node_modules/typescript/lib/lib.es2022.array.d.ts +0 -121
  148. package/packages/packet/node_modules/typescript/lib/lib.es2022.d.ts +0 -25
  149. package/packages/packet/node_modules/typescript/lib/lib.es2022.error.d.ts +0 -75
  150. package/packages/packet/node_modules/typescript/lib/lib.es2022.full.d.ts +0 -24
  151. package/packages/packet/node_modules/typescript/lib/lib.es2022.intl.d.ts +0 -145
  152. package/packages/packet/node_modules/typescript/lib/lib.es2022.object.d.ts +0 -26
  153. package/packages/packet/node_modules/typescript/lib/lib.es2022.regexp.d.ts +0 -39
  154. package/packages/packet/node_modules/typescript/lib/lib.es2022.string.d.ts +0 -25
  155. package/packages/packet/node_modules/typescript/lib/lib.es2023.array.d.ts +0 -924
  156. package/packages/packet/node_modules/typescript/lib/lib.es2023.collection.d.ts +0 -21
  157. package/packages/packet/node_modules/typescript/lib/lib.es2023.d.ts +0 -22
  158. package/packages/packet/node_modules/typescript/lib/lib.es2023.full.d.ts +0 -24
  159. package/packages/packet/node_modules/typescript/lib/lib.es2023.intl.d.ts +0 -56
  160. package/packages/packet/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts +0 -65
  161. package/packages/packet/node_modules/typescript/lib/lib.es2024.collection.d.ts +0 -29
  162. package/packages/packet/node_modules/typescript/lib/lib.es2024.d.ts +0 -26
  163. package/packages/packet/node_modules/typescript/lib/lib.es2024.full.d.ts +0 -24
  164. package/packages/packet/node_modules/typescript/lib/lib.es2024.object.d.ts +0 -29
  165. package/packages/packet/node_modules/typescript/lib/lib.es2024.promise.d.ts +0 -35
  166. package/packages/packet/node_modules/typescript/lib/lib.es2024.regexp.d.ts +0 -25
  167. package/packages/packet/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts +0 -68
  168. package/packages/packet/node_modules/typescript/lib/lib.es2024.string.d.ts +0 -29
  169. package/packages/packet/node_modules/typescript/lib/lib.es5.d.ts +0 -4601
  170. package/packages/packet/node_modules/typescript/lib/lib.es6.d.ts +0 -23
  171. package/packages/packet/node_modules/typescript/lib/lib.esnext.array.d.ts +0 -35
  172. package/packages/packet/node_modules/typescript/lib/lib.esnext.collection.d.ts +0 -96
  173. package/packages/packet/node_modules/typescript/lib/lib.esnext.d.ts +0 -29
  174. package/packages/packet/node_modules/typescript/lib/lib.esnext.decorators.d.ts +0 -28
  175. package/packages/packet/node_modules/typescript/lib/lib.esnext.disposable.d.ts +0 -193
  176. package/packages/packet/node_modules/typescript/lib/lib.esnext.error.d.ts +0 -24
  177. package/packages/packet/node_modules/typescript/lib/lib.esnext.float16.d.ts +0 -445
  178. package/packages/packet/node_modules/typescript/lib/lib.esnext.full.d.ts +0 -24
  179. package/packages/packet/node_modules/typescript/lib/lib.esnext.intl.d.ts +0 -21
  180. package/packages/packet/node_modules/typescript/lib/lib.esnext.iterator.d.ts +0 -148
  181. package/packages/packet/node_modules/typescript/lib/lib.esnext.promise.d.ts +0 -34
  182. package/packages/packet/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts +0 -25
  183. package/packages/packet/node_modules/typescript/lib/lib.scripthost.d.ts +0 -322
  184. package/packages/packet/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts +0 -41
  185. package/packages/packet/node_modules/typescript/lib/lib.webworker.d.ts +0 -13150
  186. package/packages/packet/node_modules/typescript/lib/lib.webworker.importscripts.d.ts +0 -23
  187. package/packages/packet/node_modules/typescript/lib/lib.webworker.iterable.d.ts +0 -340
  188. package/packages/packet/node_modules/typescript/lib/pl/diagnosticMessages.generated.json +0 -2122
  189. package/packages/packet/node_modules/typescript/lib/pt-br/diagnosticMessages.generated.json +0 -2122
  190. package/packages/packet/node_modules/typescript/lib/ru/diagnosticMessages.generated.json +0 -2122
  191. package/packages/packet/node_modules/typescript/lib/tr/diagnosticMessages.generated.json +0 -2122
  192. package/packages/packet/node_modules/typescript/lib/tsc.js +0 -8
  193. package/packages/packet/node_modules/typescript/lib/tsserver.js +0 -8
  194. package/packages/packet/node_modules/typescript/lib/tsserverlibrary.d.ts +0 -17
  195. package/packages/packet/node_modules/typescript/lib/tsserverlibrary.js +0 -21
  196. package/packages/packet/node_modules/typescript/lib/typesMap.json +0 -497
  197. package/packages/packet/node_modules/typescript/lib/typescript.d.ts +0 -11437
  198. package/packages/packet/node_modules/typescript/lib/typescript.js +0 -200276
  199. package/packages/packet/node_modules/typescript/lib/typingsInstaller.js +0 -8
  200. package/packages/packet/node_modules/typescript/lib/watchGuard.js +0 -53
  201. package/packages/packet/node_modules/typescript/lib/zh-cn/diagnosticMessages.generated.json +0 -2122
  202. package/packages/packet/node_modules/typescript/lib/zh-tw/diagnosticMessages.generated.json +0 -2122
  203. package/packages/packet/node_modules/typescript/package.json +0 -120
  204. package/titanpl-sdk/README.md +0 -111
  205. package/titanpl-sdk/assets/titanpl-sdk.png +0 -0
  206. package/titanpl-sdk/bin/run.js +0 -274
  207. package/titanpl-sdk/index.js +0 -5
  208. package/titanpl-sdk/package-lock.json +0 -28
  209. package/titanpl-sdk/package.json +0 -40
  210. package/titanpl-sdk/templates/app/actions/hello.js +0 -5
  211. package/titanpl-sdk/templates/app/app.js +0 -7
  212. package/titanpl-sdk/templates/jsconfig.json +0 -19
  213. package/titanpl-sdk/templates/server/Cargo.toml +0 -52
  214. package/titanpl-sdk/templates/server/src/action_management.rs +0 -175
  215. package/titanpl-sdk/templates/server/src/errors.rs +0 -12
  216. package/titanpl-sdk/templates/server/src/extensions/builtin.rs +0 -1060
  217. package/titanpl-sdk/templates/server/src/extensions/external.rs +0 -338
  218. package/titanpl-sdk/templates/server/src/extensions/mod.rs +0 -580
  219. package/titanpl-sdk/templates/server/src/extensions/titan_core.js +0 -249
  220. package/titanpl-sdk/templates/server/src/fast_path.rs +0 -719
  221. package/titanpl-sdk/templates/server/src/main.rs +0 -607
  222. package/titanpl-sdk/templates/server/src/runtime.rs +0 -284
  223. package/titanpl-sdk/templates/server/src/utils.rs +0 -33
  224. package/titanpl-sdk/templates/titan/bundle.js +0 -259
  225. package/titanpl-sdk/templates/titan/dev.js +0 -390
  226. package/titanpl-sdk/templates/titan/error-box.js +0 -277
  227. package/titanpl-sdk/templates/titan/titan.js +0 -129
@@ -0,0 +1,702 @@
1
+ use std::ffi::{CStr, CString};
2
+ use std::os::raw::c_char;
3
+ use std::ptr;
4
+ use std::thread;
5
+ use std::time::Duration;
6
+ use base64::{Engine as _, engine::general_purpose};
7
+
8
+ // Force rebuild 2
9
+ mod storage_impl;
10
+ mod crypto_impl;
11
+ mod v8_impl;
12
+
13
+ // --- V8 Serialization ---
14
+
15
+ #[no_mangle]
16
+ pub extern "C" fn native_serialize(
17
+ scope: &mut v8::HandleScope,
18
+ args: v8::FunctionCallbackArguments,
19
+ retval: v8::ReturnValue,
20
+ ) {
21
+ v8_impl::native_serialize(scope, args, retval)
22
+ }
23
+
24
+ #[no_mangle]
25
+ pub extern "C" fn native_deserialize(
26
+ scope: &mut v8::HandleScope,
27
+ args: v8::FunctionCallbackArguments,
28
+ retval: v8::ReturnValue,
29
+ ) {
30
+ v8_impl::native_deserialize(scope, args, retval)
31
+ }
32
+
33
+ // --- Helper Functions ---
34
+
35
+ fn ptr_to_string(ptr: *const c_char) -> String {
36
+ if ptr.is_null() {
37
+ return String::new();
38
+ }
39
+ unsafe {
40
+ CStr::from_ptr(ptr).to_string_lossy().into_owned()
41
+ }
42
+ }
43
+
44
+ fn string_to_ptr(s: String) -> *mut c_char {
45
+ match CString::new(s) {
46
+ Ok(c_str) => c_str.into_raw(),
47
+ Err(_) => ptr::null_mut(),
48
+ }
49
+ }
50
+
51
+ fn safe_string(bytes: &[u8]) -> String {
52
+ match std::str::from_utf8(bytes) {
53
+ Ok(s) => s.to_string(),
54
+ Err(_) => general_purpose::STANDARD.encode(bytes),
55
+ }
56
+ }
57
+
58
+ // --- File System ---
59
+
60
+ #[no_mangle]
61
+ pub extern "C" fn fs_read_file(path: *const c_char) -> *mut c_char {
62
+ let path_str = ptr_to_string(path);
63
+ match std::fs::read(path_str) {
64
+ Ok(bytes) => string_to_ptr(String::from_utf8_lossy(&bytes).into_owned()),
65
+ Err(e) => string_to_ptr(format!("ERROR: {}", e)),
66
+ }
67
+ }
68
+
69
+ #[no_mangle]
70
+ pub extern "C" fn fs_write_file(path: *const c_char, content: *const c_char) {
71
+ let path_str = ptr_to_string(path);
72
+ let content_str = ptr_to_string(content);
73
+ let _ = std::fs::write(path_str, content_str);
74
+ }
75
+
76
+ #[no_mangle]
77
+ pub extern "C" fn fs_readdir(path: *const c_char) -> *mut c_char {
78
+ let path_str = ptr_to_string(path);
79
+ match std::fs::read_dir(path_str) {
80
+ Ok(entries) => {
81
+ let files: Vec<String> = entries
82
+ .filter_map(|entry| entry.ok().and_then(|e| e.file_name().into_string().ok()))
83
+ .collect();
84
+ let json = serde_json::to_string(&files).unwrap_or_else(|_| "[]".to_string());
85
+ string_to_ptr(json)
86
+ },
87
+ Err(_) => string_to_ptr("[]".to_string()),
88
+ }
89
+ }
90
+
91
+ #[no_mangle]
92
+ pub extern "C" fn fs_mkdir(path: *const c_char) {
93
+ let path_str = ptr_to_string(path);
94
+ let _ = std::fs::create_dir_all(path_str);
95
+ }
96
+
97
+ #[no_mangle]
98
+ pub extern "C" fn fs_exists(path: *const c_char) -> bool {
99
+ let path_str = ptr_to_string(path);
100
+ std::path::Path::new(&path_str).exists()
101
+ }
102
+
103
+ #[no_mangle]
104
+ pub extern "C" fn fs_stat(path: *const c_char) -> *mut c_char {
105
+ let path_str = ptr_to_string(path);
106
+ match std::fs::metadata(path_str) {
107
+ Ok(meta) => {
108
+ let stat = serde_json::json!({
109
+ "size": meta.len(),
110
+ "isFile": meta.is_file(),
111
+ "isDir": meta.is_dir(),
112
+ "modified": meta.modified().ok().and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok()).map(|d| d.as_millis()).unwrap_or(0),
113
+ });
114
+ string_to_ptr(stat.to_string())
115
+ },
116
+ Err(_) => string_to_ptr("{}".to_string()),
117
+ }
118
+ }
119
+
120
+ #[no_mangle]
121
+ pub extern "C" fn fs_remove(path: *const c_char) {
122
+ let path_str = ptr_to_string(path);
123
+ let p = std::path::Path::new(&path_str);
124
+ if p.is_dir() {
125
+ let _ = std::fs::remove_dir_all(p);
126
+ } else {
127
+ let _ = std::fs::remove_file(p);
128
+ }
129
+ }
130
+
131
+ #[no_mangle]
132
+ pub extern "C" fn path_cwd() -> *mut c_char {
133
+ match std::env::current_dir() {
134
+ Ok(p) => string_to_ptr(p.to_string_lossy().into_owned()),
135
+ Err(_) => string_to_ptr(String::new()),
136
+ }
137
+ }
138
+
139
+ // --- Proc ---
140
+ #[no_mangle]
141
+ pub extern "C" fn proc_info() -> *mut c_char {
142
+ let info = serde_json::json!({
143
+ "pid": std::process::id(),
144
+ "uptime": 0, // difficult to get comfortably x-platform without more crates
145
+ });
146
+ string_to_ptr(info.to_string())
147
+ }
148
+
149
+ #[no_mangle]
150
+ pub extern "C" fn proc_run(
151
+ command: *const c_char,
152
+ options_json: *const c_char,
153
+ ) -> *mut c_char {
154
+ let cmd = ptr_to_string(command);
155
+ let options_str = ptr_to_string(options_json);
156
+
157
+ let options: serde_json::Value =
158
+ serde_json::from_str(&options_str).unwrap_or(serde_json::json!({}));
159
+
160
+ let args: Vec<String> = options["args"]
161
+ .as_array()
162
+ .map(|arr| arr.iter().map(|v| v.as_str().unwrap_or("").to_string()).collect())
163
+ .unwrap_or_default();
164
+
165
+ let cwd_str = options["cwd"].as_str().unwrap_or("");
166
+
167
+ let cwd_res = if cwd_str.is_empty() {
168
+ std::env::current_dir()
169
+ } else {
170
+ let p = std::path::Path::new(cwd_str);
171
+ if p.is_absolute() {
172
+ Ok(p.to_path_buf())
173
+ } else {
174
+ std::env::current_dir().map(|d| d.join(p))
175
+ }
176
+ };
177
+
178
+ let cwd = match cwd_res {
179
+ Ok(c) => c,
180
+ Err(e) => return string_to_ptr(format!("ERROR: Failed to resolve CWD: {}", e)),
181
+ };
182
+
183
+ let mut command = std::process::Command::new(cmd);
184
+ command.args(args);
185
+ command.current_dir(&cwd);
186
+ command.stdin(std::process::Stdio::null());
187
+ command.stdout(std::process::Stdio::null());
188
+ command.stderr(std::process::Stdio::null());
189
+
190
+ match command.spawn() {
191
+ Ok(child) => {
192
+ let res = serde_json::json!({
193
+ "ok": true,
194
+ "pid": child.id(),
195
+ "cwd": cwd
196
+ });
197
+ string_to_ptr(res.to_string())
198
+ }
199
+ Err(e) => {
200
+ string_to_ptr(format!("ERROR: Spawn failed: {}", e))
201
+ }
202
+ }
203
+ }
204
+
205
+ #[no_mangle]
206
+ pub extern "C" fn proc_kill(pid: f64) -> bool {
207
+ let pid_int = pid as usize;
208
+ use sysinfo::{System, Pid};
209
+ let s = System::new_all();
210
+ let pid = Pid::from(pid_int);
211
+ if let Some(process) = s.process(pid) {
212
+ process.kill()
213
+ } else {
214
+ false
215
+ }
216
+ }
217
+
218
+ #[no_mangle]
219
+ pub extern "C" fn proc_list() -> *mut c_char {
220
+ use sysinfo::System;
221
+ let mut s = System::new_all();
222
+ s.refresh_processes();
223
+ let processes: Vec<serde_json::Value> = s.processes().iter().map(|(pid, process)| {
224
+ serde_json::json!({
225
+ "pid": pid.as_u32(),
226
+ "name": process.name(),
227
+ "cmd": process.cmd(),
228
+ "memory": process.memory(),
229
+ "cpu": process.cpu_usage(),
230
+ })
231
+ }).collect();
232
+ string_to_ptr(serde_json::to_string(&processes).unwrap_or("[]".to_string()))
233
+ }
234
+
235
+ // --- Crypto ---
236
+
237
+ #[no_mangle]
238
+ pub extern "C" fn crypto_hash(algo: *const c_char, data: *const c_char) -> *mut c_char {
239
+ let algo_str = ptr_to_string(algo);
240
+ let data_str = ptr_to_string(data);
241
+
242
+ let res = crypto_impl::hash_keyed(&algo_str, "", &data_str); // Re-use hash_keyed with empty key? Or implement simple hash logic?
243
+ // Wait, crypto_impl doesn't have simple hash. It has hash_keyed (HMAC).
244
+ // I should check crypto_impl content again.
245
+ // It has `hash_keyed`. It imports sha2::{Sha256, Sha512}.
246
+ // I will implement simple hash here or add it to crypto_impl.
247
+ // For now, I'll use Sha256 directly here to save time editing crypto_impl.
248
+ let res = match algo_str.as_str() {
249
+ "sha256" => {
250
+ use sha2::Digest;
251
+ let mut hasher = sha2::Sha256::new();
252
+ hasher.update(data_str);
253
+ Ok(hex::encode(hasher.finalize()))
254
+ },
255
+ "sha512" => {
256
+ use sha2::Digest;
257
+ let mut hasher = sha2::Sha512::new();
258
+ hasher.update(data_str);
259
+ Ok(hex::encode(hasher.finalize()))
260
+ },
261
+ _ => Err("Unsupported algorithm".to_string())
262
+ };
263
+
264
+ match res {
265
+ Ok(s) => string_to_ptr(s),
266
+ Err(e) => string_to_ptr(format!("ERROR: {}", e)),
267
+ }
268
+ }
269
+
270
+ #[no_mangle]
271
+ pub extern "C" fn crypto_random_bytes(size: f64) -> *mut c_char {
272
+ let size = size as usize;
273
+ let mut bytes = vec![0u8; size];
274
+ // let _ = getrandom::getrandom(&mut bytes);
275
+ // crypto_impl uses rand::thread_rng().
276
+ let mut rng = rand::thread_rng();
277
+ use rand::RngCore;
278
+ rng.fill_bytes(&mut bytes);
279
+ string_to_ptr(hex::encode(bytes))
280
+ }
281
+
282
+ #[no_mangle]
283
+ pub extern "C" fn crypto_uuid() -> *mut c_char {
284
+ string_to_ptr(uuid::Uuid::new_v4().to_string())
285
+ }
286
+
287
+ #[no_mangle]
288
+ pub extern "C" fn crypto_encrypt(algo: *const c_char, json_args: *const c_char) -> *mut c_char {
289
+ let algo_str = ptr_to_string(algo);
290
+ let args_str = ptr_to_string(json_args);
291
+
292
+ // Parse JSON args {key, plaintext}
293
+ let args: serde_json::Value = match serde_json::from_str(&args_str) {
294
+ Ok(v) => v,
295
+ Err(_) => return string_to_ptr("ERROR: Invalid JSON".to_string()),
296
+ };
297
+
298
+ let key = args["key"].as_str().unwrap_or("");
299
+ let plaintext = args["plaintext"].as_str().unwrap_or("");
300
+
301
+ match crypto_impl::encrypt(&algo_str, key, plaintext) {
302
+ Ok(s) => string_to_ptr(s),
303
+ Err(e) => string_to_ptr(format!("ERROR: {}", e)),
304
+ }
305
+ }
306
+
307
+ #[no_mangle]
308
+ pub extern "C" fn crypto_decrypt(algo: *const c_char, json_args: *const c_char) -> *mut c_char {
309
+ let algo_str = ptr_to_string(algo);
310
+ let args_str = ptr_to_string(json_args);
311
+
312
+ let args: serde_json::Value = match serde_json::from_str(&args_str) {
313
+ Ok(v) => v,
314
+ Err(_) => return string_to_ptr("ERROR: Invalid JSON".to_string()),
315
+ };
316
+
317
+ let key = args["key"].as_str().unwrap_or("");
318
+ let ciphertext = args["ciphertext"].as_str().unwrap_or("");
319
+
320
+ match crypto_impl::decrypt(&algo_str, key, ciphertext) {
321
+ Ok(bytes) => string_to_ptr(safe_string(&bytes)),
322
+ Err(e) => string_to_ptr(format!("ERROR: {}", e)),
323
+ }
324
+ }
325
+
326
+ #[no_mangle]
327
+ pub extern "C" fn crypto_hash_keyed(algo: *const c_char, json_args: *const c_char) -> *mut c_char {
328
+ let algo_str = ptr_to_string(algo);
329
+ let args_str = ptr_to_string(json_args);
330
+
331
+ let args: serde_json::Value = match serde_json::from_str(&args_str) {
332
+ Ok(v) => v,
333
+ Err(_) => return string_to_ptr("ERROR: Invalid JSON".to_string()),
334
+ };
335
+
336
+ let key = args["key"].as_str().unwrap_or("");
337
+ let message = args["message"].as_str().unwrap_or("");
338
+
339
+ match crypto_impl::hash_keyed(&algo_str, key, message) {
340
+ Ok(s) => string_to_ptr(s),
341
+ Err(e) => string_to_ptr(format!("ERROR: {}", e)),
342
+ }
343
+ }
344
+
345
+ #[no_mangle]
346
+ pub extern "C" fn crypto_compare(a: *const c_char, b: *const c_char) -> bool {
347
+ let a_str = ptr_to_string(a);
348
+ let b_str = ptr_to_string(b);
349
+ crypto_impl::compare(&a_str, &b_str)
350
+ }
351
+
352
+
353
+ // --- OS ---
354
+ #[no_mangle]
355
+ pub extern "C" fn os_info() -> *mut c_char {
356
+ let info = serde_json::json!({
357
+ "platform": std::env::consts::OS,
358
+ "cpus": std::thread::available_parallelism().map(|n| n.get()).unwrap_or(1),
359
+ // sys-info = "0.9"
360
+ "totalMemory": sys_info::mem_info().map(|m| m.total * 1024).unwrap_or(0),
361
+ "freeMemory": sys_info::mem_info().map(|m| m.free * 1024).unwrap_or(0),
362
+ "tempDir": std::env::temp_dir(),
363
+ });
364
+ string_to_ptr(info.to_string())
365
+ }
366
+
367
+ // --- Net ---
368
+ #[no_mangle]
369
+ pub extern "C" fn net_resolve(hostname: *const c_char) -> *mut c_char {
370
+ let host = ptr_to_string(hostname);
371
+ // dns-lookup crate
372
+ match dns_lookup::lookup_host(&host) {
373
+ Ok(ips) => {
374
+ let ip_strs: Vec<String> = ips.iter().map(|ip| ip.to_string()).collect();
375
+ string_to_ptr(serde_json::to_string(&ip_strs).unwrap_or("[]".into()))
376
+ },
377
+ Err(_) => string_to_ptr("[]".to_string()),
378
+ }
379
+ }
380
+
381
+ #[no_mangle]
382
+ pub extern "C" fn net_ip() -> *mut c_char {
383
+ // local-ip-address crate
384
+ use local_ip_address::local_ip;
385
+ match local_ip() {
386
+ Ok(ip) => string_to_ptr(ip.to_string()),
387
+ Err(_) => string_to_ptr("127.0.0.1".to_string()),
388
+ }
389
+ }
390
+
391
+ // --- Time ---
392
+ #[no_mangle]
393
+ pub extern "C" fn time_sleep(ms: f64) {
394
+ thread::sleep(Duration::from_millis(ms as u64));
395
+ }
396
+
397
+ // --- Local Storage (THE FIX) ---
398
+
399
+ #[no_mangle]
400
+ pub extern "C" fn ls_get(key: *const c_char) -> *mut c_char {
401
+ let key_str = ptr_to_string(key);
402
+ match storage_impl::ls_get(&key_str) {
403
+ Some(val) => string_to_ptr(safe_string(val.as_bytes())),
404
+ None => string_to_ptr(String::new()),
405
+ }
406
+ }
407
+
408
+ #[no_mangle]
409
+ pub extern "C" fn ls_set(key: *const c_char, value: *const c_char) {
410
+ let key_str = ptr_to_string(key);
411
+ let val_str = ptr_to_string(value);
412
+ let _ = storage_impl::ls_set(&key_str, &val_str);
413
+ }
414
+
415
+ #[no_mangle]
416
+ pub extern "C" fn ls_remove(key: *const c_char) {
417
+ let key_str = ptr_to_string(key);
418
+ let _ = storage_impl::ls_remove(&key_str);
419
+ }
420
+
421
+ #[no_mangle]
422
+ pub extern "C" fn ls_clear() {
423
+ let _ = storage_impl::ls_clear();
424
+ }
425
+
426
+ #[no_mangle]
427
+ pub extern "C" fn ls_keys() -> *mut c_char {
428
+ match storage_impl::ls_keys() {
429
+ Ok(keys) => {
430
+ let json = serde_json::to_string(&keys).unwrap_or("[]".to_string());
431
+ string_to_ptr(json)
432
+ },
433
+ Err(_) => string_to_ptr("[]".to_string()),
434
+ }
435
+ }
436
+
437
+ // --- Sessions ---
438
+
439
+ #[no_mangle]
440
+ pub extern "C" fn session_get(sid: *const c_char, key: *const c_char) -> *mut c_char {
441
+ let sid_str = ptr_to_string(sid);
442
+ let key_str = ptr_to_string(key);
443
+ match storage_impl::session_get(&sid_str, &key_str) {
444
+ Some(v) => string_to_ptr(v),
445
+ None => string_to_ptr(String::new()),
446
+ }
447
+ }
448
+
449
+ #[no_mangle]
450
+ pub extern "C" fn session_set(sid: *const c_char, key: *const c_char) { // Value?
451
+ // Wait, titan.json says session_set(string, string).
452
+ // And storage_impl::session_set takes (sid, key, value).
453
+ // titan.json signatures are limited to 2 args in the user's snippet?
454
+ // "session_set": parameters: ["string", "string"].
455
+ // But index.js says: native_session_set(sessionId, JSON.stringify({ key, value }))
456
+ // Ah! It packs key and value into the second argument.
457
+ // So I need to unpack it here.
458
+ let sid_str = ptr_to_string(sid);
459
+ let args_str = ptr_to_string(key); // This is actually the "packed" arg
460
+
461
+ // BUT! index.js line 360: native_session_set(sessionId, JSON.stringify({ key, value }))
462
+ // So Rust needs to parse that JSON.
463
+
464
+ if let Ok(json) = serde_json::from_str::<serde_json::Value>(&args_str) {
465
+ let real_key = json["key"].as_str().unwrap_or("");
466
+ let real_val = json["value"].as_str().unwrap_or("");
467
+ let _ = storage_impl::session_set(&sid_str, real_key, real_val);
468
+ }
469
+ }
470
+
471
+ #[no_mangle]
472
+ pub extern "C" fn session_delete(sid: *const c_char, key: *const c_char) {
473
+ let sid_str = ptr_to_string(sid);
474
+ let key_str = ptr_to_string(key);
475
+ let _ = storage_impl::session_delete(&sid_str, &key_str);
476
+ }
477
+
478
+ #[no_mangle]
479
+ pub extern "C" fn session_clear(sid: *const c_char) {
480
+ let sid_str = ptr_to_string(sid);
481
+ let _ = storage_impl::session_clear(&sid_str);
482
+ }
483
+
484
+ // --- TITAN ABI: Unified JSON Export ---
485
+ // All native calls pass through this single entry point.
486
+ // Request: { "function": "fn_name", "params": [...args] }
487
+ // Response: any JSON value
488
+
489
+ #[no_mangle]
490
+ pub extern "C" fn titan_export(request_json: *const c_char) -> *const c_char {
491
+ let request_str = ptr_to_string(request_json);
492
+ let request: serde_json::Value = match serde_json::from_str(&request_str) {
493
+ Ok(v) => v,
494
+ Err(_) => return string_to_ptr(serde_json::json!({"error": "Invalid request JSON"}).to_string()),
495
+ };
496
+
497
+ let function = request["function"].as_str().unwrap_or("");
498
+ let params = request["params"].as_array();
499
+
500
+ let res = match function {
501
+
502
+ // ── File System ──────────────────────────────────────────────────
503
+ "fs_read_file" => {
504
+ let path = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
505
+ match std::fs::read(path) {
506
+ Ok(bytes) => serde_json::json!(String::from_utf8_lossy(&bytes).to_string()),
507
+ Err(e) => serde_json::json!(format!("ERROR: {}", e)),
508
+ }
509
+ },
510
+ "fs_write_file" => {
511
+ let path = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
512
+ let content = params.and_then(|p| p.get(1)).and_then(|v| v.as_str()).unwrap_or("");
513
+ match std::fs::write(path, content) {
514
+ Ok(_) => serde_json::json!(true),
515
+ Err(e) => serde_json::json!(format!("ERROR: {}", e)),
516
+ }
517
+ },
518
+ "fs_exists" => {
519
+ let path = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
520
+ serde_json::json!(std::path::Path::new(path).exists())
521
+ },
522
+ "fs_readdir" => {
523
+ let path = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
524
+ match std::fs::read_dir(path) {
525
+ Ok(entries) => {
526
+ let files: Vec<String> = entries
527
+ .filter_map(|e| e.ok().and_then(|e| e.file_name().into_string().ok()))
528
+ .collect();
529
+ serde_json::json!(files)
530
+ },
531
+ Err(e) => serde_json::json!(format!("ERROR: {}", e)),
532
+ }
533
+ },
534
+ "fs_mkdir" => {
535
+ let path = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
536
+ match std::fs::create_dir_all(path) {
537
+ Ok(_) => serde_json::json!(true),
538
+ Err(e) => serde_json::json!(format!("ERROR: {}", e)),
539
+ }
540
+ },
541
+ "fs_stat" => {
542
+ let path = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
543
+ match std::fs::metadata(path) {
544
+ Ok(m) => serde_json::json!({
545
+ "size": m.len(),
546
+ "isFile": m.is_file(),
547
+ "isDir": m.is_dir(),
548
+ }),
549
+ Err(e) => serde_json::json!(format!("ERROR: {}", e)),
550
+ }
551
+ },
552
+ "fs_remove" => {
553
+ let path = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
554
+ let p = std::path::Path::new(path);
555
+ let res = if p.is_dir() { std::fs::remove_dir_all(p) } else { std::fs::remove_file(p) };
556
+ match res {
557
+ Ok(_) => serde_json::json!(true),
558
+ Err(e) => serde_json::json!(format!("ERROR: {}", e)),
559
+ }
560
+ },
561
+
562
+ // ── Crypto ──────────────────────────────────────────────────────
563
+ "crypto_uuid" => serde_json::json!(uuid::Uuid::new_v4().to_string()),
564
+ "crypto_hash" => {
565
+ let algo = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("sha256");
566
+ let data = params.and_then(|p| p.get(1)).and_then(|v| v.as_str()).unwrap_or("");
567
+ serde_json::json!(crypto_impl::hash(algo, data))
568
+ },
569
+ "crypto_random_bytes" => {
570
+ let size = params.and_then(|p| p.get(0)).and_then(|v| v.as_u64()).unwrap_or(32) as usize;
571
+ serde_json::json!(crypto_impl::random_bytes(size))
572
+ },
573
+ "crypto_encrypt" => {
574
+ let algo = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("aes-256-gcm");
575
+ let payload_str = params.and_then(|p| p.get(1)).and_then(|v| v.as_str()).unwrap_or("{}");
576
+ let payload: serde_json::Value = serde_json::from_str(payload_str).unwrap_or(serde_json::json!({}));
577
+ let key = payload["key"].as_str().unwrap_or("");
578
+ let plaintext = payload["plaintext"].as_str().unwrap_or("");
579
+ match crypto_impl::encrypt(algo, key, plaintext) {
580
+ Ok(s) => serde_json::json!(s),
581
+ Err(e) => serde_json::json!(format!("ERROR: {}", e)),
582
+ }
583
+ },
584
+ "crypto_decrypt" => {
585
+ let algo = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("aes-256-gcm");
586
+ let payload_str = params.and_then(|p| p.get(1)).and_then(|v| v.as_str()).unwrap_or("{}");
587
+ let payload: serde_json::Value = serde_json::from_str(payload_str).unwrap_or(serde_json::json!({}));
588
+ let key = payload["key"].as_str().unwrap_or("");
589
+ let ciphertext = payload["ciphertext"].as_str().unwrap_or("");
590
+ match crypto_impl::decrypt(algo, key, ciphertext) {
591
+ Ok(bytes) => serde_json::json!(String::from_utf8_lossy(&bytes).to_string()),
592
+ Err(e) => serde_json::json!(format!("ERROR: {}", e)),
593
+ }
594
+ },
595
+ "crypto_hash_keyed" => {
596
+ let algo = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("sha256");
597
+ let payload_str = params.and_then(|p| p.get(1)).and_then(|v| v.as_str()).unwrap_or("{}");
598
+ let payload: serde_json::Value = serde_json::from_str(payload_str).unwrap_or(serde_json::json!({}));
599
+ let key = payload["key"].as_str().unwrap_or("");
600
+ let message = payload["message"].as_str().unwrap_or("");
601
+ match crypto_impl::hash_keyed(algo, key, message) {
602
+ Ok(s) => serde_json::json!(s),
603
+ Err(e) => serde_json::json!(format!("ERROR: {}", e)),
604
+ }
605
+ },
606
+ "crypto_compare" => {
607
+ let a = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
608
+ let b = params.and_then(|p| p.get(1)).and_then(|v| v.as_str()).unwrap_or("");
609
+ serde_json::json!(crypto_impl::compare(a, b))
610
+ },
611
+
612
+ // ── Local Storage ───────────────────────────────────────────────
613
+ "ls_get" => {
614
+ let key = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
615
+ serde_json::json!(storage_impl::ls_get(key))
616
+ },
617
+ "ls_set" => {
618
+ let key = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
619
+ let value = params.and_then(|p| p.get(1)).and_then(|v| v.as_str()).unwrap_or("");
620
+ storage_impl::ls_set(key, value);
621
+ serde_json::json!(true)
622
+ },
623
+ "ls_remove" => {
624
+ let key = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
625
+ storage_impl::ls_remove(key);
626
+ serde_json::json!(true)
627
+ },
628
+ "ls_clear" => { storage_impl::ls_clear(); serde_json::json!(true) },
629
+ "ls_keys" => serde_json::json!(storage_impl::ls_keys()),
630
+ "serialize" => {
631
+ // In IPC mode, we can't really do native V8 serialization of handles easily.
632
+ // But for compatibility with the Proxy, we can return an error or a placeholder.
633
+ // Actually, the JS side should use t.serialize if available.
634
+ // If we are here, it means we are in the NativeHost process, which has NO V8 scope.
635
+ // So we CANNOT perform native V8 serialization here.
636
+ serde_json::json!({"error": "Native V8 serialization requires engine-level built-ins. Please update titan-server."})
637
+ },
638
+ "deserialize" => {
639
+ serde_json::json!({"error": "Native V8 deserialization requires engine-level built-ins. Please update titan-server."})
640
+ },
641
+
642
+ // ── Sessions ────────────────────────────────────────────────────
643
+ "session_get" => {
644
+ let sid = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
645
+ let key = params.and_then(|p| p.get(1)).and_then(|v| v.as_str()).unwrap_or("");
646
+ serde_json::json!(storage_impl::session_get(sid, key))
647
+ },
648
+ "session_set" => {
649
+ let sid = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
650
+ let key = params.and_then(|p| p.get(1)).and_then(|v| v.as_str()).unwrap_or("");
651
+ let value = params.and_then(|p| p.get(2)).and_then(|v| v.as_str()).unwrap_or("");
652
+ storage_impl::session_set(sid, key, value);
653
+ serde_json::json!(true)
654
+ },
655
+ "session_delete" => {
656
+ let sid = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
657
+ let key = params.and_then(|p| p.get(1)).and_then(|v| v.as_str()).unwrap_or("");
658
+ storage_impl::session_delete(sid, key);
659
+ serde_json::json!(true)
660
+ },
661
+ "session_clear" => {
662
+ let sid = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
663
+ storage_impl::session_clear(sid);
664
+ serde_json::json!(true)
665
+ },
666
+
667
+ // ── System / OS ─────────────────────────────────────────────────
668
+ "os_info" => {
669
+ serde_json::json!({
670
+ "platform": std::env::consts::OS,
671
+ "arch": std::env::consts::ARCH,
672
+ "cpus": thread::available_parallelism().map(|n| n.get()).unwrap_or(1),
673
+ "totalMemory": sys_info::mem_info().map(|m| m.total * 1024).unwrap_or(0),
674
+ "freeMemory": sys_info::mem_info().map(|m| m.free * 1024).unwrap_or(0),
675
+ "tempDir": std::env::temp_dir().to_string_lossy().to_string(),
676
+ })
677
+ },
678
+ "proc_info" => {
679
+ serde_json::json!({
680
+ "pid": std::process::id(),
681
+ "uptime": 0,
682
+ })
683
+ },
684
+ "path_cwd" => {
685
+ serde_json::json!(std::env::current_dir()
686
+ .map(|p| p.to_string_lossy().to_string())
687
+ .unwrap_or_default())
688
+ },
689
+ "net_resolve" => {
690
+ let host = params.and_then(|p| p.get(0)).and_then(|v| v.as_str()).unwrap_or("");
691
+ use std::net::ToSocketAddrs;
692
+ match (host, 80u16).to_socket_addrs() {
693
+ Ok(mut addrs) => serde_json::json!(addrs.next().map(|a| a.ip().to_string())),
694
+ Err(_) => serde_json::json!(null),
695
+ }
696
+ },
697
+
698
+ _ => serde_json::json!({"error": format!("Function '{}' not found in @titanpl/core", function)}),
699
+ };
700
+
701
+ string_to_ptr(res.to_string())
702
+ }