@titanpl/packet 2.0.4 → 4.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.
Files changed (2) hide show
  1. package/index.js +205 -0
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -32,6 +32,25 @@ function ensureDist(root) {
32
32
  return dist;
33
33
  }
34
34
 
35
+ /**
36
+ * Recursive copy
37
+ */
38
+ function copyDir(src, dest, filter) {
39
+ if (filter && !filter(src)) return;
40
+
41
+ const stats = fs.lstatSync(src);
42
+ if (stats.isDirectory()) {
43
+ if (!fs.existsSync(dest)) {
44
+ fs.mkdirSync(dest, { recursive: true });
45
+ }
46
+ for (const file of fs.readdirSync(src)) {
47
+ copyDir(path.join(src, file), path.join(dest, file), filter);
48
+ }
49
+ } else {
50
+ fs.copyFileSync(src, dest);
51
+ }
52
+ }
53
+
35
54
  /**
36
55
  * Production build
37
56
  */
@@ -51,6 +70,192 @@ export async function build(root = process.cwd()) {
51
70
  return dist;
52
71
  }
53
72
 
73
+ /**
74
+ * Release build (Production ready folder)
75
+ */
76
+ export async function release(root = process.cwd()) {
77
+ const dist = await build(root);
78
+ const buildDir = path.join(root, "build");
79
+
80
+ // Read config
81
+ let config = {};
82
+ const configPath = fs.existsSync(path.join(root, "tanfig.json"))
83
+ ? path.join(root, "tanfig.json")
84
+ : fs.existsSync(path.join(root, "titan.json"))
85
+ ? path.join(root, "titan.json")
86
+ : null;
87
+
88
+ if (configPath) {
89
+ try {
90
+ config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
91
+ } catch (e) { }
92
+ }
93
+
94
+ const filesToCopy = config.build && config.build.files ? config.build.files : ["public", "static", "db", "config"];
95
+
96
+ // Clear or ensure build dir
97
+ if (fs.existsSync(buildDir)) {
98
+ fs.rmSync(buildDir, { recursive: true, force: true });
99
+ }
100
+ fs.mkdirSync(buildDir, { recursive: true });
101
+
102
+ // 1. Copy dist
103
+ copyDir(dist, path.join(buildDir, "dist"));
104
+
105
+ // 2. Extra files/folders from root based on config
106
+ for (const item of filesToCopy) {
107
+ const src = path.join(root, item);
108
+ if (fs.existsSync(src)) {
109
+ const dest = path.join(buildDir, item);
110
+ copyDir(src, dest);
111
+ }
112
+ }
113
+
114
+ // 3. Copy package.json
115
+ const pkgPath = path.join(root, "package.json");
116
+ if (fs.existsSync(pkgPath)) {
117
+ fs.copyFileSync(pkgPath, path.join(buildDir, "package.json"));
118
+ }
119
+
120
+ // 4. Create .env
121
+ fs.writeFileSync(path.join(buildDir, ".env"), "TITAN_DEV=0\n");
122
+
123
+ // 5. Extract extensions
124
+ const extDir = path.join(buildDir, ".ext");
125
+ fs.mkdirSync(extDir, { recursive: true });
126
+
127
+ const nodeModules = path.join(root, "node_modules");
128
+ if (fs.existsSync(nodeModules)) {
129
+ const findExtensions = (dir, depth = 0) => {
130
+ if (depth > 2) return;
131
+ if (!fs.existsSync(dir)) return;
132
+
133
+ const files = fs.readdirSync(dir);
134
+ for (const file of files) {
135
+ const fullPath = path.join(dir, file);
136
+ try {
137
+ const stats = fs.lstatSync(fullPath);
138
+ if (stats.isDirectory()) {
139
+ if (file === "node_modules" && depth > 0) continue;
140
+
141
+ const titanJson = path.join(fullPath, "titan.json");
142
+ if (fs.existsSync(titanJson)) {
143
+ let targetPkgName = file;
144
+ const parentDirName = path.basename(dir);
145
+ if (parentDirName.startsWith("@")) {
146
+ targetPkgName = path.join(parentDirName, file);
147
+ }
148
+
149
+ const destPath = path.join(extDir, targetPkgName);
150
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
151
+
152
+ copyDir(fullPath, destPath, (src) => {
153
+ const rel = path.relative(fullPath, src);
154
+ return !rel.startsWith("node_modules");
155
+ });
156
+ } else {
157
+ findExtensions(fullPath, depth + 1);
158
+ }
159
+ }
160
+ } catch (e) { }
161
+ }
162
+ };
163
+ findExtensions(nodeModules);
164
+ }
165
+
166
+ // 6. Copy Engine binaries
167
+ if (fs.existsSync(path.join(nodeModules, "@titanpl"))) {
168
+ const scopeDir = path.join(nodeModules, "@titanpl");
169
+ const folders = fs.readdirSync(scopeDir);
170
+ for (const folder of folders) {
171
+ if (folder.startsWith("engine-")) {
172
+ const engineDest = path.join(extDir, "@titanpl", folder);
173
+ copyDir(path.join(scopeDir, folder), engineDest);
174
+ }
175
+ }
176
+ }
177
+
178
+ // 7. Create node_modules junction to .ext for engine resolution
179
+ // If env is 'deploy' or 'production', we might want to skip this for a cleaner build
180
+ const buildEnv = config.build && (config.build.env || config.build.purpose) ? (config.build.env || config.build.purpose) : "test";
181
+
182
+ if (buildEnv !== "deploy" && buildEnv !== "production") {
183
+ const nmSymlink = path.join(buildDir, "node_modules");
184
+ if (!fs.existsSync(nmSymlink)) {
185
+ try {
186
+ // Junctions don't require admin on Windows
187
+ fs.symlinkSync(".ext", nmSymlink, "junction");
188
+ } catch (e) {
189
+ try {
190
+ fs.symlinkSync(".ext", nmSymlink, "dir");
191
+ } catch (e2) {
192
+ // Fallback or ignore if symlink creation is totally restricted
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ // 8. Create 'titan' executable link in the build root for easy starting
199
+ const binName = process.platform === "win32" ? "titan-server.exe" : "titan-server";
200
+ let engineBin = null;
201
+
202
+ // Strategy A: Search in the .ext we just populated
203
+ const findInExt = (dir) => {
204
+ if (!fs.existsSync(dir)) return null;
205
+ const entries = fs.readdirSync(dir);
206
+ for (const entry of entries) {
207
+ const full = path.join(dir, entry);
208
+ if (fs.statSync(full).isDirectory()) {
209
+ // Check both pkgRoot/bin/titan-server and pkgRoot/titan-server (some layouts differ)
210
+ const p1 = path.join(full, "bin", binName);
211
+ if (fs.existsSync(p1)) return p1;
212
+ const p2 = path.join(full, binName);
213
+ if (fs.existsSync(p2)) return p2;
214
+
215
+ const found = findInExt(full);
216
+ if (found) return found;
217
+ }
218
+ }
219
+ return null;
220
+ };
221
+
222
+ engineBin = findInExt(extDir);
223
+
224
+ // Strategy B: Monorepo fallback (if building inside the titanpl repo)
225
+ if (!engineBin) {
226
+ let current = root;
227
+ for (let i = 0; i < 5; i++) {
228
+ const potential = path.join(current, "engine", "target", "release", binName);
229
+ if (fs.existsSync(potential)) {
230
+ engineBin = potential;
231
+ break;
232
+ }
233
+ const parent = path.dirname(current);
234
+ if (parent === current) break;
235
+ current = parent;
236
+ }
237
+ }
238
+
239
+ if (engineBin) {
240
+ const linkName = binName; // Keep the original name 'titan-server'
241
+ const linkPath = path.join(buildDir, linkName);
242
+
243
+ if (!fs.existsSync(linkPath)) {
244
+ try {
245
+ // Always copy the binary to the root for maximum portability in the 'build' folder
246
+ fs.copyFileSync(engineBin, linkPath);
247
+ if (process.platform !== "win32") {
248
+ fs.chmodSync(linkPath, 0o755);
249
+ }
250
+ } catch (e) {
251
+ console.error(`[Titan] Failed to create titan binary: ${e.message}`);
252
+ }
253
+ }
254
+ }
255
+
256
+ return buildDir;
257
+ }
258
+
54
259
  /**
55
260
  * Dev mode build
56
261
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@titanpl/packet",
3
- "version": "2.0.4",
3
+ "version": "4.0.1",
4
4
  "description": "The bundler for TitanPl servers.",
5
5
  "keywords": [
6
6
  "bundler",