@ezetgalaxy/titan 26.7.4 → 26.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +88 -201
  2. package/index.js +552 -489
  3. package/package.json +6 -5
  4. package/templates/js/_gitignore +37 -0
  5. package/templates/{package.json → js/package.json} +4 -1
  6. package/templates/js/server/action_map.json +3 -0
  7. package/templates/js/server/actions/hello.jsbundle +48 -0
  8. package/templates/js/server/routes.json +16 -0
  9. package/templates/js/server/src/actions_rust/mod.rs +15 -0
  10. package/templates/{server → js/server}/src/extensions.rs +149 -17
  11. package/templates/{titan → js/titan}/bundle.js +22 -9
  12. package/templates/js/titan/dev.js +194 -0
  13. package/templates/{titan → js/titan}/titan.js +25 -1
  14. package/templates/rust/Dockerfile +66 -0
  15. package/templates/rust/_dockerignore +3 -0
  16. package/templates/rust/_gitignore +37 -0
  17. package/templates/rust/app/actions/hello.js +5 -0
  18. package/templates/rust/app/actions/rust_hello.rs +14 -0
  19. package/templates/rust/app/app.js +11 -0
  20. package/templates/rust/app/titan.d.ts +101 -0
  21. package/templates/rust/jsconfig.json +19 -0
  22. package/templates/rust/package.json +13 -0
  23. package/templates/rust/server/Cargo.lock +2869 -0
  24. package/templates/rust/server/Cargo.toml +27 -0
  25. package/templates/rust/server/action_map.json +3 -0
  26. package/templates/rust/server/actions/hello.jsbundle +47 -0
  27. package/templates/rust/server/routes.json +22 -0
  28. package/templates/rust/server/src/action_management.rs +131 -0
  29. package/templates/rust/server/src/actions_rust/mod.rs +19 -0
  30. package/templates/rust/server/src/actions_rust/rust_hello.rs +14 -0
  31. package/templates/rust/server/src/errors.rs +10 -0
  32. package/templates/rust/server/src/extensions.rs +989 -0
  33. package/templates/rust/server/src/main.rs +443 -0
  34. package/templates/rust/server/src/utils.rs +33 -0
  35. package/templates/rust/titan/bundle.js +157 -0
  36. package/templates/rust/titan/dev.js +194 -0
  37. package/templates/rust/titan/titan.js +122 -0
  38. package/titanpl-sdk/package.json +1 -1
  39. package/titanpl-sdk/templates/Dockerfile +4 -17
  40. package/titanpl-sdk/templates/server/src/extensions.rs +218 -423
  41. package/titanpl-sdk/templates/server/src/main.rs +68 -134
  42. package/scripts/make_dist.sh +0 -71
  43. package/templates/titan/dev.js +0 -144
  44. /package/templates/{Dockerfile → js/Dockerfile} +0 -0
  45. /package/templates/{.dockerignore → js/_dockerignore} +0 -0
  46. /package/templates/{app → js/app}/actions/hello.js +0 -0
  47. /package/templates/{app → js/app}/app.js +0 -0
  48. /package/templates/{app → js/app}/titan.d.ts +0 -0
  49. /package/templates/{jsconfig.json → js/jsconfig.json} +0 -0
  50. /package/templates/{server → js/server}/Cargo.lock +0 -0
  51. /package/templates/{server → js/server}/Cargo.toml +0 -0
  52. /package/templates/{server → js/server}/src/action_management.rs +0 -0
  53. /package/templates/{server → js/server}/src/errors.rs +0 -0
  54. /package/templates/{server → js/server}/src/main.rs +0 -0
  55. /package/templates/{server → js/server}/src/utils.rs +0 -0
@@ -0,0 +1,194 @@
1
+ import chokidar from "chokidar";
2
+ import { spawn, execSync } from "child_process";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+ import fs from "fs";
6
+ import { bundle } from "./bundle.js";
7
+
8
+ // Required for __dirname in ES modules
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+
12
+
13
+ // Colors
14
+ import { createRequire } from "module";
15
+
16
+ // Colors
17
+ const cyan = (t) => `\x1b[36m${t}\x1b[0m`;
18
+ const green = (t) => `\x1b[32m${t}\x1b[0m`;
19
+ const yellow = (t) => `\x1b[33m${t}\x1b[0m`;
20
+ const red = (t) => `\x1b[31m${t}\x1b[0m`;
21
+ const gray = (t) => `\x1b[90m${t}\x1b[0m`;
22
+ const bold = (t) => `\x1b[1m${t}\x1b[0m`;
23
+
24
+ function getTitanVersion() {
25
+ try {
26
+ // 1. Try resolving from node_modules (standard user case)
27
+ const require = createRequire(import.meta.url);
28
+ // We look for @ezetgalaxy/titan/package.json
29
+ const pkgPath = require.resolve("@ezetgalaxy/titan/package.json");
30
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
31
+ return pkg.version;
32
+ } catch (e) {
33
+ try {
34
+ // 2. Fallback for local dev (path to repo root)
35
+ const localPath = path.join(__dirname, "..", "..", "..", "package.json");
36
+ if (fs.existsSync(localPath)) {
37
+ const pkg = JSON.parse(fs.readFileSync(localPath, "utf-8"));
38
+ if (pkg.name === "@ezetgalaxy/titan") {
39
+ return pkg.version;
40
+ }
41
+ }
42
+ } catch (e2) { }
43
+ }
44
+ return "0.1.0"; // Fallback
45
+ }
46
+
47
+ let serverProcess = null;
48
+ let isKilling = false;
49
+
50
+ // ... (killServer same as before)
51
+ async function killServer() {
52
+ if (!serverProcess) return;
53
+
54
+ isKilling = true;
55
+ const pid = serverProcess.pid;
56
+ const killPromise = new Promise((resolve) => {
57
+ if (serverProcess.exitCode !== null) return resolve();
58
+ serverProcess.once("close", resolve);
59
+ });
60
+
61
+ if (process.platform === "win32") {
62
+ try {
63
+ execSync(`taskkill /pid ${pid} /f /t`, { stdio: 'ignore' });
64
+ } catch (e) {
65
+ // Ignore errors if process is already dead
66
+ }
67
+ } else {
68
+ serverProcess.kill();
69
+ }
70
+
71
+ try {
72
+ await killPromise;
73
+ } catch (e) { }
74
+ serverProcess = null;
75
+ isKilling = false;
76
+ }
77
+
78
+ async function startRustServer(retryCount = 0) {
79
+ const waitTime = retryCount > 0 ? 2000 : 1000;
80
+
81
+ await killServer();
82
+ await new Promise(r => setTimeout(r, waitTime));
83
+
84
+ const serverPath = path.join(process.cwd(), "server");
85
+ const startTime = Date.now();
86
+
87
+ if (retryCount > 0) {
88
+ console.log(yellow(`[Titan] Retrying Rust server (Attempt ${retryCount})...`));
89
+ }
90
+
91
+ serverProcess = spawn("cargo", ["run", "--jobs", "1"], {
92
+ cwd: serverPath,
93
+ stdio: "inherit",
94
+ shell: true,
95
+ env: { ...process.env, CARGO_INCREMENTAL: "0" }
96
+ });
97
+
98
+ serverProcess.on("close", async (code) => {
99
+ if (isKilling) return;
100
+ const runTime = Date.now() - startTime;
101
+ if (code !== 0 && code !== null && runTime < 15000 && retryCount < 5) {
102
+ await startRustServer(retryCount + 1);
103
+ } else if (code !== 0 && code !== null && retryCount >= 5) {
104
+ console.log(red(`[Titan] Server failed to start after multiple attempts.`));
105
+ }
106
+ });
107
+ }
108
+
109
+ async function rebuild() {
110
+ // process.stdout.write(gray("[Titan] Preparing runtime... "));
111
+ const start = Date.now();
112
+ try {
113
+ execSync("node app/app.js", { stdio: "ignore" });
114
+ await bundle();
115
+ // console.log(green("Done"));
116
+ const elapsed = ((Date.now() - start) / 1000).toFixed(1);
117
+ console.log(gray(` A new orbit is ready for your app in ${elapsed}s`));
118
+ console.log(green(` Your app is now orbiting Titan Planet`));
119
+ } catch (e) {
120
+ console.log(red("Failed"));
121
+ console.log(red("[Titan] Failed to prepare runtime. Check your app/app.js"));
122
+ }
123
+ }
124
+
125
+ async function startDev() {
126
+ const root = process.cwd();
127
+ // Check if Rust actions exist by looking for .rs files in app/actions
128
+ const actionsDir = path.join(root, "app", "actions");
129
+ let hasRust = false;
130
+ if (fs.existsSync(actionsDir)) {
131
+ hasRust = fs.readdirSync(actionsDir).some(f => f.endsWith(".rs"));
132
+ }
133
+
134
+ const mode = hasRust ? "Rust + JS Actions" : "JS Actions";
135
+ const version = getTitanVersion();
136
+
137
+ console.clear();
138
+ console.log("");
139
+ console.log(` ${bold(cyan("Titan Planet"))} ${gray("v" + version)} ${yellow("[ Dev Mode ]")}`);
140
+ console.log("");
141
+ console.log(` ${gray("Type: ")} ${mode}`);
142
+ console.log(` ${gray("Hot Reload: ")} ${green("Enabled")}`);
143
+
144
+ if (fs.existsSync(path.join(root, ".env"))) {
145
+ console.log(` ${gray("Env: ")} ${yellow("Loaded")}`);
146
+ }
147
+ console.log(""); // Spacer
148
+
149
+ // FIRST BUILD
150
+ try {
151
+ await rebuild();
152
+ await startRustServer();
153
+ } catch (e) {
154
+ console.log(red("[Titan] Initial build failed. Waiting for changes..."));
155
+ }
156
+
157
+ // ... watcher logic same as before but using color vars ...
158
+ const watcher = chokidar.watch(["app", ".env"], {
159
+ ignoreInitial: true,
160
+ awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 }
161
+ });
162
+
163
+ let timer = null;
164
+ watcher.on("all", async (event, file) => {
165
+ if (timer) clearTimeout(timer);
166
+ timer = setTimeout(async () => {
167
+ console.log(""); // Spacer before reload logs
168
+ if (file.includes(".env")) {
169
+ console.log(yellow("[Titan] Env Refreshed"));
170
+ } else {
171
+ console.log(cyan(`[Titan] Change: ${path.basename(file)}`));
172
+ }
173
+ try {
174
+ await killServer();
175
+ await rebuild();
176
+ await startRustServer();
177
+ } catch (e) {
178
+ console.log(red("[Titan] Build failed -- waiting for changes..."));
179
+ }
180
+ }, 1000);
181
+ });
182
+ }
183
+
184
+ // Handle graceful exit to release file locks
185
+ async function handleExit() {
186
+ console.log("\n[Titan] Stopping server...");
187
+ await killServer();
188
+ process.exit(0);
189
+ }
190
+
191
+ process.on("SIGINT", handleExit);
192
+ process.on("SIGTERM", handleExit);
193
+
194
+ startDev();
@@ -0,0 +1,122 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { bundle } from "./bundle.js";
4
+
5
+ const cyan = (t) => `\x1b[36m${t}\x1b[0m`;
6
+ const green = (t) => `\x1b[32m${t}\x1b[0m`;
7
+
8
+ const routes = {};
9
+ const dynamicRoutes = {};
10
+ const actionMap = {};
11
+
12
+ function addRoute(method, route) {
13
+ const key = `${method.toUpperCase()}:${route}`;
14
+
15
+
16
+ return {
17
+ reply(value) {
18
+ routes[key] = {
19
+ type: typeof value === "object" ? "json" : "text",
20
+ value
21
+ };
22
+ },
23
+
24
+ action(name) {
25
+ if (route.includes(":")) {
26
+ if (!dynamicRoutes[method]) dynamicRoutes[method] = [];
27
+ dynamicRoutes[method].push({
28
+ method: method.toUpperCase(),
29
+ pattern: route,
30
+ action: name
31
+ });
32
+ } else {
33
+ routes[key] = {
34
+ type: "action",
35
+ value: name
36
+ };
37
+ actionMap[key] = name;
38
+ }
39
+ }
40
+ };
41
+ }
42
+
43
+ /**
44
+ * @typedef {Object} RouteHandler
45
+ * @property {(value: any) => void} reply - Send a direct response
46
+ * @property {(name: string) => void} action - Bind to a server-side action
47
+ */
48
+
49
+ /**
50
+ * Titan App Builder
51
+ */
52
+ const t = {
53
+ /**
54
+ * Define a GET route
55
+ * @param {string} route
56
+ * @returns {RouteHandler}
57
+ */
58
+ get(route) {
59
+ return addRoute("GET", route);
60
+ },
61
+
62
+ /**
63
+ * Define a POST route
64
+ * @param {string} route
65
+ * @returns {RouteHandler}
66
+ */
67
+ post(route) {
68
+ return addRoute("POST", route);
69
+ },
70
+
71
+ log(module, msg) {
72
+ console.log(`[\x1b[35m${module}\x1b[0m] ${msg}`);
73
+ },
74
+
75
+ /**
76
+ * Start the Titan Server
77
+ * @param {number} [port=3000]
78
+ * @param {string} [msg=""]
79
+ */
80
+ async start(port = 3000, msg = "") {
81
+ try {
82
+ console.log(cyan("[Titan] Preparing runtime..."));
83
+ await bundle();
84
+
85
+ const base = path.join(process.cwd(), "server");
86
+ if (!fs.existsSync(base)) {
87
+ fs.mkdirSync(base, { recursive: true });
88
+ }
89
+
90
+ const routesPath = path.join(base, "routes.json");
91
+ const actionMapPath = path.join(base, "action_map.json");
92
+
93
+ fs.writeFileSync(
94
+ routesPath,
95
+ JSON.stringify(
96
+ {
97
+ __config: { port },
98
+ routes,
99
+ __dynamic_routes: Object.values(dynamicRoutes).flat()
100
+ },
101
+ null,
102
+ 2
103
+ )
104
+ );
105
+
106
+ fs.writeFileSync(
107
+ actionMapPath,
108
+ JSON.stringify(actionMap, null, 2)
109
+ );
110
+
111
+ console.log(green("✔ Titan metadata written successfully"));
112
+ if (msg) console.log(cyan(msg));
113
+
114
+ } catch (e) {
115
+ console.error(`\x1b[31m[Titan] Build Error: ${e.message}\x1b[0m`);
116
+ process.exit(1);
117
+ }
118
+ }
119
+ };
120
+
121
+
122
+ export default t;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "titanpl-sdk",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
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",
@@ -18,20 +18,6 @@ COPY . .
18
18
  # Install JS dependencies (needed for Titan DSL + bundler)
19
19
  RUN npm install
20
20
 
21
- SHELL ["/bin/bash", "-c"]
22
-
23
- # Extract Titan extensions into .ext
24
- RUN mkdir -p /app/.ext && \
25
- find /app/node_modules -maxdepth 5 -type f -name "titan.json" -print0 | \
26
- while IFS= read -r -d '' file; do \
27
- pkg_dir="$(dirname "$file")"; \
28
- pkg_name="$(basename "$pkg_dir")"; \
29
- echo "Copying Titan extension: $pkg_name from $pkg_dir"; \
30
- cp -r "$pkg_dir" "/app/.ext/$pkg_name"; \
31
- done && \
32
- echo "Extensions in .ext:" && \
33
- ls -R /app/.ext
34
-
35
21
  # Build Titan metadata + bundle JS actions
36
22
  RUN titan build
37
23
 
@@ -48,7 +34,7 @@ FROM debian:stable-slim
48
34
  WORKDIR /app
49
35
 
50
36
  # Copy Rust binary from builder stage
51
- COPY --from=builder /app/server/target/release/titan-server ./titan-server
37
+ COPY --from=builder /app/server/target/release/server ./titan-server
52
38
 
53
39
  # Copy Titan routing metadata
54
40
  COPY --from=builder /app/server/routes.json ./routes.json
@@ -58,9 +44,10 @@ COPY --from=builder /app/server/action_map.json ./action_map.json
58
44
  RUN mkdir -p /app/actions
59
45
  COPY --from=builder /app/server/actions /app/actions
60
46
 
61
- # Copy only Titan extensions
62
- COPY --from=builder /app/.ext ./.ext
47
+ COPY --from=builder /app/db /app/assets
63
48
 
49
+ # Expose Titan port
64
50
  EXPOSE 3000
65
51
 
52
+ # Start Titan
66
53
  CMD ["./titan-server"]