@ezetgalaxy/titan 25.12.8 → 25.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -4,11 +4,11 @@ import path from "path";
4
4
  import { execSync, spawn } from "child_process";
5
5
  import { fileURLToPath } from "url";
6
6
 
7
- // __dirname in ES modules
7
+ /* Resolve __dirname for ES modules */
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = path.dirname(__filename);
10
10
 
11
- // Colors
11
+ /* Colors */
12
12
  const cyan = (t) => `\x1b[36m${t}\x1b[0m`;
13
13
  const green = (t) => `\x1b[32m${t}\x1b[0m`;
14
14
  const yellow = (t) => `\x1b[33m${t}\x1b[0m`;
@@ -18,7 +18,13 @@ const bold = (t) => `\x1b[1m${t}\x1b[0m`;
18
18
  const args = process.argv.slice(2);
19
19
  const cmd = args[0];
20
20
 
21
- // COPY TEMPLATES
21
+ /* Titan version (read from package.json) */
22
+ const pkg = JSON.parse(
23
+ fs.readFileSync(path.join(__dirname, "package.json"), "utf8")
24
+ );
25
+ const TITAN_VERSION = pkg.version;
26
+
27
+ /* Safe copy directory */
22
28
  function copyDir(src, dest) {
23
29
  fs.mkdirSync(dest, { recursive: true });
24
30
 
@@ -34,20 +40,21 @@ function copyDir(src, dest) {
34
40
  }
35
41
  }
36
42
 
37
- // HELP
43
+ /* HELP */
38
44
  function help() {
39
45
  console.log(`
40
- ${bold(cyan("Titan CLI"))}
46
+ ${bold(cyan("Titan CLI"))} v${TITAN_VERSION}
41
47
 
42
48
  ${green("tit init <project>")} Create new Titan project
43
49
  ${green("tit dev")} Dev mode (hot reload)
44
50
  ${green("tit build")} Build production Rust server
45
51
  ${green("tit start")} Start production binary
46
- ${green("tit update")} Update to latest version
52
+ ${green("tit update")} Update Titan engine
53
+ ${green("tit --version")} Show Titan CLI version
47
54
  `);
48
55
  }
49
56
 
50
- // INIT PROJECT
57
+ /* INIT PROJECT */
51
58
  function initProject(name) {
52
59
  if (!name) return console.log(red("Usage: tit init <project>"));
53
60
 
@@ -61,7 +68,6 @@ function initProject(name) {
61
68
 
62
69
  console.log(cyan(`Creating Titan project → ${target}`));
63
70
 
64
- copyDir(templateDir, target);
65
71
  copyDir(templateDir, target);
66
72
 
67
73
  [".gitignore", ".dockerignore", "Dockerfile"].forEach((file) => {
@@ -70,13 +76,12 @@ function initProject(name) {
70
76
  if (fs.existsSync(src)) fs.copyFileSync(src, dest);
71
77
  });
72
78
 
73
-
74
79
  console.log(green("✔ Titan project created!"));
75
80
  console.log(cyan("Installing dependencies..."));
76
81
 
77
82
  execSync(`npm install esbuild --silent`, {
78
83
  cwd: target,
79
- stdio: "inherit"
84
+ stdio: "inherit",
80
85
  });
81
86
 
82
87
  console.log(green("✔ Dependencies installed"));
@@ -87,31 +92,44 @@ Next steps:
87
92
  `);
88
93
  }
89
94
 
90
- // BUNDLE
91
- function runBundler() {
92
- const bundler = path.join(process.cwd(), "titan", "bundle.js");
95
+ /* BUNDLER (absolute path, Railway-safe) */
96
+ function runBundler(root) {
97
+ const bundler = path.join(root, "titan", "bundle.js");
93
98
 
94
- if (fs.existsSync(bundler)) {
95
- execSync(`node ${bundler}`, { stdio: "inherit" });
96
- } else {
97
- console.log(yellow("Warning: titan/bundle.js missing."));
99
+ if (!fs.existsSync(bundler)) {
100
+ console.log(red("ERROR: titan/bundle.js missing."));
101
+ process.exit(1);
98
102
  }
99
- }
100
103
 
101
- // ------------------------------------------
102
- // FULL HOT RELOAD DEV SERVER
103
- // ------------------------------------------
104
+ execSync(`node "${bundler}"`, { stdio: "inherit" });
105
+ }
104
106
 
107
+ /* DEV SERVER — HOT RELOAD */
105
108
  async function devServer() {
109
+ const root = process.cwd();
106
110
  console.log(cyan("Titan Dev Mode — Hot Reload Enabled"));
107
111
 
108
112
  let rustProcess = null;
109
113
 
114
+ function launchRust(done) {
115
+ const processHandle = spawn("cargo", ["run"], {
116
+ cwd: path.join(root, "server"),
117
+ stdio: "inherit",
118
+ shell: true,
119
+ });
120
+
121
+ processHandle.on("spawn", () => setTimeout(done, 200));
122
+ processHandle.on("close", (code) =>
123
+ console.log(`[Titan] Rust server exited: ${code}`)
124
+ );
125
+
126
+ return processHandle;
127
+ }
128
+
110
129
  function startRust() {
111
130
  return new Promise((resolve) => {
112
- // if server already running → kill it
113
131
  if (rustProcess) {
114
- console.log("[Titan] Killing old Rust server...");
132
+ console.log("[Titan] Restarting Rust server...");
115
133
 
116
134
  if (process.platform === "win32") {
117
135
  const killer = spawn("taskkill", ["/PID", rustProcess.pid, "/T", "/F"], {
@@ -134,40 +152,19 @@ async function devServer() {
134
152
  });
135
153
  }
136
154
 
137
- function launchRust(done) {
138
- const processHandle = spawn("cargo", ["run"], {
139
- cwd: path.join(process.cwd(), "server"),
155
+ /* Build logic */
156
+ function rebuild() {
157
+ execSync(`node "${path.join(root, "app", "app.js")}"`, {
140
158
  stdio: "inherit",
141
- shell: true,
142
- });
143
-
144
- processHandle.on("spawn", () => {
145
- setTimeout(done, 200); // wait for OS to release port
146
159
  });
147
160
 
148
- processHandle.on("close", (code) => {
149
- console.log(`[Titan] Rust server exited: ${code}`);
150
- });
151
-
152
- return processHandle;
153
- }
154
-
155
-
156
- function rebuild() {
157
- console.log(cyan("Titan: Regenerating routes..."));
158
- execSync("node app/app.js", { stdio: "inherit" });
159
-
160
- console.log(cyan("Titan: Bundling actions..."));
161
- runBundler();
161
+ runBundler(root);
162
162
  }
163
163
 
164
- // First build
165
164
  rebuild();
166
165
  startRust();
167
166
 
168
- // WATCHER
169
167
  const chokidar = (await import("chokidar")).default;
170
-
171
168
  const watcher = chokidar.watch("app", { ignoreInitial: true });
172
169
 
173
170
  let timer = null;
@@ -176,178 +173,88 @@ async function devServer() {
176
173
  if (timer) clearTimeout(timer);
177
174
 
178
175
  timer = setTimeout(() => {
179
- console.log(yellow(`Change detected → ${file}`));
180
-
176
+ console.log(yellow(`Change → ${file}`));
181
177
  rebuild();
182
178
  startRust();
183
-
184
179
  }, 250);
185
180
  });
186
181
  }
187
182
 
188
-
189
- // BUILD RELEASE — PRODUCTION READY
183
+ /* PRODUCTION BUILD */
190
184
  function buildProd() {
191
- console.log(cyan("Titan: Building production output..."));
185
+ const root = process.cwd();
186
+ const appJs = path.join(root, "app", "app.js");
192
187
 
193
- const projectRoot = process.cwd();
194
-
195
- const appJs = path.join(projectRoot, "app", "app.js");
196
- const bundler = path.join(projectRoot, "titan", "bundle.js");
197
- const serverDir = path.join(projectRoot, "server");
188
+ console.log(cyan("Titan: Building production output..."));
198
189
 
199
- // 1) Ensure app/app.js exists
200
190
  if (!fs.existsSync(appJs)) {
201
- console.log(red("ERROR: app/app.js not found. Cannot build Titan project."));
191
+ console.log(red("ERROR: app/app.js missing."));
202
192
  process.exit(1);
203
193
  }
204
194
 
205
- // 2) Ensure bundler exists
206
- if (!fs.existsSync(bundler)) {
207
- console.log(red("ERROR: titan/bundle.js not found. Cannot bundle actions."));
208
- process.exit(1);
209
- }
195
+ /* Generate routes */
196
+ execSync(`node "${appJs}"`, { stdio: "inherit" });
210
197
 
211
- // 3) Generate routes.json + action_map.json
212
- console.log(cyan("→ Generating Titan metadata (routes + action_map)..."));
213
- try {
214
- execSync(`node app/app.js --build`, { stdio: "inherit" });
215
- } catch (err) {
216
- console.log(red("Failed to generate metadata via app/app.js"));
217
- process.exit(1);
218
- }
198
+ /* Bundle actions */
199
+ runBundler(root);
219
200
 
220
- // 4) Bundle JS actions → .jsbundle files
221
- console.log(cyan(" Bundling Titan actions..."));
222
- try {
223
- execSync(`node titan/bundle.js`, { stdio: "inherit" });
224
- } catch (err) {
225
- console.log(red("Bundler failed. Check titan/bundle.js for errors."));
226
- process.exit(1);
227
- }
201
+ /* Copy bundles server/actions */
202
+ const outDir = path.join(root, "server", "actions");
203
+ fs.mkdirSync(outDir, { recursive: true });
228
204
 
229
- // 5) Ensure server/actions folder exists
230
- const actionsOut = path.join(serverDir, "actions");
231
- if (!fs.existsSync(actionsOut)) {
232
- fs.mkdirSync(actionsOut, { recursive: true });
233
- }
205
+ const builtActions = path.join(root, "titan", "actions");
234
206
 
235
- // 6) Copy generated bundles into server/actions
236
- const builtActions = path.join(projectRoot, "titan", "actions");
237
207
  if (fs.existsSync(builtActions)) {
238
208
  for (const file of fs.readdirSync(builtActions)) {
239
209
  if (file.endsWith(".jsbundle")) {
240
210
  fs.copyFileSync(
241
211
  path.join(builtActions, file),
242
- path.join(actionsOut, file)
212
+ path.join(outDir, file)
243
213
  );
244
214
  }
245
215
  }
246
216
  }
247
217
 
248
- console.log(green("✔ Bundles copied to server/actions"));
218
+ console.log(green("✔ Actions copied to server/actions"));
249
219
 
250
- // 7) Build Rust binary
251
- console.log(cyan("→ Building Rust release binary..."));
252
- try {
253
- execSync(`cargo build --release`, {
254
- cwd: serverDir,
255
- stdio: "inherit",
256
- });
257
- } catch (err) {
258
- console.log(red("Rust build failed."));
259
- process.exit(1);
260
- }
220
+ /* Rust release build */
221
+ execSync(`cargo build --release`, {
222
+ cwd: path.join(root, "server"),
223
+ stdio: "inherit",
224
+ });
261
225
 
262
- console.log(green("✔ Titan production build complete!"));
263
- console.log(green("✔ Rust binary ready at server/target/release/"));
226
+ console.log(green("✔ Rust binary built successfully."));
264
227
  }
265
228
 
266
-
267
- // START PRODUCTION
229
+ /* START PRODUCTION BINARY */
268
230
  function startProd() {
269
- const isWindows = process.platform === "win32";
270
- const binaryName = isWindows ? "titan-server.exe" : "titan-server";
271
-
272
- const exe = path.join(
273
- process.cwd(),
274
- "server",
275
- "target",
276
- "release",
277
- binaryName
278
- );
231
+ const isWin = process.platform === "win32";
232
+ const bin = isWin ? "titan-server.exe" : "titan-server";
279
233
 
234
+ const exe = path.join(process.cwd(), "server", "target", "release", bin);
280
235
  execSync(`"${exe}"`, { stdio: "inherit" });
281
236
  }
282
237
 
283
- // ------------------------------------------
284
- // TITAN UPDATE — Upgrade titan/ runtime
285
- // ------------------------------------------
238
+ /* UPDATE TITAN */
286
239
  function updateTitan() {
287
- const projectRoot = process.cwd();
288
- const projectTitan = path.join(projectRoot, "titan");
240
+ const root = process.cwd();
241
+ const projectTitan = path.join(root, "titan");
289
242
 
290
243
  const cliTemplatesRoot = path.join(__dirname, "templates");
291
244
  const cliTitan = path.join(cliTemplatesRoot, "titan");
292
245
 
293
246
  if (!fs.existsSync(projectTitan)) {
294
- console.log(red("No titan/ folder found in this project."));
295
- console.log(yellow("Make sure you are inside a Titan project."));
247
+ console.log(red("Not a Titan project (titan/ missing)."));
296
248
  return;
297
249
  }
298
250
 
299
-
300
- //
301
- // 2. Replace titan/ runtime folder
302
- //
303
251
  fs.rmSync(projectTitan, { recursive: true, force: true });
304
- console.log(green("✔ Old titan/ runtime removed"));
305
-
306
252
  copyDir(cliTitan, projectTitan);
307
- console.log(green("✔ titan/ runtime updated"));
308
-
309
- //
310
- // 3. Update server/Cargo.toml
311
- //
312
- const srcToml = path.join(cliTemplatesRoot, "server", "Cargo.toml");
313
- const destToml = path.join(projectRoot, "server", "Cargo.toml");
314
- if (fs.existsSync(srcToml)) {
315
- fs.copyFileSync(srcToml, destToml);
316
- console.log(green("✔ Updated server/Cargo.toml"));
317
- }
318
-
319
- //
320
- // 4. Update ONLY server/src/main.rs
321
- //
322
- const srcMain = path.join(cliTemplatesRoot, "server", "src", "main.rs");
323
- const destMain = path.join(projectRoot, "server", "src", "main.rs");
324
- if (fs.existsSync(srcMain)) {
325
- fs.copyFileSync(srcMain, destMain);
326
- console.log(green("✔ Updated server/src/main.rs"));
327
- }
328
-
329
- //
330
- // 5. Update root-level config files
331
- //
332
- [".gitignore", ".dockerignore", "Dockerfile"].forEach((file) => {
333
- const src = path.join(cliTemplatesRoot, file);
334
- const dest = path.join(projectRoot, file);
335
-
336
- if (fs.existsSync(src)) {
337
- fs.copyFileSync(src, dest);
338
- console.log(green(`✔ Updated ${file}`));
339
- }
340
- });
341
253
 
342
- console.log(cyan("✔ Titan forced update complete"));
254
+ console.log(green("✔ Titan runtime updated"));
343
255
  }
344
256
 
345
-
346
-
347
-
348
-
349
-
350
- // ROUTER
257
+ /* ROUTER */
351
258
  switch (cmd) {
352
259
  case "init":
353
260
  initProject(args[1]);
@@ -369,7 +276,12 @@ switch (cmd) {
369
276
  updateTitan();
370
277
  break;
371
278
 
279
+ case "--version":
280
+ case "-v":
281
+ case "version":
282
+ console.log(green(`Titan v${TITAN_VERSION}`));
283
+ break;
284
+
372
285
  default:
373
286
  help();
374
287
  }
375
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ezetgalaxy/titan",
3
- "version": "25.12.8",
3
+ "version": "25.13.0",
4
4
  "description": "JavaScript backend framework that compiles your JS into a Rust + Axum server.",
5
5
  "license": "ISC",
6
6
  "author": "ezetgalaxy",
@@ -186,12 +186,12 @@ async fn dynamic_handler_inner(
186
186
  .into_response();
187
187
  }
188
188
 
189
- let action_path = state
190
- .project_root
191
- .join("server")
189
+ let action_path = state.project_root
192
190
  .join("actions")
193
191
  .join(format!("{}.jsbundle", action_name));
194
192
 
193
+
194
+
195
195
  if !action_path.exists() {
196
196
  return (
197
197
  StatusCode::NOT_FOUND,