bs9 1.5.4 → 1.5.7
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/package.json +1 -1
- package/src/commands/start.ts +79 -9
- package/src/commands/status.ts +1 -1
package/package.json
CHANGED
package/src/commands/start.ts
CHANGED
|
@@ -110,6 +110,22 @@ async function handleMultiServiceStart(file: string, options: StartOptions): Pro
|
|
|
110
110
|
async function handleSingleServiceStart(file: string, options: StartOptions): Promise<void> {
|
|
111
111
|
const platformInfo = getPlatformInfo();
|
|
112
112
|
|
|
113
|
+
// First, try to start existing service without file
|
|
114
|
+
const serviceName = options.name || file;
|
|
115
|
+
|
|
116
|
+
const serviceExists = await checkServiceExists(serviceName, platformInfo);
|
|
117
|
+
|
|
118
|
+
if (serviceExists) {
|
|
119
|
+
console.log(`📋 Service '${serviceName}' already exists, starting...`);
|
|
120
|
+
try {
|
|
121
|
+
await startExistingService(serviceName, platformInfo);
|
|
122
|
+
return;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.log(`⚠️ Failed to start existing service: ${error}`);
|
|
125
|
+
console.log(`📁 Looking for application file: ${file}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
113
129
|
// Security: Validate and sanitize file path
|
|
114
130
|
const fullPath = resolve(file);
|
|
115
131
|
if (!existsSync(fullPath)) {
|
|
@@ -127,7 +143,7 @@ async function handleSingleServiceStart(file: string, options: StartOptions): Pr
|
|
|
127
143
|
|
|
128
144
|
// Security: Validate and sanitize service name
|
|
129
145
|
const rawServiceName = options.name || basename(fullPath, fullPath.endsWith('.ts') ? '.ts' : '.js');
|
|
130
|
-
const
|
|
146
|
+
const finalServiceName = rawServiceName.replace(/[^a-zA-Z0-9-_]/g, "_").replace(/^[^a-zA-Z]/, "_").substring(0, 64);
|
|
131
147
|
|
|
132
148
|
// Security: Validate port number
|
|
133
149
|
const port = options.port || "3000";
|
|
@@ -170,7 +186,7 @@ async function handleSingleServiceStart(file: string, options: StartOptions): Pr
|
|
|
170
186
|
const buildDir = join(dirname(fullPath), ".bs9-build");
|
|
171
187
|
mkdirSync(buildDir, { recursive: true });
|
|
172
188
|
|
|
173
|
-
const outputFile = join(buildDir, `${
|
|
189
|
+
const outputFile = join(buildDir, `${finalServiceName}.js`);
|
|
174
190
|
try {
|
|
175
191
|
execSync(`bun build ${fullPath} --outdir ${buildDir} --target bun --minify --splitting`, { stdio: "inherit" });
|
|
176
192
|
execPath = outputFile;
|
|
@@ -202,17 +218,61 @@ async function handleSingleServiceStart(file: string, options: StartOptions): Pr
|
|
|
202
218
|
|
|
203
219
|
// Platform-specific service creation
|
|
204
220
|
if (platformInfo.isLinux) {
|
|
205
|
-
await createLinuxService(
|
|
221
|
+
await createLinuxService(finalServiceName, execPath, host, port, protocol, options);
|
|
206
222
|
} else if (platformInfo.isMacOS) {
|
|
207
|
-
await createMacOSService(
|
|
223
|
+
await createMacOSService(finalServiceName, execPath, host, port, protocol, options);
|
|
208
224
|
} else if (platformInfo.isWindows) {
|
|
209
|
-
await createWindowsService(
|
|
225
|
+
await createWindowsService(finalServiceName, execPath, host, port, protocol, options);
|
|
210
226
|
} else {
|
|
211
227
|
console.error(`❌ Platform ${platformInfo.platform} is not supported`);
|
|
212
228
|
process.exit(1);
|
|
213
229
|
}
|
|
214
230
|
}
|
|
215
231
|
|
|
232
|
+
async function checkServiceExists(serviceName: string, platformInfo: any): Promise<boolean> {
|
|
233
|
+
try {
|
|
234
|
+
if (platformInfo.isLinux) {
|
|
235
|
+
// Check if service exists in systemctl list-units
|
|
236
|
+
const listOutput = execSync("systemctl --user list-units --type=service --all --no-pager --no-legend", { encoding: "utf-8" });
|
|
237
|
+
const serviceExists = listOutput.includes(`${serviceName}.service`);
|
|
238
|
+
return serviceExists;
|
|
239
|
+
} else if (platformInfo.isMacOS) {
|
|
240
|
+
// Check if launchd service exists
|
|
241
|
+
const servicePath = join(platformInfo.serviceDir, `bs9.${serviceName}.plist`);
|
|
242
|
+
return existsSync(servicePath);
|
|
243
|
+
} else if (platformInfo.isWindows) {
|
|
244
|
+
// Check if Windows service exists
|
|
245
|
+
const { windowsCommand } = await import("../windows/service.js");
|
|
246
|
+
try {
|
|
247
|
+
await windowsCommand('show', { name: `BS9_${serviceName}` });
|
|
248
|
+
return true;
|
|
249
|
+
} catch {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return false;
|
|
254
|
+
} catch {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async function startExistingService(serviceName: string, platformInfo: any): Promise<void> {
|
|
260
|
+
try {
|
|
261
|
+
if (platformInfo.isLinux) {
|
|
262
|
+
execSync(`systemctl --user start ${serviceName}`, { stdio: "inherit" });
|
|
263
|
+
} else if (platformInfo.isMacOS) {
|
|
264
|
+
const { launchdCommand } = await import("../macos/launchd.js");
|
|
265
|
+
await launchdCommand('start', { name: `bs9.${serviceName}` });
|
|
266
|
+
} else if (platformInfo.isWindows) {
|
|
267
|
+
const { windowsCommand } = await import("../windows/service.js");
|
|
268
|
+
await windowsCommand('start', { name: `BS9_${serviceName}` });
|
|
269
|
+
}
|
|
270
|
+
console.log(`🚀 Service '${serviceName}' started successfully`);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
216
276
|
function findServiceFile(serviceName: string): string | null {
|
|
217
277
|
// Try to find the service file in common locations
|
|
218
278
|
const possiblePaths = [
|
|
@@ -281,11 +341,21 @@ async function createLinuxService(serviceName: string, execPath: string, host: s
|
|
|
281
341
|
}
|
|
282
342
|
|
|
283
343
|
try {
|
|
284
|
-
|
|
285
|
-
|
|
344
|
+
// Check if service already exists
|
|
345
|
+
const serviceExists = existsSync(unitPath);
|
|
346
|
+
|
|
347
|
+
if (!serviceExists) {
|
|
348
|
+
// First time: Create service file
|
|
349
|
+
writeFileSync(unitPath, unitContent);
|
|
350
|
+
console.log(`✅ Systemd user unit written to: ${unitPath}`);
|
|
351
|
+
execSync("systemctl --user daemon-reload");
|
|
352
|
+
execSync(`systemctl --user enable ${serviceName}`);
|
|
353
|
+
console.log(`🔧 Service '${serviceName}' created and enabled`);
|
|
354
|
+
} else {
|
|
355
|
+
console.log(`📋 Service '${serviceName}' already exists, starting...`);
|
|
356
|
+
}
|
|
286
357
|
|
|
287
|
-
|
|
288
|
-
execSync(`systemctl --user enable ${serviceName}`);
|
|
358
|
+
// Always start the service
|
|
289
359
|
execSync(`systemctl --user start ${serviceName}`);
|
|
290
360
|
|
|
291
361
|
console.log(`🚀 Service '${serviceName}' started successfully`);
|
package/src/commands/status.ts
CHANGED
|
@@ -240,7 +240,7 @@ async function getLinuxServices(): Promise<ServiceStatus[]> {
|
|
|
240
240
|
const platformInfo = getPlatformInfo();
|
|
241
241
|
|
|
242
242
|
try {
|
|
243
|
-
const listOutput = execSync("systemctl --user list-units --type=service --no-pager --no-legend", { encoding: "utf-8" });
|
|
243
|
+
const listOutput = execSync("systemctl --user list-units --type=service --all --no-pager --no-legend", { encoding: "utf-8" });
|
|
244
244
|
const lines = listOutput.split("\n").filter(line => line.includes(".service"));
|
|
245
245
|
|
|
246
246
|
for (const line of lines) {
|