@ezetgalaxy/titan 25.12.8 → 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.
- package/index.js +83 -171
- package/package.json +1 -1
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
|
-
|
|
7
|
+
/* Resolve __dirname for ES modules */
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
9
|
const __dirname = path.dirname(__filename);
|
|
10
10
|
|
|
11
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
52
|
+
${green("tit update")} Update Titan engine
|
|
53
|
+
${green("tit --version")} Show Titan CLI version
|
|
47
54
|
`);
|
|
48
55
|
}
|
|
49
56
|
|
|
50
|
-
|
|
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
|
-
|
|
91
|
-
function runBundler() {
|
|
92
|
-
const bundler = path.join(
|
|
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
|
-
|
|
96
|
-
|
|
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
|
-
|
|
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]
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
185
|
+
const root = process.cwd();
|
|
186
|
+
const appJs = path.join(root, "app", "app.js");
|
|
192
187
|
|
|
193
|
-
|
|
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
|
|
191
|
+
console.log(red("ERROR: app/app.js missing."));
|
|
202
192
|
process.exit(1);
|
|
203
193
|
}
|
|
204
194
|
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
212
|
-
|
|
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
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
-
|
|
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(
|
|
212
|
+
path.join(outDir, file)
|
|
243
213
|
);
|
|
244
214
|
}
|
|
245
215
|
}
|
|
246
216
|
}
|
|
247
217
|
|
|
248
|
-
console.log(green("✔
|
|
218
|
+
console.log(green("✔ Actions copied to server/actions"));
|
|
249
219
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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("✔
|
|
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
|
|
270
|
-
const
|
|
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
|
|
288
|
-
const projectTitan = path.join(
|
|
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("
|
|
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(
|
|
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
|
-
|