titan-sdk 0.0.1
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/bin/run.js +206 -0
- package/index.d.ts +46 -0
- package/index.js +5 -0
- package/package.json +12 -0
package/bin/run.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
// Helper for colors
|
|
11
|
+
const cyan = (t) => `\x1b[36m${t}\x1b[0m`;
|
|
12
|
+
const green = (t) => `\x1b[32m${t}\x1b[0m`;
|
|
13
|
+
const red = (t) => `\x1b[31m${t}\x1b[0m`;
|
|
14
|
+
const yellow = (t) => `\x1b[33m${t}\x1b[0m`;
|
|
15
|
+
|
|
16
|
+
function run() {
|
|
17
|
+
console.log(cyan("Titan SDK: Test Runner"));
|
|
18
|
+
|
|
19
|
+
// 1. Validate we are in an extension directory
|
|
20
|
+
const cwd = process.cwd();
|
|
21
|
+
const manifestPath = path.join(cwd, "titan.json");
|
|
22
|
+
if (!fs.existsSync(manifestPath)) {
|
|
23
|
+
console.log(red("Error: titan.json not found. Run this command inside your extension folder."));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
28
|
+
const name = manifest.name;
|
|
29
|
+
console.log(green(`Extension: ${name}`));
|
|
30
|
+
|
|
31
|
+
// 2. Build Native Logic (if properly set up)
|
|
32
|
+
const nativeDir = path.join(cwd, "native");
|
|
33
|
+
if (fs.existsSync(nativeDir) && fs.existsSync(path.join(nativeDir, "Cargo.toml"))) {
|
|
34
|
+
console.log(cyan("Building native Rust module..."));
|
|
35
|
+
try {
|
|
36
|
+
execSync("cargo build --release", { cwd: nativeDir, stdio: "inherit" });
|
|
37
|
+
} catch (e) {
|
|
38
|
+
console.log(red("Failed to build native module."));
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 3. Create a Test Harness (Mini Titan Project)
|
|
44
|
+
const runDir = path.join(cwd, ".titan_test_run");
|
|
45
|
+
if (fs.existsSync(runDir)) {
|
|
46
|
+
fs.rmSync(runDir, { recursive: true, force: true });
|
|
47
|
+
}
|
|
48
|
+
fs.mkdirSync(runDir);
|
|
49
|
+
|
|
50
|
+
// Create app structure
|
|
51
|
+
const appDir = path.join(runDir, "app");
|
|
52
|
+
fs.mkdirSync(appDir);
|
|
53
|
+
|
|
54
|
+
// Create actions folder (required by Titan build)
|
|
55
|
+
const actionsDir = path.join(appDir, "actions");
|
|
56
|
+
fs.mkdirSync(actionsDir);
|
|
57
|
+
|
|
58
|
+
// Copy titan/ and server/ from templates
|
|
59
|
+
const repoRoot = path.resolve(__dirname, "..", "..");
|
|
60
|
+
const templatesDir = path.join(repoRoot, "templates");
|
|
61
|
+
|
|
62
|
+
const titanSrc = path.join(templatesDir, "titan");
|
|
63
|
+
const titanDest = path.join(runDir, "titan");
|
|
64
|
+
if (fs.existsSync(titanSrc)) {
|
|
65
|
+
fs.cpSync(titanSrc, titanDest, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const serverSrc = path.join(templatesDir, "server");
|
|
69
|
+
const serverDest = path.join(runDir, "server");
|
|
70
|
+
if (fs.existsSync(serverSrc)) {
|
|
71
|
+
fs.cpSync(serverSrc, serverDest, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Create package.json for the test harness
|
|
75
|
+
const pkgJson = {
|
|
76
|
+
"type": "module"
|
|
77
|
+
};
|
|
78
|
+
fs.writeFileSync(path.join(runDir, "package.json"), JSON.stringify(pkgJson, null, 2));
|
|
79
|
+
|
|
80
|
+
// Create 'node_modules' to link the extension
|
|
81
|
+
const nmDir = path.join(runDir, "node_modules");
|
|
82
|
+
fs.mkdirSync(nmDir);
|
|
83
|
+
|
|
84
|
+
// Link current extension to node_modules/NAME
|
|
85
|
+
// Use junction for Windows compat without admin rights
|
|
86
|
+
const extDest = path.join(nmDir, name);
|
|
87
|
+
try {
|
|
88
|
+
fs.symlinkSync(cwd, extDest, "junction");
|
|
89
|
+
} catch (e) {
|
|
90
|
+
// Fallback to copy if link fails
|
|
91
|
+
console.log(yellow("Linking failed, copying extension files..."));
|
|
92
|
+
fs.cpSync(cwd, extDest, { recursive: true });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Create a test action in app/actions/test.js
|
|
96
|
+
const testAction = `export const test = (req) => {
|
|
97
|
+
const ext = t["${name}"];
|
|
98
|
+
|
|
99
|
+
const results = {
|
|
100
|
+
extension: "${name}",
|
|
101
|
+
loaded: !!ext,
|
|
102
|
+
methods: ext ? Object.keys(ext) : [],
|
|
103
|
+
timestamp: new Date().toISOString()
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
if (ext && ext.hello) {
|
|
107
|
+
try {
|
|
108
|
+
results.hello_test = ext.hello("World");
|
|
109
|
+
} catch(e) {
|
|
110
|
+
results.hello_error = String(e);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (ext && ext.calc) {
|
|
115
|
+
try {
|
|
116
|
+
results.calc_test = ext.calc(15, 25);
|
|
117
|
+
} catch(e) {
|
|
118
|
+
results.calc_error = String(e);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return results;
|
|
123
|
+
};
|
|
124
|
+
`;
|
|
125
|
+
|
|
126
|
+
fs.writeFileSync(path.join(actionsDir, "test.js"), testAction);
|
|
127
|
+
|
|
128
|
+
// Create a simple test script in app/app.js
|
|
129
|
+
// This script will be executed by Titan
|
|
130
|
+
const testScript = `import t from "../titan/titan.js";
|
|
131
|
+
|
|
132
|
+
// Extension test harness for: ${name}
|
|
133
|
+
const ext = t["${name}"];
|
|
134
|
+
|
|
135
|
+
console.log("---------------------------------------------------");
|
|
136
|
+
console.log("Testing Extension: ${name}");
|
|
137
|
+
console.log("---------------------------------------------------");
|
|
138
|
+
|
|
139
|
+
if (!ext) {
|
|
140
|
+
console.log("ERROR: Extension '${name}' not found in global 't'.");
|
|
141
|
+
console.log("Make sure your extension's package.json has 'type': 'commonjs'");
|
|
142
|
+
} else {
|
|
143
|
+
console.log("✓ Extension loaded successfully!");
|
|
144
|
+
console.log("✓ Available methods:", Object.keys(ext).join(", "));
|
|
145
|
+
|
|
146
|
+
// Try 'hello' if it exists
|
|
147
|
+
if (typeof ext.hello === 'function') {
|
|
148
|
+
console.log("\\nTesting ext.hello('Titan')...");
|
|
149
|
+
try {
|
|
150
|
+
const res = ext.hello("Titan");
|
|
151
|
+
console.log("✓ Result:", res);
|
|
152
|
+
} catch(e) {
|
|
153
|
+
console.log("✗ Error:", e.message);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Try 'calc' if it exists
|
|
158
|
+
if (typeof ext.calc === 'function') {
|
|
159
|
+
console.log("\\nTesting ext.calc(10, 20)...");
|
|
160
|
+
try {
|
|
161
|
+
const res = ext.calc(10, 20);
|
|
162
|
+
console.log("✓ Result:", res);
|
|
163
|
+
} catch(e) {
|
|
164
|
+
console.log("✗ Error:", e.message);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
console.log("---------------------------------------------------");
|
|
170
|
+
console.log("✓ Test complete!");
|
|
171
|
+
console.log("\\n📍 Routes:");
|
|
172
|
+
console.log(" GET http://localhost:3000/ → Test harness info");
|
|
173
|
+
console.log(" GET http://localhost:3000/test → Extension test results (JSON)");
|
|
174
|
+
console.log("---------------------------------------------------\\n");
|
|
175
|
+
|
|
176
|
+
// Create routes
|
|
177
|
+
t.get("/test").action("test");
|
|
178
|
+
t.get("/").reply("🚀 Extension Test Harness for ${name}\\n\\nVisit /test to see extension test results");
|
|
179
|
+
|
|
180
|
+
t.start(3000, "Titan Extension Test Running!");
|
|
181
|
+
`;
|
|
182
|
+
|
|
183
|
+
fs.writeFileSync(path.join(appDir, "app.js"), testScript);
|
|
184
|
+
|
|
185
|
+
// Build the app (bundle actions)
|
|
186
|
+
console.log(cyan("Building test app..."));
|
|
187
|
+
try {
|
|
188
|
+
execSync("node app/app.js --build", { cwd: runDir, stdio: "inherit" });
|
|
189
|
+
} catch (e) {
|
|
190
|
+
console.log(red("Failed to build test app."));
|
|
191
|
+
console.log(yellow("This is expected if your extension has errors."));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// 4. Run Titan Server using cargo run (like dev mode)
|
|
195
|
+
console.log(cyan("Starting Titan Runtime..."));
|
|
196
|
+
|
|
197
|
+
const serverDir = path.join(runDir, "server");
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
execSync("cargo run", { cwd: serverDir, stdio: "inherit" });
|
|
201
|
+
} catch (e) {
|
|
202
|
+
console.log(red("Runtime exited."));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
run();
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export { };
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
/**
|
|
5
|
+
* Titan Runtime Global Object
|
|
6
|
+
*/
|
|
7
|
+
const t: Titan.Runtime;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export namespace Titan {
|
|
11
|
+
interface Runtime {
|
|
12
|
+
/**
|
|
13
|
+
* Log messages to the Titan console
|
|
14
|
+
*/
|
|
15
|
+
log: LogInterface;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Read file content
|
|
19
|
+
*/
|
|
20
|
+
read(path: string): string;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Fetch API wrapper
|
|
24
|
+
*/
|
|
25
|
+
fetch(url: string, options?: any): Promise<any>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Database operations
|
|
29
|
+
*/
|
|
30
|
+
db: {
|
|
31
|
+
query(sql: string, params?: any[]): Promise<any>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Titan Extensions
|
|
36
|
+
*/
|
|
37
|
+
[key: string]: any;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface LogInterface {
|
|
41
|
+
(...args: any[]): void;
|
|
42
|
+
info(...args: any[]): void;
|
|
43
|
+
warn(...args: any[]): void;
|
|
44
|
+
error(...args: any[]): void;
|
|
45
|
+
}
|
|
46
|
+
}
|
package/index.js
ADDED
package/package.json
ADDED