@ezetgalaxy/titan 26.15.1 → 26.15.3

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 CHANGED
@@ -1,56 +1,84 @@
1
+ <p align="center">
2
+ <a href="https://titan-docs-ez.vercel.app/" target="_blank">
3
+ <img src="https://i.ibb.co/VpBsTg6m/tpl-Logo.png" width="120" alt="TitanPl Logo" />
4
+ </a>
5
+ </p>
1
6
 
2
- ```
3
- ████████╗██╗████████╗ █████╗ ███╗ ██╗ ██████╗ ██████╗ ██████╗ ██████╗
4
- ╚══██╔══╝██║╚══██╔══╝██╔══██╗████╗ ██║ ╚════██╗██╔═████╗╚════██╗██╔════╝
5
- ██║ ██║ ██║ ███████║██╔██╗ ██║ █████╔╝██║██╔██║ █████╔╝███████╗
6
- ██║ ██║ ██║ ██╔══██║██║╚██╗██║ ██╔═══╝ ████╔╝██║██╔═══╝ ██═══██║
7
- ██║ ██║ ██║ ██║ ██║██║ ╚████║ ███████╗╚██████╔╝███████╗███████║
8
- ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚══════╝ ╚═════╝ ╚══════╝╚══════╝
9
- ```
7
+ <p align="center">
8
+ You write zero Rust. TitanPl handles routing, bundling, runtime execution, hot reload, and deployment — <br> all powered by <a href="https://rust-lang.org/">Rust</a> under the hood.
9
+ </p>
10
10
 
11
- # Notice
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/@ezetgalaxy/titan">
13
+ <img src="https://img.shields.io/npm/v/@ezetgalaxy/titan?style=for-the-badge&logo=npm&logoColor=white" />
14
+ </a>
12
15
 
13
- 💙 **Enjoy development mode `titan dev`**
14
- 💟 **Titan Planet docs:** https://titan-docs-ez.vercel.app/docs
15
- 🚀 **CLI: `titan` is now the canonical command. `tit` remains supported as an alias.**
16
- 🛡️ **Strict Mode:** Titan now enforces zero type errors before running.
17
- ✅ **For text response from a action file use t.response.text("Hii TitanPl")
16
+ <img src="https://img.shields.io/badge/Runtime-Gravity(V8)%20%26%20Rust%20Tokio-1f2937?style=for-the-badge" />
18
17
 
19
- ---
18
+ <img src="https://img.shields.io/badge/Powered%20By%20Rust%20Axum-DEA584?style=for-the-badge&logo=rust&logoColor=black" />
20
19
 
21
- # TITAN PLANET 🚀
20
+ <a href="https://discord.gg/mPDaTRtP">
21
+ <img src="https://img.shields.io/badge/Join-5865F2?style=for-the-badge&logo=discord&logoColor=white" />
22
+ </a>
22
23
 
23
- [![npm version](https://img.shields.io/npm/v/@ezetgalaxy/titan.svg?style=flat-square)](https://www.npmjs.com/package/@ezetgalaxy/titan)
24
+ <a href="https://x.com/TitanPl">
25
+ <img src="https://img.shields.io/badge/Follow-000000?style=for-the-badge&logo=x&logoColor=white" />
26
+ </a>
24
27
 
28
+ </p>
25
29
 
26
- **TypeScript Precision. JavaScript Simplicity. Native Rust Power. Zero Configuration.**
27
-
28
- Titan Planet is a **JavaScript/TypeScript-first Backend Framework** that compiles your application into a single, high-performance native binary. It embeds a V8 JavaScript runtime directly into a specialized Rust + Axum server.
29
30
 
30
- **Start with pure TypeScript/JavaScript.**
31
- **Need raw power? Add Rust actions seamlessly.**
32
- Titan handles the compilation, bundling, and routing automatically for both.
33
31
 
34
- Titan = **TS/JS productivity × Rust performance × Zero DevOps**
35
32
 
36
- ---
33
+ <h1> Description
34
+ </h1>
37
35
 
38
- # 🌌 Why Titan?
36
+ Titan Planet is a JavaScript/TypeScript-first Backend Framework that compiles your application into a single, high-performance native binary. It embeds it's own Gravity (V8) JavaScript runtime directly into a specialized Rust + Axum server.
39
37
 
40
- | Feature | Titan | Express/Nest | FastAPI | Bun |
41
- | ------------------------------------ | ----- | ------------ | ------- | --------- |
42
- | Native binary output | ✅ Yes | ❌ No | ❌ No | ❌ No |
43
- | Hybrid Rust + JS/TS Actions | ✅ Yes | ❌ No | ❌ No | ❌ No |
44
- | Strict TypeScript Enforcement | ✅ Yes | ❌ Setup Req. | ❌ No | ❌ Partial |
45
- | Zero-config Docker deploy | ✅ Yes | ❌ No | ❌ No | ❌ No |
46
- | Action-based architecture | ✅ Yes | ❌ No | ❌ No | ❌ No |
47
- | Hot reload dev server | ✅ Yes | ❌ No | ❌ No | ❌ No |
48
- | Modular, Isolated Templates | ✅ Yes | ❌ No | ❌ No | ❌ No |
38
+ **TypeScript Precision. JavaScript Simplicity. Native Rust Power. Zero Configuration.**
49
39
 
50
- ---
40
+ <p>
41
+
42
+ <img src="https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white" />
43
+ <img src="https://img.shields.io/badge/JavaScript-F7DF1E?style=for-the-badge&logo=javascript&logoColor=black" />
44
+ <img src="https://img.shields.io/badge/Rust-DEA584?style=for-the-badge&logo=rust&logoColor=black" />
45
+ </p>
46
+
47
+
48
+ ## Why Titan?
49
+
50
+ Titan Planet compiles your JavaScript or TypeScript application into a **single native Rust binary**.
51
+
52
+ It embeds a V8 runtime inside a Rust + Axum server — giving you:
53
+
54
+ - ⚡ Native-level performance
55
+ - 📦 Single binary deployment
56
+ - 🧠 Strict TypeScript enforcement
57
+ - 🛡 Zero type errors before runtime
58
+ - 🚀 No DevOps configuration required
59
+
60
+ Start with pure TypeScript.
61
+ Drop into Rust when you need extreme performance.
62
+ Titan handles the integration automatically.
63
+
64
+ <p>
65
+ <a href="https://titan-docs-ez.vercel.app/docs" target="_blank">
66
+ <img src="https://i.ibb.co/VpBsTg6m/tpl-Logo.png" width="28" style="vertical-align:middle;" />
67
+ <strong style="vertical-align:middle;"> Documentation</strong>
68
+ </p>
69
+ <p>
70
+ <a href="https://titan-docs-ez.vercel.app/docs/runtime-architecture" target="_blank">
71
+ <strong style="vertical-align:middle;">Gravity Runtime</strong>
72
+ </a>
73
+ </p>
74
+
75
+ <p>
76
+ <a href="https://titan-docs-ez.vercel.app/docs/14-drift" target="_blank">
77
+ <strong style="vertical-align:middle;">Drift</strong>
78
+ </a>
79
+ </p>
51
80
 
52
81
  # 🚀 Quick Start
53
-
54
82
  ### 1. Prerequisites
55
83
  * **Rust** (latest stable): [Install Rust](https://rust-lang.org/tools/install/)
56
84
  * **Node.js** (v18+): Required for CLI and JS tooling.
@@ -100,7 +128,6 @@ You'll see the Titan Dev Server spin up:
100
128
  • Your app is now orbiting Titan Planet
101
129
  ```
102
130
 
103
- ---
104
131
 
105
132
  # ⚡ Hybrid Action System
106
133
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ezetgalaxy/titan",
3
- "version": "26.15.1",
3
+ "version": "26.15.3",
4
4
  "description": "Titan Planet is a JavaScript-first backend framework that embeds JS actions into a Rust + Axum server and ships as a single native binary. Routes are compiled to static metadata; only actions run in the embedded JS runtime. No Node.js. No event loop in production.",
5
5
  "license": "ISC",
6
6
  "author": "ezetgalaxy",
@@ -470,16 +470,15 @@ pub fn execute_action_optimized(
470
470
  let p_val = v8_str(scope, req_path);
471
471
  req_obj.set(scope, p_key.into(), p_val.into());
472
472
 
473
- // rawBodyzero-copy via ArrayBuffer backing store
473
+ // bodyattach raw bytes as ArrayBuffer under "rawBody" key
474
+ let rb_key = v8::Local::new(scope, &gk_raw_body);
474
475
  let body_val: v8::Local<v8::Value> = if let Some(bytes) = req_body {
475
- let vec = bytes.to_vec();
476
- let store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(vec.into_boxed_slice());
477
- let ab = v8::ArrayBuffer::with_backing_store(scope, &store.make_shared());
476
+ let backing = v8::ArrayBuffer::new_backing_store_from_vec(bytes.to_vec());
477
+ let ab = v8::ArrayBuffer::with_backing_store(scope, &backing.make_shared());
478
478
  ab.into()
479
479
  } else {
480
480
  v8::null(scope).into()
481
481
  };
482
- let rb_key = v8::Local::new(scope, &gk_raw_body);
483
482
  req_obj.set(scope, rb_key.into(), body_val);
484
483
 
485
484
  // headers
@@ -577,4 +576,4 @@ pub fn throw(scope: &mut v8::HandleScope, msg: &str) {
577
576
  let message = v8_str(scope, msg);
578
577
  let exception = v8::Exception::error(scope, message);
579
578
  scope.throw_exception(exception);
580
- }
579
+ }
@@ -15,6 +15,32 @@ if (!globalThis.__TITAN_CORE_LOADED__) {
15
15
  const wrapped = function (req) {
16
16
  const requestId = req.__titan_request_id;
17
17
 
18
+ if (req.rawBody && req.rawBody.byteLength !== undefined) {
19
+ try {
20
+ const decoder = new TextDecoder();
21
+ const text = decoder.decode(req.rawBody);
22
+
23
+ const contentType =
24
+ (req.headers && req.headers["content-type"]) ||
25
+ (req.headers && req.headers["Content-Type"]) ||
26
+ "";
27
+
28
+ if (contentType.includes("application/json")) {
29
+ req.body = text ? JSON.parse(text) : {};
30
+ } else if (contentType.includes("application/x-www-form-urlencoded")) {
31
+ req.body = Object.fromEntries(new URLSearchParams(text));
32
+ } else {
33
+ req.body = text;
34
+ }
35
+ } catch (e) {
36
+ req.body = {};
37
+ }
38
+ } else {
39
+ req.body = {};
40
+ }
41
+
42
+ // ===============================
43
+
18
44
  const isSuspend = (err) => {
19
45
  const msg = err && (err.message || String(err));
20
46
  return msg && (msg.includes("__SUSPEND__") || msg.includes("SUSPEND"));
@@ -25,9 +51,7 @@ if (!globalThis.__TITAN_CORE_LOADED__) {
25
51
 
26
52
  if (result && typeof result.then === 'function') {
27
53
  result.then(
28
- (data) => {
29
- t._finish_request(requestId, data);
30
- },
54
+ (data) => t._finish_request(requestId, data),
31
55
  (err) => {
32
56
  if (isSuspend(err)) return;
33
57
  t._finish_request(requestId, { error: err.message || String(err) });
@@ -54,10 +78,8 @@ if (!globalThis.__TITAN_CORE_LOADED__) {
54
78
  }
55
79
  };
56
80
 
57
- // process.env
58
- globalThis.process = {
59
- env: t.loadEnv ? t.loadEnv() : {}
60
- };
81
+ // Titan Environment API
82
+ t.env = t.loadEnv ? t.loadEnv() : {};
61
83
 
62
84
  // Async Proxy Creator
63
85
  function createAsyncOp(op) {
@@ -73,8 +95,7 @@ if (!globalThis.__TITAN_CORE_LOADED__) {
73
95
  }
74
96
 
75
97
  throw new Error(
76
- `[Titan Error] Accessed '${String(prop)}' without drift(). ` +
77
- `Fix: const res = drift(t.fetch(...));`
98
+ `[Titan Error] Accessed '${String(prop)}' without drift(). `
78
99
  );
79
100
  }
80
101
  });
@@ -470,16 +470,15 @@ pub fn execute_action_optimized(
470
470
  let p_val = v8_str(scope, req_path);
471
471
  req_obj.set(scope, p_key.into(), p_val.into());
472
472
 
473
- // rawBodyzero-copy via ArrayBuffer backing store
473
+ // bodyattach raw bytes as ArrayBuffer under "rawBody" key
474
+ let rb_key = v8::Local::new(scope, &gk_raw_body);
474
475
  let body_val: v8::Local<v8::Value> = if let Some(bytes) = req_body {
475
- let vec = bytes.to_vec();
476
- let store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(vec.into_boxed_slice());
477
- let ab = v8::ArrayBuffer::with_backing_store(scope, &store.make_shared());
476
+ let backing = v8::ArrayBuffer::new_backing_store_from_vec(bytes.to_vec());
477
+ let ab = v8::ArrayBuffer::with_backing_store(scope, &backing.make_shared());
478
478
  ab.into()
479
479
  } else {
480
480
  v8::null(scope).into()
481
481
  };
482
- let rb_key = v8::Local::new(scope, &gk_raw_body);
483
482
  req_obj.set(scope, rb_key.into(), body_val);
484
483
 
485
484
  // headers
@@ -577,4 +576,4 @@ pub fn throw(scope: &mut v8::HandleScope, msg: &str) {
577
576
  let message = v8_str(scope, msg);
578
577
  let exception = v8::Exception::error(scope, message);
579
578
  scope.throw_exception(exception);
580
- }
579
+ }
@@ -15,6 +15,32 @@ if (!globalThis.__TITAN_CORE_LOADED__) {
15
15
  const wrapped = function (req) {
16
16
  const requestId = req.__titan_request_id;
17
17
 
18
+ if (req.rawBody && req.rawBody.byteLength !== undefined) {
19
+ try {
20
+ const decoder = new TextDecoder();
21
+ const text = decoder.decode(req.rawBody);
22
+
23
+ const contentType =
24
+ (req.headers && req.headers["content-type"]) ||
25
+ (req.headers && req.headers["Content-Type"]) ||
26
+ "";
27
+
28
+ if (contentType.includes("application/json")) {
29
+ req.body = text ? JSON.parse(text) : {};
30
+ } else if (contentType.includes("application/x-www-form-urlencoded")) {
31
+ req.body = Object.fromEntries(new URLSearchParams(text));
32
+ } else {
33
+ req.body = text;
34
+ }
35
+ } catch (e) {
36
+ req.body = {};
37
+ }
38
+ } else {
39
+ req.body = {};
40
+ }
41
+
42
+ // ===============================
43
+
18
44
  const isSuspend = (err) => {
19
45
  const msg = err && (err.message || String(err));
20
46
  return msg && (msg.includes("__SUSPEND__") || msg.includes("SUSPEND"));
@@ -25,9 +51,7 @@ if (!globalThis.__TITAN_CORE_LOADED__) {
25
51
 
26
52
  if (result && typeof result.then === 'function') {
27
53
  result.then(
28
- (data) => {
29
- t._finish_request(requestId, data);
30
- },
54
+ (data) => t._finish_request(requestId, data),
31
55
  (err) => {
32
56
  if (isSuspend(err)) return;
33
57
  t._finish_request(requestId, { error: err.message || String(err) });
@@ -54,10 +78,8 @@ if (!globalThis.__TITAN_CORE_LOADED__) {
54
78
  }
55
79
  };
56
80
 
57
- // process.env
58
- globalThis.process = {
59
- env: t.loadEnv ? t.loadEnv() : {}
60
- };
81
+ // Titan Environment API
82
+ t.env = t.loadEnv ? t.loadEnv() : {};
61
83
 
62
84
  // Async Proxy Creator
63
85
  function createAsyncOp(op) {
@@ -73,8 +95,7 @@ if (!globalThis.__TITAN_CORE_LOADED__) {
73
95
  }
74
96
 
75
97
  throw new Error(
76
- `[Titan Error] Accessed '${String(prop)}' without drift(). ` +
77
- `Fix: const res = drift(t.fetch(...));`
98
+ `[Titan Error] Accessed '${String(prop)}' without drift(). `
78
99
  );
79
100
  }
80
101
  });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "titanpl-sdk",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
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
5
  "main": "index.js",
6
6
  "type": "module",
@@ -470,16 +470,15 @@ pub fn execute_action_optimized(
470
470
  let p_val = v8_str(scope, req_path);
471
471
  req_obj.set(scope, p_key.into(), p_val.into());
472
472
 
473
- // rawBodyzero-copy via ArrayBuffer backing store
473
+ // bodyattach raw bytes as ArrayBuffer under "rawBody" key
474
+ let rb_key = v8::Local::new(scope, &gk_raw_body);
474
475
  let body_val: v8::Local<v8::Value> = if let Some(bytes) = req_body {
475
- let vec = bytes.to_vec();
476
- let store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(vec.into_boxed_slice());
477
- let ab = v8::ArrayBuffer::with_backing_store(scope, &store.make_shared());
476
+ let backing = v8::ArrayBuffer::new_backing_store_from_vec(bytes.to_vec());
477
+ let ab = v8::ArrayBuffer::with_backing_store(scope, &backing.make_shared());
478
478
  ab.into()
479
479
  } else {
480
480
  v8::null(scope).into()
481
481
  };
482
- let rb_key = v8::Local::new(scope, &gk_raw_body);
483
482
  req_obj.set(scope, rb_key.into(), body_val);
484
483
 
485
484
  // headers
@@ -577,4 +576,4 @@ pub fn throw(scope: &mut v8::HandleScope, msg: &str) {
577
576
  let message = v8_str(scope, msg);
578
577
  let exception = v8::Exception::error(scope, message);
579
578
  scope.throw_exception(exception);
580
- }
579
+ }
@@ -15,6 +15,32 @@ if (!globalThis.__TITAN_CORE_LOADED__) {
15
15
  const wrapped = function (req) {
16
16
  const requestId = req.__titan_request_id;
17
17
 
18
+ if (req.rawBody && req.rawBody.byteLength !== undefined) {
19
+ try {
20
+ const decoder = new TextDecoder();
21
+ const text = decoder.decode(req.rawBody);
22
+
23
+ const contentType =
24
+ (req.headers && req.headers["content-type"]) ||
25
+ (req.headers && req.headers["Content-Type"]) ||
26
+ "";
27
+
28
+ if (contentType.includes("application/json")) {
29
+ req.body = text ? JSON.parse(text) : {};
30
+ } else if (contentType.includes("application/x-www-form-urlencoded")) {
31
+ req.body = Object.fromEntries(new URLSearchParams(text));
32
+ } else {
33
+ req.body = text;
34
+ }
35
+ } catch (e) {
36
+ req.body = {};
37
+ }
38
+ } else {
39
+ req.body = {};
40
+ }
41
+
42
+ // ===============================
43
+
18
44
  const isSuspend = (err) => {
19
45
  const msg = err && (err.message || String(err));
20
46
  return msg && (msg.includes("__SUSPEND__") || msg.includes("SUSPEND"));
@@ -25,9 +51,7 @@ if (!globalThis.__TITAN_CORE_LOADED__) {
25
51
 
26
52
  if (result && typeof result.then === 'function') {
27
53
  result.then(
28
- (data) => {
29
- t._finish_request(requestId, data);
30
- },
54
+ (data) => t._finish_request(requestId, data),
31
55
  (err) => {
32
56
  if (isSuspend(err)) return;
33
57
  t._finish_request(requestId, { error: err.message || String(err) });
@@ -54,10 +78,8 @@ if (!globalThis.__TITAN_CORE_LOADED__) {
54
78
  }
55
79
  };
56
80
 
57
- // process.env
58
- globalThis.process = {
59
- env: t.loadEnv ? t.loadEnv() : {}
60
- };
81
+ // Titan Environment API
82
+ t.env = t.loadEnv ? t.loadEnv() : {};
61
83
 
62
84
  // Async Proxy Creator
63
85
  function createAsyncOp(op) {
@@ -73,8 +95,7 @@ if (!globalThis.__TITAN_CORE_LOADED__) {
73
95
  }
74
96
 
75
97
  throw new Error(
76
- `[Titan Error] Accessed '${String(prop)}' without drift(). ` +
77
- `Fix: const res = drift(t.fetch(...));`
98
+ `[Titan Error] Accessed '${String(prop)}' without drift(). `
78
99
  );
79
100
  }
80
101
  });