titanpl-sdk 3.0.0 → 6.0.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/README.md +2 -0
- package/package.json +38 -34
- package/templates/app/app.js +1 -4
- package/templates/server/Cargo.toml +2 -0
- package/templates/server/src/extensions/builtin.rs +271 -139
- package/templates/server/src/extensions/external.rs +338 -338
- package/templates/server/src/extensions/mod.rs +6 -6
- package/templates/server/src/extensions/titan_core.js +49 -13
- package/templates/server/src/main.rs +3 -3
- package/templates/titan/bundle.js +259 -264
- package/templates/titan/dev.js +46 -6
- package/templates/titan/error-box.js +277 -268
- package/templates/app/t.native.d.ts +0 -1983
- package/templates/app/t.native.js +0 -39
|
@@ -1,264 +1,259 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bundle.js
|
|
3
|
-
* Handles esbuild bundling with comprehensive error reporting
|
|
4
|
-
* RULE: This file handles ALL esbuild errors and prints error boxes directly
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import esbuild from 'esbuild';
|
|
8
|
-
import path from 'path';
|
|
9
|
-
import fs from 'fs';
|
|
10
|
-
import { fileURLToPath } from 'url';
|
|
11
|
-
import { createRequire } from 'module';
|
|
12
|
-
import { renderErrorBox, parseEsbuildError } from './error-box.js';
|
|
13
|
-
|
|
14
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
-
const __dirname = path.dirname(__filename);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*/
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
// RULE: Throw special error to signal bundle failure
|
|
261
|
-
throw new Error('__TITAN_BUNDLE_FAILED__');
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Bundle.js
|
|
3
|
+
* Handles esbuild bundling with comprehensive error reporting
|
|
4
|
+
* RULE: This file handles ALL esbuild errors and prints error boxes directly
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import esbuild from 'esbuild';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
import { createRequire } from 'module';
|
|
12
|
+
import { renderErrorBox, parseEsbuildError } from './error-box.js';
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = path.dirname(__filename);
|
|
16
|
+
|
|
17
|
+
// Required for resolving node_modules inside ESM
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Titan Node Builtin Rewrite Map
|
|
22
|
+
* Rewrites Node builtins to @titanpl/node shims
|
|
23
|
+
*/
|
|
24
|
+
const NODE_BUILTIN_MAP = {
|
|
25
|
+
"fs": "@titanpl/node/fs",
|
|
26
|
+
"node:fs": "@titanpl/node/fs",
|
|
27
|
+
|
|
28
|
+
"path": "@titanpl/node/path",
|
|
29
|
+
"node:path": "@titanpl/node/path",
|
|
30
|
+
|
|
31
|
+
"os": "@titanpl/node/os",
|
|
32
|
+
"node:os": "@titanpl/node/os",
|
|
33
|
+
|
|
34
|
+
"crypto": "@titanpl/node/crypto",
|
|
35
|
+
"node:crypto": "@titanpl/node/crypto",
|
|
36
|
+
|
|
37
|
+
"process": "@titanpl/node/process",
|
|
38
|
+
|
|
39
|
+
"util": "@titanpl/node/util",
|
|
40
|
+
"node:util": "@titanpl/node/util",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Titan Node Compatibility Plugin
|
|
45
|
+
* Rewrites require/import of Node builtins
|
|
46
|
+
* Returns absolute paths (required by esbuild)
|
|
47
|
+
*/
|
|
48
|
+
const titanNodeCompatPlugin = {
|
|
49
|
+
name: "titan-node-compat",
|
|
50
|
+
setup(build) {
|
|
51
|
+
build.onResolve({ filter: /.*/ }, args => {
|
|
52
|
+
if (NODE_BUILTIN_MAP[args.path]) {
|
|
53
|
+
try {
|
|
54
|
+
const resolved = require.resolve(NODE_BUILTIN_MAP[args.path]);
|
|
55
|
+
return { path: resolved };
|
|
56
|
+
} catch (e) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`[Titan] Failed to resolve Node shim: ${NODE_BUILTIN_MAP[args.path]}`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get Titan version for error branding
|
|
68
|
+
*/
|
|
69
|
+
function getTitanVersion() {
|
|
70
|
+
try {
|
|
71
|
+
const pkgPath = require.resolve("titanpl/package.json");
|
|
72
|
+
return JSON.parse(fs.readFileSync(pkgPath, "utf-8")).version;
|
|
73
|
+
} catch (e) {
|
|
74
|
+
return "0.1.0";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Custom error class for bundle errors
|
|
80
|
+
*/
|
|
81
|
+
export class BundleError extends Error {
|
|
82
|
+
constructor(message, errors = [], warnings = []) {
|
|
83
|
+
super(message);
|
|
84
|
+
this.name = 'BundleError';
|
|
85
|
+
this.errors = errors;
|
|
86
|
+
this.warnings = warnings;
|
|
87
|
+
this.isBundleError = true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Validate entry file exists
|
|
93
|
+
*/
|
|
94
|
+
async function validateEntryPoint(entryPoint) {
|
|
95
|
+
const absPath = path.resolve(entryPoint);
|
|
96
|
+
|
|
97
|
+
if (!fs.existsSync(absPath)) {
|
|
98
|
+
throw new BundleError(
|
|
99
|
+
`Entry point does not exist: ${entryPoint}`,
|
|
100
|
+
[{ text: `Cannot find file: ${absPath}`, location: { file: entryPoint } }]
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
await fs.promises.access(absPath, fs.constants.R_OK);
|
|
106
|
+
} catch {
|
|
107
|
+
throw new BundleError(
|
|
108
|
+
`Entry point is not readable: ${entryPoint}`,
|
|
109
|
+
[{ text: `Cannot read file: ${absPath}`, location: { file: entryPoint } }]
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Bundles a single file
|
|
116
|
+
*/
|
|
117
|
+
export async function bundleFile(options) {
|
|
118
|
+
const {
|
|
119
|
+
entryPoint,
|
|
120
|
+
outfile,
|
|
121
|
+
format = 'iife',
|
|
122
|
+
minify = false,
|
|
123
|
+
sourcemap = false,
|
|
124
|
+
platform = 'neutral',
|
|
125
|
+
globalName = '__titan_exports',
|
|
126
|
+
target = 'es2020',
|
|
127
|
+
banner = {},
|
|
128
|
+
footer = {}
|
|
129
|
+
} = options;
|
|
130
|
+
|
|
131
|
+
await validateEntryPoint(entryPoint);
|
|
132
|
+
|
|
133
|
+
const outDir = path.dirname(outfile);
|
|
134
|
+
await fs.promises.mkdir(outDir, { recursive: true });
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const result = await esbuild.build({
|
|
138
|
+
entryPoints: [entryPoint],
|
|
139
|
+
bundle: true,
|
|
140
|
+
outfile,
|
|
141
|
+
format,
|
|
142
|
+
globalName,
|
|
143
|
+
platform,
|
|
144
|
+
target,
|
|
145
|
+
banner,
|
|
146
|
+
footer,
|
|
147
|
+
minify,
|
|
148
|
+
sourcemap,
|
|
149
|
+
logLevel: 'silent',
|
|
150
|
+
logLimit: 0,
|
|
151
|
+
write: true,
|
|
152
|
+
metafile: false,
|
|
153
|
+
plugins: [titanNodeCompatPlugin],
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
if (result.errors?.length) {
|
|
157
|
+
throw new BundleError(
|
|
158
|
+
`Build failed with ${result.errors.length} error(s)`,
|
|
159
|
+
result.errors,
|
|
160
|
+
result.warnings || []
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
} catch (err) {
|
|
165
|
+
if (err.errors?.length) {
|
|
166
|
+
throw new BundleError(
|
|
167
|
+
`Build failed with ${err.errors.length} error(s)`,
|
|
168
|
+
err.errors,
|
|
169
|
+
err.warnings || []
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
throw new BundleError(
|
|
174
|
+
`Unexpected build error: ${err.message}`,
|
|
175
|
+
[{ text: err.message, location: { file: entryPoint } }]
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Main bundler
|
|
182
|
+
*/
|
|
183
|
+
export async function bundle() {
|
|
184
|
+
const root = process.cwd();
|
|
185
|
+
const actionsDir = path.join(root, 'app', 'actions');
|
|
186
|
+
const bundleDir = path.join(root, 'server', 'src', 'actions');
|
|
187
|
+
|
|
188
|
+
if (fs.existsSync(bundleDir)) {
|
|
189
|
+
fs.rmSync(bundleDir, { recursive: true, force: true });
|
|
190
|
+
}
|
|
191
|
+
await fs.promises.mkdir(bundleDir, { recursive: true });
|
|
192
|
+
|
|
193
|
+
if (!fs.existsSync(actionsDir)) return;
|
|
194
|
+
|
|
195
|
+
const files = fs.readdirSync(actionsDir).filter(f =>
|
|
196
|
+
(f.endsWith('.js') || f.endsWith('.ts')) && !f.endsWith('.d.ts')
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
for (const file of files) {
|
|
200
|
+
const actionName = path.basename(file, path.extname(file));
|
|
201
|
+
const entryPoint = path.join(actionsDir, file);
|
|
202
|
+
const outfile = path.join(bundleDir, actionName + ".jsbundle");
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
await bundleFile({
|
|
206
|
+
entryPoint,
|
|
207
|
+
outfile,
|
|
208
|
+
format: 'iife',
|
|
209
|
+
globalName: '__titan_exports',
|
|
210
|
+
platform: 'node',
|
|
211
|
+
target: 'es2020',
|
|
212
|
+
banner: { js: "var Titan = t;" },
|
|
213
|
+
footer: {
|
|
214
|
+
js: `
|
|
215
|
+
(function () {
|
|
216
|
+
const fn =
|
|
217
|
+
__titan_exports["${actionName}"] ||
|
|
218
|
+
__titan_exports.default;
|
|
219
|
+
|
|
220
|
+
if (typeof fn !== "function") {
|
|
221
|
+
throw new Error("[Titan] Action '${actionName}' not found or not a function");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
globalThis["${actionName}"] = globalThis.defineAction(fn);
|
|
225
|
+
})();
|
|
226
|
+
`
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
} catch (error) {
|
|
231
|
+
|
|
232
|
+
console.error();
|
|
233
|
+
|
|
234
|
+
const titanVersion = getTitanVersion();
|
|
235
|
+
|
|
236
|
+
if (error.isBundleError && error.errors?.length) {
|
|
237
|
+
for (let i = 0; i < error.errors.length; i++) {
|
|
238
|
+
const errorInfo = parseEsbuildError(error.errors[i]);
|
|
239
|
+
if (error.errors.length > 1) {
|
|
240
|
+
errorInfo.title = `Build Error ${i + 1}/${error.errors.length}`;
|
|
241
|
+
}
|
|
242
|
+
errorInfo.titanVersion = titanVersion;
|
|
243
|
+
console.error(renderErrorBox(errorInfo));
|
|
244
|
+
console.error();
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
const errorInfo = {
|
|
248
|
+
title: 'Build Error',
|
|
249
|
+
file: entryPoint,
|
|
250
|
+
message: error.message || 'Unknown error',
|
|
251
|
+
titanVersion
|
|
252
|
+
};
|
|
253
|
+
console.error(renderErrorBox(errorInfo));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
throw new Error('__TITAN_BUNDLE_FAILED__');
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
package/templates/titan/dev.js
CHANGED
|
@@ -25,7 +25,7 @@ const bold = (t) => `\x1b[1m${t}\x1b[0m`;
|
|
|
25
25
|
function getTitanVersion() {
|
|
26
26
|
try {
|
|
27
27
|
const require = createRequire(import.meta.url);
|
|
28
|
-
const pkgPath = require.resolve("
|
|
28
|
+
const pkgPath = require.resolve("titanpl/package.json");
|
|
29
29
|
return JSON.parse(fs.readFileSync(pkgPath, "utf-8")).version;
|
|
30
30
|
} catch (e) {
|
|
31
31
|
try {
|
|
@@ -34,7 +34,7 @@ function getTitanVersion() {
|
|
|
34
34
|
const pkgPath = path.join(cur, "package.json");
|
|
35
35
|
if (fs.existsSync(pkgPath)) {
|
|
36
36
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
37
|
-
if (pkg.name === "
|
|
37
|
+
if (pkg.name === "titanpl") return pkg.version;
|
|
38
38
|
}
|
|
39
39
|
cur = path.join(cur, "..");
|
|
40
40
|
}
|
|
@@ -135,8 +135,8 @@ async function startRustServer(retryCount = 0) {
|
|
|
135
135
|
|
|
136
136
|
serverProcess = spawn("cargo", ["run", "--quiet"], {
|
|
137
137
|
cwd: serverPath,
|
|
138
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
139
|
-
env: { ...process.env, CARGO_INCREMENTAL: "1" }
|
|
138
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
139
|
+
env: { ...process.env, CARGO_INCREMENTAL: "1", TITAN_DEV: "1" }
|
|
140
140
|
});
|
|
141
141
|
|
|
142
142
|
serverProcess.on("error", (err) => {
|
|
@@ -195,17 +195,34 @@ async function startRustServer(retryCount = 0) {
|
|
|
195
195
|
stderrBuffer.includes("AddrInUse");
|
|
196
196
|
|
|
197
197
|
if (isPortError) {
|
|
198
|
+
if (retryCount < 3) {
|
|
199
|
+
// It's likely the previous process hasn't fully released the port
|
|
200
|
+
await delay(1000);
|
|
201
|
+
await startRustServer(retryCount + 1);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
198
205
|
stopSpinner(false, "Orbit stabilization failed");
|
|
206
|
+
|
|
207
|
+
// Try to read intended port
|
|
208
|
+
let port = 3000;
|
|
209
|
+
try {
|
|
210
|
+
const routesConfig = JSON.parse(fs.readFileSync(path.join(process.cwd(), "server", "routes.json"), "utf8"));
|
|
211
|
+
if (routesConfig && routesConfig.__config && routesConfig.__config.port) {
|
|
212
|
+
port = routesConfig.__config.port;
|
|
213
|
+
}
|
|
214
|
+
} catch (e) { }
|
|
215
|
+
|
|
199
216
|
console.log("");
|
|
200
217
|
|
|
201
218
|
console.log(red("⏣ Your application cannot enter this orbit"));
|
|
202
|
-
console.log(red(
|
|
219
|
+
console.log(red(`↳ Another application is already bound to port ${port}.`));
|
|
203
220
|
console.log("");
|
|
204
221
|
|
|
205
222
|
console.log(yellow("Recommended Actions:"));
|
|
206
223
|
console.log(yellow(" 1.") + " Release the occupied orbit (stop the other service).");
|
|
207
224
|
console.log(yellow(" 2.") + " Assign your application to a new orbit in " + cyan("app/app.js"));
|
|
208
|
-
console.log(yellow(" Example: ") + cyan(
|
|
225
|
+
console.log(yellow(" Example: ") + cyan(`t.start(${port + 1}, "Titan Running!")`));
|
|
209
226
|
console.log("");
|
|
210
227
|
|
|
211
228
|
return;
|
|
@@ -230,6 +247,28 @@ async function startRustServer(retryCount = 0) {
|
|
|
230
247
|
});
|
|
231
248
|
}
|
|
232
249
|
|
|
250
|
+
function prepareRuntime() {
|
|
251
|
+
try {
|
|
252
|
+
const nm = path.join(process.cwd(), "node_modules");
|
|
253
|
+
const titanPkg = path.join(nm, "@titanpl");
|
|
254
|
+
const routePkg = path.join(titanPkg, "route");
|
|
255
|
+
|
|
256
|
+
if (!fs.existsSync(nm)) fs.mkdirSync(nm, { recursive: true });
|
|
257
|
+
if (!fs.existsSync(titanPkg)) fs.mkdirSync(titanPkg, { recursive: true });
|
|
258
|
+
|
|
259
|
+
if (!fs.existsSync(routePkg)) {
|
|
260
|
+
fs.mkdirSync(routePkg, { recursive: true });
|
|
261
|
+
fs.writeFileSync(path.join(routePkg, "package.json"), JSON.stringify({
|
|
262
|
+
name: "@titanpl/route",
|
|
263
|
+
main: "../../../titan/titan.js",
|
|
264
|
+
type: "module"
|
|
265
|
+
}, null, 2));
|
|
266
|
+
}
|
|
267
|
+
} catch (e) {
|
|
268
|
+
// Ignore errors
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
233
272
|
/**
|
|
234
273
|
* Rebuild JS runtime
|
|
235
274
|
* RULE: Only show "✖ Runtime preparation failed" on error
|
|
@@ -280,6 +319,7 @@ async function rebuild() {
|
|
|
280
319
|
}
|
|
281
320
|
|
|
282
321
|
async function startDev() {
|
|
322
|
+
prepareRuntime();
|
|
283
323
|
const root = process.cwd();
|
|
284
324
|
const actionsDir = path.join(root, "app", "actions");
|
|
285
325
|
let hasRust = false;
|