@ezetgalaxy/titan 25.12.7 → 25.12.9

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 (2) hide show
  1. package/index.js +103 -126
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,14 +1,14 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  import fs from "fs";
3
3
  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
- });
147
-
148
- processHandle.on("close", (code) => {
149
- console.log(`[Titan] Rust server exited: ${code}`);
150
159
  });
151
160
 
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,113 +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
183
+ /* PRODUCTION BUILD */
190
184
  function buildProd() {
191
- console.log(cyan("Titan: generate routes + bundle..."));
192
- execSync("node app/app.js", { stdio: "inherit" });
193
- runBundler();
185
+ const root = process.cwd();
186
+ const appJs = path.join(root, "app", "app.js");
187
+
188
+ console.log(cyan("Titan: Building production output..."));
189
+
190
+ if (!fs.existsSync(appJs)) {
191
+ console.log(red("ERROR: app/app.js missing."));
192
+ process.exit(1);
193
+ }
194
+
195
+ /* Generate routes */
196
+ execSync(`node "${appJs}"`, { stdio: "inherit" });
194
197
 
195
- console.log(cyan("Titan: building release..."));
196
- execSync("cargo build --release", {
197
- cwd: path.join(process.cwd(), "server"),
198
+ /* Bundle actions */
199
+ runBundler(root);
200
+
201
+ /* Copy bundles → server/actions */
202
+ const outDir = path.join(root, "server", "actions");
203
+ fs.mkdirSync(outDir, { recursive: true });
204
+
205
+ const builtActions = path.join(root, "titan", "actions");
206
+
207
+ if (fs.existsSync(builtActions)) {
208
+ for (const file of fs.readdirSync(builtActions)) {
209
+ if (file.endsWith(".jsbundle")) {
210
+ fs.copyFileSync(
211
+ path.join(builtActions, file),
212
+ path.join(outDir, file)
213
+ );
214
+ }
215
+ }
216
+ }
217
+
218
+ console.log(green("✔ Actions copied to server/actions"));
219
+
220
+ /* Rust release build */
221
+ execSync(`cargo build --release`, {
222
+ cwd: path.join(root, "server"),
198
223
  stdio: "inherit",
199
224
  });
225
+
226
+ console.log(green("✔ Rust binary built successfully."));
200
227
  }
201
228
 
202
- // START PRODUCTION
229
+ /* START PRODUCTION BINARY */
203
230
  function startProd() {
204
- const isWindows = process.platform === "win32";
205
- const binaryName = isWindows ? "titan-server.exe" : "titan-server";
206
-
207
- const exe = path.join(
208
- process.cwd(),
209
- "server",
210
- "target",
211
- "release",
212
- binaryName
213
- );
231
+ const isWin = process.platform === "win32";
232
+ const bin = isWin ? "titan-server.exe" : "titan-server";
214
233
 
234
+ const exe = path.join(process.cwd(), "server", "target", "release", bin);
215
235
  execSync(`"${exe}"`, { stdio: "inherit" });
216
236
  }
217
237
 
218
- // ------------------------------------------
219
- // TITAN UPDATE — Upgrade titan/ runtime
220
- // ------------------------------------------
238
+ /* UPDATE TITAN */
221
239
  function updateTitan() {
222
- const projectRoot = process.cwd();
223
- const projectTitan = path.join(projectRoot, "titan");
240
+ const root = process.cwd();
241
+ const projectTitan = path.join(root, "titan");
224
242
 
225
243
  const cliTemplatesRoot = path.join(__dirname, "templates");
226
244
  const cliTitan = path.join(cliTemplatesRoot, "titan");
227
245
 
228
246
  if (!fs.existsSync(projectTitan)) {
229
- console.log(red("No titan/ folder found in this project."));
230
- console.log(yellow("Make sure you are inside a Titan project."));
247
+ console.log(red("Not a Titan project (titan/ missing)."));
231
248
  return;
232
249
  }
233
250
 
234
-
235
- //
236
- // 2. Replace titan/ runtime folder
237
- //
238
251
  fs.rmSync(projectTitan, { recursive: true, force: true });
239
- console.log(green("✔ Old titan/ runtime removed"));
240
-
241
252
  copyDir(cliTitan, projectTitan);
242
- console.log(green("✔ titan/ runtime updated"));
243
-
244
- //
245
- // 3. Update server/Cargo.toml
246
- //
247
- const srcToml = path.join(cliTemplatesRoot, "server", "Cargo.toml");
248
- const destToml = path.join(projectRoot, "server", "Cargo.toml");
249
- if (fs.existsSync(srcToml)) {
250
- fs.copyFileSync(srcToml, destToml);
251
- console.log(green("✔ Updated server/Cargo.toml"));
252
- }
253
-
254
- //
255
- // 4. Update ONLY server/src/main.rs
256
- //
257
- const srcMain = path.join(cliTemplatesRoot, "server", "src", "main.rs");
258
- const destMain = path.join(projectRoot, "server", "src", "main.rs");
259
- if (fs.existsSync(srcMain)) {
260
- fs.copyFileSync(srcMain, destMain);
261
- console.log(green("✔ Updated server/src/main.rs"));
262
- }
263
-
264
- //
265
- // 5. Update root-level config files
266
- //
267
- [".gitignore", ".dockerignore", "Dockerfile"].forEach((file) => {
268
- const src = path.join(cliTemplatesRoot, file);
269
- const dest = path.join(projectRoot, file);
270
-
271
- if (fs.existsSync(src)) {
272
- fs.copyFileSync(src, dest);
273
- console.log(green(`✔ Updated ${file}`));
274
- }
275
- });
276
253
 
277
- console.log(cyan("✔ Titan forced update complete"));
254
+ console.log(green("✔ Titan runtime updated"));
278
255
  }
279
256
 
280
-
281
-
282
-
283
-
284
-
285
- // ROUTER
257
+ /* ROUTER */
286
258
  switch (cmd) {
287
259
  case "init":
288
260
  initProject(args[1]);
@@ -304,7 +276,12 @@ switch (cmd) {
304
276
  updateTitan();
305
277
  break;
306
278
 
279
+ case "--version":
280
+ case "-v":
281
+ case "version":
282
+ console.log(green(`Titan v${TITAN_VERSION}`));
283
+ break;
284
+
307
285
  default:
308
286
  help();
309
287
  }
310
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ezetgalaxy/titan",
3
- "version": "25.12.7",
3
+ "version": "25.12.9",
4
4
  "description": "JavaScript backend framework that compiles your JS into a Rust + Axum server.",
5
5
  "license": "ISC",
6
6
  "author": "ezetgalaxy",