@ezetgalaxy/titan 26.7.4 → 26.7.5

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
@@ -17,7 +17,8 @@
17
17
  ---
18
18
 
19
19
  # TITAN PLANET 🚀
20
- [![Titan Planet](https://img.shields.io/npm/v/@ezetgalaxy/titan.svg?style=flat-square&logo=data:image/png;base64,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)](https://github.com/ezet-galaxy/titanpl)
20
+
21
+ [![npm version](https://img.shields.io/npm/v/@ezetgalaxy/titan.svg?style=flat-square)](https://www.npmjs.com/package/@ezetgalaxy/titan)
21
22
 
22
23
 
23
24
  **JavaScript Simplicity. Rust Power. Zero Configuration.**
package/index.js CHANGED
@@ -1,490 +1,489 @@
1
1
  #!/usr/bin/env node
2
- import fs from "fs";
3
- import path from "path";
4
- import { execSync, spawn } from "child_process";
5
- import { fileURLToPath } from "url";
6
-
7
- /* Resolve __dirname for ES modules */
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
-
11
- /* -------------------------------------------------------
12
- * Colors
13
- * ----------------------------------------------------- */
14
- const cyan = (t) => `\x1b[36m${t}\x1b[0m`;
15
- const green = (t) => `\x1b[32m${t}\x1b[0m`;
16
- const yellow = (t) => `\x1b[33m${t}\x1b[0m`;
17
- const red = (t) => `\x1b[31m${t}\x1b[0m`;
18
- const bold = (t) => `\x1b[1m${t}\x1b[0m`;
19
-
20
- /* -------------------------------------------------------
21
- * Invocation detection (tit vs titan)
22
- * ----------------------------------------------------- */
23
- function wasInvokedAsTit() {
24
- const script = process.argv[1];
25
- if (script) {
26
- const base = path.basename(script, path.extname(script)).toLowerCase();
27
- if (base === "tit") return true;
28
- }
29
-
30
- try {
31
- const raw = process.env.npm_config_argv;
32
- if (raw) {
33
- const cfg = JSON.parse(raw);
34
- if (cfg.original && Array.isArray(cfg.original)) {
35
- // e.g. ["tit", "dev"]
36
- const first = cfg.original[0];
37
- if (first && first.includes("tit") && !first.includes("titan")) {
38
- return true;
39
- }
40
- }
41
- }
42
- } catch { }
43
-
44
- const lastCmd = process.env["_"];
45
- if (lastCmd) {
46
- const base = path.basename(lastCmd, path.extname(lastCmd)).toLowerCase();
47
- if (base === "tit") return true;
48
- }
49
-
50
- return false;
51
- }
52
-
53
- const isTitAlias = wasInvokedAsTit();
54
-
55
- if (isTitAlias) {
56
- console.log(
57
- yellow(
58
- "[Notice] `tit` is deprecated. Please use `titan` instead.\n" +
59
- " `tit` will continue to work for now."
60
- )
61
- );
62
- }
63
-
64
- /* -------------------------------------------------------
65
- * Args
66
- * ----------------------------------------------------- */
67
- const args = process.argv.slice(2);
68
- const cmd = args[0];
69
-
70
- /* -------------------------------------------------------
71
- * Titan version
72
- * ----------------------------------------------------- */
73
- const pkg = JSON.parse(
74
- fs.readFileSync(path.join(__dirname, "package.json"), "utf8")
75
- );
76
- const TITAN_VERSION = pkg.version;
77
-
78
- /* -------------------------------------------------------
79
- * Utils
80
- * ----------------------------------------------------- */
81
- function copyDir(src, dest, excludes = []) {
82
- fs.mkdirSync(dest, { recursive: true });
83
-
84
- for (const file of fs.readdirSync(src)) {
85
- // Skip excluded files/folders
86
- if (excludes.includes(file)) {
87
- continue;
88
- }
89
-
90
- const srcPath = path.join(src, file);
91
- const destPath = path.join(dest, file);
92
-
93
- if (fs.lstatSync(srcPath).isDirectory()) {
94
- copyDir(srcPath, destPath, excludes);
95
- } else {
96
- fs.copyFileSync(srcPath, destPath);
97
- }
98
- }
99
- }
100
-
101
- /* -------------------------------------------------------
102
- * HELP
103
- * ----------------------------------------------------- */
104
- function help() {
105
- console.log(`
106
- ${bold(cyan("Titan Planet"))} v${TITAN_VERSION}
107
-
108
- ${green("titan init <project>")} Create new Titan project
109
- ${green("titan create ext <name>")} Create new Titan extension
110
- ${green("titan dev")} Dev mode (hot reload)
111
- ${green("titan build")} Build production Rust server
112
- ${green("titan start")} Start production binary
113
- ${green("titan update")} Update Titan engine
114
- ${green("titan --version")} Show Titan CLI version
115
-
116
- ${yellow("Note: `tit` is supported as a legacy alias.")}
117
- `);
118
- }
119
-
120
- /* -------------------------------------------------------
121
- * INIT
122
- * ----------------------------------------------------- */
123
- function initProject(name) {
124
- if (!name) {
125
- console.log(red("Usage: titan init <project>"));
126
- return;
127
- }
128
-
129
- const target = path.join(process.cwd(), name);
130
- const templateDir = path.join(__dirname, "templates");
131
-
132
- if (fs.existsSync(target)) {
133
- console.log(yellow(`Folder already exists: ${target}`));
134
- return;
135
- }
136
-
137
- console.log(cyan(`Creating Titan project → ${target}`));
138
-
139
- // ----------------------------------------------------------
140
- // 1. Copy full template directory (excluding extension folder)
141
- // ----------------------------------------------------------
142
- copyDir(templateDir, target, ["extension"]);
143
-
144
- // ----------------------------------------------------------
145
- // 2. Explicitly install dotfiles
146
- // ----------------------------------------------------------
147
- const dotfiles = {
148
- "_gitignore": ".gitignore",
149
- "_dockerignore": ".dockerignore",
150
- };
151
-
152
- for (const [srcName, destName] of Object.entries(dotfiles)) {
153
- const src = path.join(templateDir, srcName);
154
- const dest = path.join(target, destName);
155
-
156
- if (fs.existsSync(src)) {
157
- fs.copyFileSync(src, dest);
158
- console.log(green(`✔ Added ${destName}`));
159
- }
160
- }
161
-
162
- // Dockerfile is safe as-is
163
- const dockerfileSrc = path.join(templateDir, "Dockerfile");
164
- if (fs.existsSync(dockerfileSrc)) {
165
- fs.copyFileSync(dockerfileSrc, path.join(target, "Dockerfile"));
166
- }
167
-
168
- console.log(green(" Titan project created!"));
169
- console.log(cyan("Installing dependencies..."));
170
-
171
- execSync(`npm install esbuild chokidar --silent`, {
172
- cwd: target,
173
- stdio: "inherit",
174
- });
175
-
176
- console.log(green("✔ Dependencies installed"));
177
- console.log(`
178
- Next steps:
179
- cd ${name}
180
- titan dev
181
- `);
182
- }
183
-
184
- /* -------------------------------------------------------
185
- * DEV SERVER
186
- * ----------------------------------------------------- */
187
- async function devServer() {
188
- const root = process.cwd();
189
- const devScript = path.join(root, "titan", "dev.js");
190
-
191
- if (!fs.existsSync(devScript)) {
192
- console.log(red("Error: titan/dev.js not found."));
193
- console.log("Try running `titan update` to fix missing files.");
194
- return;
195
- }
196
-
197
- const child = spawn("node", [devScript], {
198
- stdio: "inherit",
199
- cwd: root
200
- });
201
-
202
- child.on("close", (code) => {
203
- // Exit strictly if the dev script failed
204
- if (code !== 0) {
205
- process.exit(code);
206
- }
207
- });
208
- }
209
-
210
- /* -------------------------------------------------------
211
- * BUILD
212
- * ----------------------------------------------------- */
213
- function buildProd() {
214
- console.log(cyan("Titan: Building production output..."));
215
-
216
- const root = process.cwd();
217
- const appJs = path.join(root, "app", "app.js");
218
- const serverDir = path.join(root, "server");
219
- const actionsOut = path.join(serverDir, "actions");
220
-
221
- // BASIC CHECKS
222
- if (!fs.existsSync(appJs)) {
223
- console.log(red("ERROR: app/app.js not found."));
224
- process.exit(1);
225
- }
226
-
227
- // ----------------------------------------------------
228
- // 1) BUILD METADATA + BUNDLE ACTIONS (ONE TIME ONLY)
229
- // ----------------------------------------------------
230
- console.log(cyan(" Building Titan metadata + bundling actions..."));
231
- execSync("node app/app.js --build", { stdio: "inherit" });
232
-
233
- // ensure actions directory exists
234
- fs.mkdirSync(actionsOut, { recursive: true });
235
-
236
- // verify bundled actions exist
237
- const bundles = fs.readdirSync(actionsOut).filter(f => f.endsWith(".jsbundle"));
238
- if (bundles.length === 0) {
239
- console.log(red("ERROR: No actions bundled."));
240
- console.log(red("Make sure your DSL outputs to server/actions."));
241
- process.exit(1);
242
- }
243
-
244
- bundles.forEach(file => {
245
- console.log(cyan(`→ Found action bundle: ${file}`));
246
- });
247
-
248
- console.log(green("✔ Actions ready in server/actions"));
249
-
250
- // ----------------------------------------------------
251
- // 2) BUILD RUST BINARY
252
- // ----------------------------------------------------
253
- console.log(cyan(" Building Rust release binary..."));
254
- execSync("cargo build --release", {
255
- cwd: serverDir,
256
- stdio: "inherit"
257
- });
258
-
259
- console.log(green("✔ Titan production build complete!"));
260
- }
261
-
262
- /* -------------------------------------------------------
263
- * START
264
- * ----------------------------------------------------- */
265
- function startProd() {
266
- const isWin = process.platform === "win32";
267
- const bin = isWin ? "titan-server.exe" : "titan-server";
268
-
269
- const exe = path.join(process.cwd(), "server", "target", "release", bin);
270
- execSync(`"${exe}"`, { stdio: "inherit" });
271
- }
272
-
273
- /* -------------------------------------------------------
274
- * UPDATE
275
- * ----------------------------------------------------- */
276
-
277
- function updateTitan() {
278
- const root = process.cwd();
279
-
280
- const projectTitan = path.join(root, "titan");
281
- const projectServer = path.join(root, "server");
282
-
283
- const templatesRoot = path.join(__dirname, "templates");
284
- const templateTitan = path.join(templatesRoot, "titan");
285
- const templateServer = path.join(templatesRoot, "server");
286
-
287
- if (!fs.existsSync(projectTitan)) {
288
- console.log(red("Not a Titan project — titan/ folder missing."));
289
- return;
290
- }
291
-
292
- if (!fs.existsSync(templateServer)) {
293
- console.log(red("CLI is corrupted — server template missing."));
294
- return;
295
- }
296
-
297
- console.log(cyan("Updating Titan runtime and server..."));
298
-
299
- // ----------------------------------------------------------
300
- // 1. Update titan/ runtime (authoritative, safe to replace)
301
- // ----------------------------------------------------------
302
- fs.rmSync(projectTitan, {
303
- recursive: true,
304
- force: true,
305
- maxRetries: 10,
306
- retryDelay: 500,
307
- });
308
-
309
- copyDir(templateTitan, projectTitan);
310
- console.log(green("✔ Updated titan/ runtime"));
311
-
312
- // ----------------------------------------------------------
313
- // 2. Update server/ WITHOUT deleting the folder
314
- // ----------------------------------------------------------
315
- if (!fs.existsSync(projectServer)) {
316
- fs.mkdirSync(projectServer);
317
- }
318
-
319
- // 2a. Overwrite Cargo.toml
320
- const srcCargo = path.join(templateServer, "Cargo.toml");
321
- const destCargo = path.join(projectServer, "Cargo.toml");
322
-
323
- if (fs.existsSync(srcCargo)) {
324
- fs.copyFileSync(srcCargo, destCargo);
325
- console.log(green("✔ Updated server/Cargo.toml"));
326
- }
327
-
328
- // 2b. Replace server/src only
329
- const projectSrc = path.join(projectServer, "src");
330
- const templateSrc = path.join(templateServer, "src");
331
-
332
- if (fs.existsSync(projectSrc)) {
333
- fs.rmSync(projectSrc, {
334
- recursive: true,
335
- force: true,
336
- maxRetries: 10,
337
- retryDelay: 500,
338
- });
339
- }
340
-
341
- copyDir(templateSrc, projectSrc);
342
- console.log(green("✔ Updated server/src/"));
343
-
344
- // Root-level config files
345
- [".gitignore", ".dockerignore", "Dockerfile", "jsconfig.json"].forEach((file) => {
346
- const src = path.join(templatesRoot, file);
347
- const dest = path.join(root, file);
348
-
349
- if (fs.existsSync(src)) {
350
- fs.copyFileSync(src, dest);
351
- console.log(green(`✔ Updated ${file}`));
352
- }
353
- });
354
-
355
- // app/titan.d.ts (JS typing contract)
356
- const appDir = path.join(root, "app");
357
- const srcDts = path.join(templateServer, "../app/titan.d.ts"); // templates/app/titan.d.ts
358
- const destDts = path.join(appDir, "titan.d.ts");
359
-
360
- if (fs.existsSync(srcDts)) {
361
- if (!fs.existsSync(appDir)) {
362
- fs.mkdirSync(appDir);
363
- }
364
-
365
- fs.copyFileSync(srcDts, destDts);
366
- console.log(green("✔ Updated app/titan.d.ts"));
367
- }
368
-
369
-
370
- console.log(bold(green("✔ Titan update complete")));
371
- }
372
-
373
-
374
-
375
- /* -------------------------------------------------------
376
- * CREATE EXTENSION
377
- * ----------------------------------------------------- */
378
- function createExtension(name) {
379
- if (!name) {
380
- console.log(red("Usage: titan create ext <name>"));
381
- return;
382
- }
383
-
384
-
385
- const folderName = name;
386
-
387
- const target = path.join(process.cwd(), folderName);
388
- const templateDir = path.join(__dirname, "templates", "extension");
389
-
390
- if (fs.existsSync(target)) {
391
- console.log(yellow(`Folder already exists: ${target}`));
392
- return;
393
- }
394
-
395
- if (!fs.existsSync(templateDir)) {
396
- console.log(red(`Extension template not found at ${templateDir}`));
397
- return;
398
- }
399
-
400
- console.log(cyan(`Creating Titan extension → ${target}`));
401
-
402
- // 1. Copy template
403
- copyDir(templateDir, target);
404
-
405
- // 2. Process templates (replace {{name}})
406
- const title = name;
407
- const nativeName = title.replace(/-/g, "_");
408
-
409
- const replaceAll = (filePath) => {
410
- if (fs.existsSync(filePath)) {
411
- let content = fs.readFileSync(filePath, "utf8");
412
- content = content.replace(/{{name}}/g, title);
413
- content = content.replace(/{{native_name}}/g, nativeName);
414
- fs.writeFileSync(filePath, content);
415
- }
416
- };
417
-
418
- const idxPath = path.join(target, "index.js");
419
- const readmePath = path.join(target, "README.md");
420
- const pkgPath = path.join(target, "package.json");
421
- const cargoPath = path.join(target, "native", "Cargo.toml");
422
-
423
- replaceAll(path.join(target, "titan.json"));
424
- replaceAll(idxPath);
425
- replaceAll(readmePath);
426
- replaceAll(pkgPath);
427
- replaceAll(cargoPath);
428
-
429
- console.log(cyan("Installing dependencies..."));
430
- try {
431
- execSync("npm install", { cwd: target, stdio: "inherit" });
432
- } catch (e) {
433
- console.log(yellow("Warning: Failed to install dependencies. You may need to run `npm install` manually."));
434
- }
435
-
436
- console.log(green("✔ Extension created!"));
437
- console.log(`
438
- Next steps:
439
- cd ${name}
440
- # If you have native code:
441
- cd native && cargo build --release
442
- # To test your extension
443
- titan run ext
444
- `);
445
- }
446
-
447
- function runExtension() {
448
- const localSdk = path.join(__dirname, "titanpl-sdk", "bin", "run.js");
449
-
450
- if (fs.existsSync(localSdk)) {
451
- console.log(cyan("[Titan] Using local SDK runner..."));
452
- try {
453
- execSync(`node "${localSdk}"`, { stdio: "inherit" });
454
- } catch (e) {
455
- // SDK runner handles its own errors
456
- }
457
- } else {
458
- console.log(cyan("[Titan] SDK not found locally, falling back to npx..."));
459
- try {
460
- execSync("npx -y titan-sdk", { stdio: "inherit" });
461
- } catch (e) {
462
- // SDK runner handles its own errors
463
- }
464
- }
465
- }
466
-
467
- /* -------------------------------------------------------
468
- * ROUTER
469
- * ----------------------------------------------------- */
470
- // "titan create ext <name>" -> args = ["create", "ext", "calc_ext"]
471
- if (cmd === "create" && args[1] === "ext") {
472
- createExtension(args[2]);
473
- } else if (cmd === "run" && args[1] === "ext") {
474
- runExtension();
475
- } else {
476
- switch (cmd) {
477
- case "init": initProject(args[1]); break;
478
- case "dev": devServer(); break;
479
- case "build": buildProd(); break;
480
- case "start": startProd(); break;
481
- case "update": updateTitan(); break;
482
- case "--version":
483
- case "-v":
484
- case "version":
485
- console.log(cyan(`Titan v${TITAN_VERSION}`));
486
- break;
487
- default:
488
- help();
489
- }
490
- }
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { execSync, spawn } from "child_process";
5
+ import { fileURLToPath } from "url";
6
+
7
+ /* Resolve __dirname for ES modules */
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ /* -------------------------------------------------------
12
+ * Colors
13
+ * ----------------------------------------------------- */
14
+ const cyan = (t) => `\x1b[36m${t}\x1b[0m`;
15
+ const green = (t) => `\x1b[32m${t}\x1b[0m`;
16
+ const yellow = (t) => `\x1b[33m${t}\x1b[0m`;
17
+ const red = (t) => `\x1b[31m${t}\x1b[0m`;
18
+ const bold = (t) => `\x1b[1m${t}\x1b[0m`;
19
+
20
+ /* -------------------------------------------------------
21
+ * Invocation detection (tit vs titan)
22
+ * ----------------------------------------------------- */
23
+ function wasInvokedAsTit() {
24
+ const script = process.argv[1];
25
+ if (script) {
26
+ const base = path.basename(script, path.extname(script)).toLowerCase();
27
+ if (base === "tit") return true;
28
+ }
29
+
30
+ try {
31
+ const raw = process.env.npm_config_argv;
32
+ if (raw) {
33
+ const cfg = JSON.parse(raw);
34
+ if (cfg.original && Array.isArray(cfg.original)) {
35
+ // e.g. ["tit", "dev"]
36
+ const first = cfg.original[0];
37
+ if (first && first.includes("tit") && !first.includes("titan")) {
38
+ return true;
39
+ }
40
+ }
41
+ }
42
+ } catch { }
43
+
44
+ const lastCmd = process.env["_"];
45
+ if (lastCmd) {
46
+ const base = path.basename(lastCmd, path.extname(lastCmd)).toLowerCase();
47
+ if (base === "tit") return true;
48
+ }
49
+
50
+ return false;
51
+ }
52
+
53
+ const isTitAlias = wasInvokedAsTit();
54
+
55
+ if (isTitAlias) {
56
+ console.log(
57
+ yellow(
58
+ "[Notice] `tit` is deprecated. Please use `titan` instead.\n" +
59
+ " `tit` will continue to work for now."
60
+ )
61
+ );
62
+ }
63
+
64
+ /* -------------------------------------------------------
65
+ * Args
66
+ * ----------------------------------------------------- */
67
+ const args = process.argv.slice(2);
68
+ const cmd = args[0];
69
+
70
+ /* -------------------------------------------------------
71
+ * Titan version
72
+ * ----------------------------------------------------- */
73
+ const pkg = JSON.parse(
74
+ fs.readFileSync(path.join(__dirname, "package.json"), "utf8")
75
+ );
76
+ const TITAN_VERSION = pkg.version;
77
+
78
+ /* -------------------------------------------------------
79
+ * Utils
80
+ * ----------------------------------------------------- */
81
+ function copyDir(src, dest, excludes = []) {
82
+ fs.mkdirSync(dest, { recursive: true });
83
+
84
+ for (const file of fs.readdirSync(src)) {
85
+ // Skip excluded files/folders
86
+ if (excludes.includes(file)) {
87
+ continue;
88
+ }
89
+
90
+ const srcPath = path.join(src, file);
91
+ const destPath = path.join(dest, file);
92
+
93
+ if (fs.lstatSync(srcPath).isDirectory()) {
94
+ copyDir(srcPath, destPath, excludes);
95
+ } else {
96
+ fs.copyFileSync(srcPath, destPath);
97
+ }
98
+ }
99
+ }
100
+
101
+ /* -------------------------------------------------------
102
+ * HELP
103
+ * ----------------------------------------------------- */
104
+ function help() {
105
+ console.log(`
106
+ ${bold(cyan("Titan Planet"))} v${TITAN_VERSION}
107
+
108
+ ${green("titan init <project>")} Create new Titan project
109
+ ${green("titan create ext <name>")} Create new Titan extension
110
+ ${green("titan dev")} Dev mode (hot reload)
111
+ ${green("titan build")} Build production Rust server
112
+ ${green("titan start")} Start production binary
113
+ ${green("titan update")} Update Titan engine
114
+ ${green("titan --version")} Show Titan CLI version
115
+
116
+ ${yellow("Note: `tit` is supported as a legacy alias.")}
117
+ `);
118
+ }
119
+
120
+ /* -------------------------------------------------------
121
+ * INIT
122
+ * ----------------------------------------------------- */
123
+ function initProject(name) {
124
+ if (!name) {
125
+ console.log(red("Usage: titan init <project>"));
126
+ return;
127
+ }
128
+
129
+ const target = path.join(process.cwd(), name);
130
+ const templateDir = path.join(__dirname, "templates");
131
+
132
+ if (fs.existsSync(target)) {
133
+ console.log(yellow(`Folder already exists: ${target}`));
134
+ return;
135
+ }
136
+
137
+ console.log(cyan(`Creating Titan project → ${target}`));
138
+
139
+ // ----------------------------------------------------------
140
+ // 1. Copy full template directory (excluding extension folder)
141
+ // ----------------------------------------------------------
142
+ copyDir(templateDir, target, ["extension", "_gitignore", "_dockerignore"]);
143
+
144
+ // ----------------------------------------------------------
145
+ // 2. Explicitly install dotfiles
146
+ // ----------------------------------------------------------
147
+ const dotfiles = {
148
+ "_gitignore": ".gitignore",
149
+ "_dockerignore": ".dockerignore",
150
+ };
151
+
152
+ for (const [srcName, destName] of Object.entries(dotfiles)) {
153
+ const src = path.join(templateDir, srcName);
154
+ const dest = path.join(target, destName);
155
+
156
+ if (fs.existsSync(src)) {
157
+ fs.copyFileSync(src, dest);
158
+ }
159
+ }
160
+
161
+ // Dockerfile is safe as-is
162
+ const dockerfileSrc = path.join(templateDir, "Dockerfile");
163
+ if (fs.existsSync(dockerfileSrc)) {
164
+ fs.copyFileSync(dockerfileSrc, path.join(target, "Dockerfile"));
165
+ }
166
+
167
+ console.log(green("✔ Titan project created!"));
168
+ console.log(cyan("Installing dependencies..."));
169
+
170
+ execSync(`npm install esbuild chokidar --silent`, {
171
+ cwd: target,
172
+ stdio: "inherit",
173
+ });
174
+
175
+ console.log(green("✔ Dependencies installed"));
176
+ console.log(`
177
+ Next steps:
178
+ cd ${name}
179
+ titan dev
180
+ `);
181
+ }
182
+
183
+ /* -------------------------------------------------------
184
+ * DEV SERVER
185
+ * ----------------------------------------------------- */
186
+ async function devServer() {
187
+ const root = process.cwd();
188
+ const devScript = path.join(root, "titan", "dev.js");
189
+
190
+ if (!fs.existsSync(devScript)) {
191
+ console.log(red("Error: titan/dev.js not found."));
192
+ console.log("Try running `titan update` to fix missing files.");
193
+ return;
194
+ }
195
+
196
+ const child = spawn("node", [devScript], {
197
+ stdio: "inherit",
198
+ cwd: root
199
+ });
200
+
201
+ child.on("close", (code) => {
202
+ // Exit strictly if the dev script failed
203
+ if (code !== 0) {
204
+ process.exit(code);
205
+ }
206
+ });
207
+ }
208
+
209
+ /* -------------------------------------------------------
210
+ * BUILD
211
+ * ----------------------------------------------------- */
212
+ function buildProd() {
213
+ console.log(cyan("Titan: Building production output..."));
214
+
215
+ const root = process.cwd();
216
+ const appJs = path.join(root, "app", "app.js");
217
+ const serverDir = path.join(root, "server");
218
+ const actionsOut = path.join(serverDir, "actions");
219
+
220
+ // BASIC CHECKS
221
+ if (!fs.existsSync(appJs)) {
222
+ console.log(red("ERROR: app/app.js not found."));
223
+ process.exit(1);
224
+ }
225
+
226
+ // ----------------------------------------------------
227
+ // 1) BUILD METADATA + BUNDLE ACTIONS (ONE TIME ONLY)
228
+ // ----------------------------------------------------
229
+ console.log(cyan("→ Building Titan metadata + bundling actions..."));
230
+ execSync("node app/app.js --build", { stdio: "inherit" });
231
+
232
+ // ensure actions directory exists
233
+ fs.mkdirSync(actionsOut, { recursive: true });
234
+
235
+ // verify bundled actions exist
236
+ const bundles = fs.readdirSync(actionsOut).filter(f => f.endsWith(".jsbundle"));
237
+ if (bundles.length === 0) {
238
+ console.log(red("ERROR: No actions bundled."));
239
+ console.log(red("Make sure your DSL outputs to server/actions."));
240
+ process.exit(1);
241
+ }
242
+
243
+ bundles.forEach(file => {
244
+ console.log(cyan(`→ Found action bundle: ${file}`));
245
+ });
246
+
247
+ console.log(green("✔ Actions ready in server/actions"));
248
+
249
+ // ----------------------------------------------------
250
+ // 2) BUILD RUST BINARY
251
+ // ----------------------------------------------------
252
+ console.log(cyan("→ Building Rust release binary..."));
253
+ execSync("cargo build --release", {
254
+ cwd: serverDir,
255
+ stdio: "inherit"
256
+ });
257
+
258
+ console.log(green("✔ Titan production build complete!"));
259
+ }
260
+
261
+ /* -------------------------------------------------------
262
+ * START
263
+ * ----------------------------------------------------- */
264
+ function startProd() {
265
+ const isWin = process.platform === "win32";
266
+ const bin = isWin ? "titan-server.exe" : "titan-server";
267
+
268
+ const exe = path.join(process.cwd(), "server", "target", "release", bin);
269
+ execSync(`"${exe}"`, { stdio: "inherit" });
270
+ }
271
+
272
+ /* -------------------------------------------------------
273
+ * UPDATE
274
+ * ----------------------------------------------------- */
275
+
276
+ function updateTitan() {
277
+ const root = process.cwd();
278
+
279
+ const projectTitan = path.join(root, "titan");
280
+ const projectServer = path.join(root, "server");
281
+
282
+ const templatesRoot = path.join(__dirname, "templates");
283
+ const templateTitan = path.join(templatesRoot, "titan");
284
+ const templateServer = path.join(templatesRoot, "server");
285
+
286
+ if (!fs.existsSync(projectTitan)) {
287
+ console.log(red("Not a Titan project — titan/ folder missing."));
288
+ return;
289
+ }
290
+
291
+ if (!fs.existsSync(templateServer)) {
292
+ console.log(red("CLI is corrupted — server template missing."));
293
+ return;
294
+ }
295
+
296
+ console.log(cyan("Updating Titan runtime and server..."));
297
+
298
+ // ----------------------------------------------------------
299
+ // 1. Update titan/ runtime (authoritative, safe to replace)
300
+ // ----------------------------------------------------------
301
+ fs.rmSync(projectTitan, {
302
+ recursive: true,
303
+ force: true,
304
+ maxRetries: 10,
305
+ retryDelay: 500,
306
+ });
307
+
308
+ copyDir(templateTitan, projectTitan);
309
+ console.log(green("✔ Updated titan/ runtime"));
310
+
311
+ // ----------------------------------------------------------
312
+ // 2. Update server/ WITHOUT deleting the folder
313
+ // ----------------------------------------------------------
314
+ if (!fs.existsSync(projectServer)) {
315
+ fs.mkdirSync(projectServer);
316
+ }
317
+
318
+ // 2a. Overwrite Cargo.toml
319
+ const srcCargo = path.join(templateServer, "Cargo.toml");
320
+ const destCargo = path.join(projectServer, "Cargo.toml");
321
+
322
+ if (fs.existsSync(srcCargo)) {
323
+ fs.copyFileSync(srcCargo, destCargo);
324
+ console.log(green("✔ Updated server/Cargo.toml"));
325
+ }
326
+
327
+ // 2b. Replace server/src only
328
+ const projectSrc = path.join(projectServer, "src");
329
+ const templateSrc = path.join(templateServer, "src");
330
+
331
+ if (fs.existsSync(projectSrc)) {
332
+ fs.rmSync(projectSrc, {
333
+ recursive: true,
334
+ force: true,
335
+ maxRetries: 10,
336
+ retryDelay: 500,
337
+ });
338
+ }
339
+
340
+ copyDir(templateSrc, projectSrc);
341
+ console.log(green("✔ Updated server/src/"));
342
+
343
+ // Root-level config files
344
+ [".gitignore", ".dockerignore", "Dockerfile", "jsconfig.json"].forEach((file) => {
345
+ const src = path.join(templatesRoot, file);
346
+ const dest = path.join(root, file);
347
+
348
+ if (fs.existsSync(src)) {
349
+ fs.copyFileSync(src, dest);
350
+ console.log(green(`✔ Updated ${file}`));
351
+ }
352
+ });
353
+
354
+ // app/titan.d.ts (JS typing contract)
355
+ const appDir = path.join(root, "app");
356
+ const srcDts = path.join(templateServer, "../app/titan.d.ts"); // templates/app/titan.d.ts
357
+ const destDts = path.join(appDir, "titan.d.ts");
358
+
359
+ if (fs.existsSync(srcDts)) {
360
+ if (!fs.existsSync(appDir)) {
361
+ fs.mkdirSync(appDir);
362
+ }
363
+
364
+ fs.copyFileSync(srcDts, destDts);
365
+ console.log(green("✔ Updated app/titan.d.ts"));
366
+ }
367
+
368
+
369
+ console.log(bold(green("✔ Titan update complete")));
370
+ }
371
+
372
+
373
+
374
+ /* -------------------------------------------------------
375
+ * CREATE EXTENSION
376
+ * ----------------------------------------------------- */
377
+ function createExtension(name) {
378
+ if (!name) {
379
+ console.log(red("Usage: titan create ext <name>"));
380
+ return;
381
+ }
382
+
383
+
384
+ const folderName = name;
385
+
386
+ const target = path.join(process.cwd(), folderName);
387
+ const templateDir = path.join(__dirname, "templates", "extension");
388
+
389
+ if (fs.existsSync(target)) {
390
+ console.log(yellow(`Folder already exists: ${target}`));
391
+ return;
392
+ }
393
+
394
+ if (!fs.existsSync(templateDir)) {
395
+ console.log(red(`Extension template not found at ${templateDir}`));
396
+ return;
397
+ }
398
+
399
+ console.log(cyan(`Creating Titan extension → ${target}`));
400
+
401
+ // 1. Copy template
402
+ copyDir(templateDir, target);
403
+
404
+ // 2. Process templates (replace {{name}})
405
+ const title = name;
406
+ const nativeName = title.replace(/-/g, "_");
407
+
408
+ const replaceAll = (filePath) => {
409
+ if (fs.existsSync(filePath)) {
410
+ let content = fs.readFileSync(filePath, "utf8");
411
+ content = content.replace(/{{name}}/g, title);
412
+ content = content.replace(/{{native_name}}/g, nativeName);
413
+ fs.writeFileSync(filePath, content);
414
+ }
415
+ };
416
+
417
+ const idxPath = path.join(target, "index.js");
418
+ const readmePath = path.join(target, "README.md");
419
+ const pkgPath = path.join(target, "package.json");
420
+ const cargoPath = path.join(target, "native", "Cargo.toml");
421
+
422
+ replaceAll(path.join(target, "titan.json"));
423
+ replaceAll(idxPath);
424
+ replaceAll(readmePath);
425
+ replaceAll(pkgPath);
426
+ replaceAll(cargoPath);
427
+
428
+ console.log(cyan("Installing dependencies..."));
429
+ try {
430
+ execSync("npm install", { cwd: target, stdio: "inherit" });
431
+ } catch (e) {
432
+ console.log(yellow("Warning: Failed to install dependencies. You may need to run `npm install` manually."));
433
+ }
434
+
435
+ console.log(green("✔ Extension created!"));
436
+ console.log(`
437
+ Next steps:
438
+ cd ${name}
439
+ # If you have native code:
440
+ cd native && cargo build --release
441
+ # To test your extension
442
+ titan run ext
443
+ `);
444
+ }
445
+
446
+ function runExtension() {
447
+ const localSdk = path.join(__dirname, "titanpl-sdk", "bin", "run.js");
448
+
449
+ if (fs.existsSync(localSdk)) {
450
+ console.log(cyan("[Titan] Using local SDK runner..."));
451
+ try {
452
+ execSync(`node "${localSdk}"`, { stdio: "inherit" });
453
+ } catch (e) {
454
+ // SDK runner handles its own errors
455
+ }
456
+ } else {
457
+ console.log(cyan("[Titan] SDK not found locally, falling back to npx..."));
458
+ try {
459
+ execSync("npx -y titan-sdk", { stdio: "inherit" });
460
+ } catch (e) {
461
+ // SDK runner handles its own errors
462
+ }
463
+ }
464
+ }
465
+
466
+ /* -------------------------------------------------------
467
+ * ROUTER
468
+ * ----------------------------------------------------- */
469
+ // "titan create ext <name>" -> args = ["create", "ext", "calc_ext"]
470
+ if (cmd === "create" && args[1] === "ext") {
471
+ createExtension(args[2]);
472
+ } else if (cmd === "run" && args[1] === "ext") {
473
+ runExtension();
474
+ } else {
475
+ switch (cmd) {
476
+ case "init": initProject(args[1]); break;
477
+ case "dev": devServer(); break;
478
+ case "build": buildProd(); break;
479
+ case "start": startProd(); break;
480
+ case "update": updateTitan(); break;
481
+ case "--version":
482
+ case "-v":
483
+ case "version":
484
+ console.log(cyan(`Titan v${TITAN_VERSION}`));
485
+ break;
486
+ default:
487
+ help();
488
+ }
489
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ezetgalaxy/titan",
3
- "version": "26.7.4",
3
+ "version": "26.7.5",
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",
@@ -12,7 +12,6 @@
12
12
  },
13
13
  "files": [
14
14
  "index.js",
15
- "scripts/",
16
15
  "templates/",
17
16
  "titan",
18
17
  "titanpl-sdk",
@@ -45,7 +44,8 @@
45
44
  ],
46
45
  "scripts": {
47
46
  "build": "echo \"No build step\"",
48
- "test": "echo \"No tests specified\""
47
+ "test": "echo \"No tests specified\"",
48
+ "test_titan_init": "node scripts/test_titan_init.js"
49
49
  },
50
50
  "dependencies": {
51
51
  "chokidar": "^5.0.0",
@@ -0,0 +1,25 @@
1
+ # Node
2
+ node_modules/
3
+ npm-debug.log
4
+ yarn-error.log
5
+
6
+ # Titan build output (auto-generated — DO NOT COMMIT)
7
+ server/routes.json
8
+ server/action_map.json
9
+ server/actions/*.jsbundle
10
+ server/titan/*.jsbundle
11
+
12
+ # Rust build output (auto-generated — DO NOT COMMIT)
13
+ server/target/
14
+ server/target/**
15
+
16
+ # Logs
17
+ *.log
18
+
19
+ # System files
20
+ .DS_Store
21
+ Thumbs.db
22
+
23
+ # Environment files
24
+ .env
25
+ .env.local
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "{{name}}",
2
+ "name": "titanpl",
3
3
  "version": "1.0.0",
4
4
  "description": "A Titan Planet server",
5
5
  "type": "module",
@@ -0,0 +1,3 @@
1
+ {
2
+ "POST:/hello": "hello"
3
+ }
@@ -0,0 +1,45 @@
1
+ const defineAction = (fn) => fn;
2
+ var __titan_exports = (() => {
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // app/actions/hello.js
22
+ var hello_exports = {};
23
+ __export(hello_exports, {
24
+ hello: () => hello
25
+ });
26
+ var hello = (req) => {
27
+ return {
28
+ message: `Hello from Titan ${req.body.name}`
29
+ };
30
+ };
31
+ return __toCommonJS(hello_exports);
32
+ })();
33
+
34
+ (function () {
35
+ const fn =
36
+ __titan_exports["hello"] ||
37
+ __titan_exports.default;
38
+
39
+ if (typeof fn !== "function") {
40
+ throw new Error("[Titan] Action 'hello' not found or not a function");
41
+ }
42
+
43
+ globalThis["hello"] = fn;
44
+ })();
45
+
@@ -0,0 +1,16 @@
1
+ {
2
+ "__config": {
3
+ "port": 3000
4
+ },
5
+ "routes": {
6
+ "POST:/hello": {
7
+ "type": "action",
8
+ "value": "hello"
9
+ },
10
+ "GET:/": {
11
+ "type": "text",
12
+ "value": "Ready to land on Titan Planet 🚀"
13
+ }
14
+ },
15
+ "__dynamic_routes": []
16
+ }
@@ -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",
@@ -1,71 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -e
3
-
4
- echo "Building Titan distribution..."
5
-
6
- # ---------------------------------------------
7
- # Resolve directories
8
- # ---------------------------------------------
9
- ROOT="$(cd "$(dirname "$0")/.." && pwd)"
10
- SERVER_DIR="$ROOT/server"
11
- DIST_DIR="$ROOT/dist"
12
-
13
- # Clean and recreate dist/
14
- rm -rf "$DIST_DIR"
15
- mkdir -p "$DIST_DIR"
16
-
17
- # ---------------------------------------------
18
- # Copy release binary titan-server
19
- # ---------------------------------------------
20
- RELEASE_PATH="$SERVER_DIR/target/release"
21
-
22
- echo "Looking for titan-server binary..."
23
-
24
- if [ -f "$RELEASE_PATH/titan-server" ]; then
25
- echo "✓ Found titan-server"
26
- cp "$RELEASE_PATH/titan-server" "$DIST_DIR/"
27
- else
28
- echo "Binary not found directly, searching..."
29
- BIN=$(ls "$RELEASE_PATH" | grep 'titan-server' || true)
30
-
31
- if [ -n "$BIN" ]; then
32
- echo "✓ Found matching binary: $BIN"
33
- cp "$RELEASE_PATH/$BIN" "$DIST_DIR/titan-server"
34
- else
35
- echo "✗ titan-server binary not found in release folder."
36
- echo "Did you run: cargo build --release ?"
37
- exit 1
38
- fi
39
- fi
40
-
41
- # ---------------------------------------------
42
- # routes.json (JS bundler should generate routes.build.json)
43
- # ---------------------------------------------
44
- if [ -f "$ROOT/routes.build.json" ]; then
45
- echo "✓ Using routes.build.json"
46
- cp "$ROOT/routes.build.json" "$DIST_DIR/routes.json"
47
- else
48
- echo "⚠ No routes.build.json found. Creating empty routes.json"
49
- echo "{}" > "$DIST_DIR/routes.json"
50
- fi
51
-
52
- # ---------------------------------------------
53
- # Copy handlers if they exist
54
- # ---------------------------------------------
55
- mkdir -p "$DIST_DIR/handlers"
56
-
57
- if [ -d "$ROOT/handlers" ]; then
58
- echo "✓ Copying handlers/"
59
- cp -r "$ROOT/handlers/"* "$DIST_DIR/handlers/" 2>/dev/null || true
60
- else
61
- echo "⚠ No handlers/ directory found."
62
- fi
63
-
64
- echo ""
65
- echo "-------------------------------------------"
66
- echo " ✔ Titan dist/ build complete"
67
- echo "-------------------------------------------"
68
- echo "Binary: dist/titan-server"
69
- echo "Routes: dist/routes.json"
70
- echo "Handlers: dist/handlers/"
71
- echo ""