bs9 1.3.9 â 1.4.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 +8 -7
- package/package.json +1 -1
- package/src/commands/resurrect.ts +12 -14
- package/src/commands/save.ts +10 -12
- package/src/platform/detect.ts +37 -14
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# BS9 (Bun Sentinel 9) đ
|
|
2
2
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
|
-
[](https://github.com/xarhang/bs9)
|
|
5
5
|
[](SECURITY.md)
|
|
6
6
|
[](PRODUCTION.md)
|
|
7
7
|
[](https://github.com/bs9/bs9)
|
|
@@ -26,24 +26,25 @@ chmod +x ~/.local/bin/bs9
|
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
-
### Platform Support
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
### đ Platform Support
|
|
30
|
+
- **â
Auto-Detection**: Automatically detects platform and creates directories
|
|
31
|
+
- **â
Zero Configuration**: No manual setup required
|
|
32
|
+
- **â
Cross-Platform**: Same commands work on all platforms
|
|
32
33
|
|
|
33
34
|
#### đ§ Linux
|
|
34
35
|
- **Service Manager**: Systemd (user-mode)
|
|
35
36
|
- **Features**: Advanced security hardening, resource limits, sandboxing
|
|
36
|
-
- **Commands**: All
|
|
37
|
+
- **Commands**: All 21 commands available
|
|
37
38
|
|
|
38
39
|
#### đ macOS
|
|
39
40
|
- **Service Manager**: Launchd
|
|
40
41
|
- **Features**: Native macOS integration, automatic recovery
|
|
41
|
-
- **Commands**:
|
|
42
|
+
- **Commands**: All commands + `bs9 macos` for launchd management
|
|
42
43
|
|
|
43
44
|
#### đĒ Windows
|
|
44
45
|
- **Service Manager**: Windows Services
|
|
45
46
|
- **Features**: PowerShell automation, event log integration
|
|
46
|
-
- **Commands**:
|
|
47
|
+
- **Commands**: All commands + `bs9 windows` for service management
|
|
47
48
|
|
|
48
49
|
```bash
|
|
49
50
|
# Check your platform
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { execSync } from "node:child_process";
|
|
13
13
|
import { join } from "node:path";
|
|
14
|
-
import { getPlatformInfo } from "../platform/detect.js";
|
|
14
|
+
import { getPlatformInfo, initializePlatformDirectories } from "../platform/detect.js";
|
|
15
15
|
|
|
16
16
|
interface ResurrectOptions {
|
|
17
17
|
all?: boolean;
|
|
@@ -28,6 +28,9 @@ function isValidServiceName(name: string): boolean {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export async function resurrectCommand(name: string, options: ResurrectOptions): Promise<void> {
|
|
31
|
+
// Initialize platform directories
|
|
32
|
+
initializePlatformDirectories();
|
|
33
|
+
|
|
31
34
|
const platformInfo = getPlatformInfo();
|
|
32
35
|
|
|
33
36
|
// Handle resurrect all services
|
|
@@ -48,8 +51,7 @@ export async function resurrectCommand(name: string, options: ResurrectOptions):
|
|
|
48
51
|
const escapedName = name.replace(/[^a-zA-Z0-9._-]/g, '');
|
|
49
52
|
|
|
50
53
|
// Check if service exists in backup
|
|
51
|
-
const
|
|
52
|
-
const backupFile = join(backupDir, `${escapedName}.json`);
|
|
54
|
+
const backupFile = join(platformInfo.backupDir, `${escapedName}.json`);
|
|
53
55
|
|
|
54
56
|
if (!require('node:fs').existsSync(backupFile)) {
|
|
55
57
|
console.error(`â No backup found for service '${name}'`);
|
|
@@ -115,16 +117,12 @@ async function resurrectAllServices(platformInfo: any, options: ResurrectOptions
|
|
|
115
117
|
try {
|
|
116
118
|
console.log("đ Resurrecting all BS9 services from backup...");
|
|
117
119
|
|
|
120
|
+
// Initialize platform directories
|
|
121
|
+
initializePlatformDirectories();
|
|
122
|
+
|
|
118
123
|
if (platformInfo.isLinux) {
|
|
119
|
-
const backupDir = join(platformInfo.configDir, 'backups');
|
|
120
|
-
|
|
121
|
-
if (!require('node:fs').existsSync(backupDir)) {
|
|
122
|
-
console.log("âšī¸ No backup directory found");
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
124
|
// Get all backup files
|
|
127
|
-
const backupFiles = require('node:fs').readdirSync(backupDir)
|
|
125
|
+
const backupFiles = require('node:fs').readdirSync(platformInfo.backupDir)
|
|
128
126
|
.filter((file: string) => file.endsWith('.json'));
|
|
129
127
|
|
|
130
128
|
if (backupFiles.length === 0) {
|
|
@@ -137,7 +135,7 @@ async function resurrectAllServices(platformInfo: any, options: ResurrectOptions
|
|
|
137
135
|
for (const backupFile of backupFiles) {
|
|
138
136
|
try {
|
|
139
137
|
const serviceName = backupFile.replace('.json', '');
|
|
140
|
-
const backupPath = join(backupDir, backupFile);
|
|
138
|
+
const backupPath = join(platformInfo.backupDir, backupFile);
|
|
141
139
|
const backupConfig = JSON.parse(require('node:fs').readFileSync(backupPath, 'utf8'));
|
|
142
140
|
|
|
143
141
|
// Restore service using backup configuration
|
|
@@ -161,11 +159,11 @@ async function resurrectAllServices(platformInfo: any, options: ResurrectOptions
|
|
|
161
159
|
|
|
162
160
|
} else if (platformInfo.isMacOS) {
|
|
163
161
|
console.log("đ To resurrect all services on macOS, you need to manually restore the plist files from:");
|
|
164
|
-
console.log(` ${
|
|
162
|
+
console.log(` ${platformInfo.backupDir}/*.plist`);
|
|
165
163
|
console.log(" And then run: launchctl load ~/Library/LaunchAgents/bs9.*.plist");
|
|
166
164
|
} else if (platformInfo.isWindows) {
|
|
167
165
|
console.log("đ To resurrect all services on Windows, use PowerShell:");
|
|
168
|
-
console.log(" Get-ChildItem -Path \"${
|
|
166
|
+
console.log(" Get-ChildItem -Path \"${platformInfo.backupDir}\" | ForEach-Object { Restore-Service $_.Name }");
|
|
169
167
|
}
|
|
170
168
|
|
|
171
169
|
console.log(`â
All BS9 services resurrection process completed`);
|
package/src/commands/save.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { execSync } from "node:child_process";
|
|
13
13
|
import { join, resolve } from "node:path";
|
|
14
|
-
import { getPlatformInfo } from "../platform/detect.js";
|
|
14
|
+
import { getPlatformInfo, initializePlatformDirectories } from "../platform/detect.js";
|
|
15
15
|
|
|
16
16
|
interface SaveOptions {
|
|
17
17
|
all?: boolean;
|
|
@@ -28,6 +28,9 @@ function isValidServiceName(name: string): boolean {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export async function saveCommand(name: string, options: SaveOptions): Promise<void> {
|
|
31
|
+
// Initialize platform directories
|
|
32
|
+
initializePlatformDirectories();
|
|
33
|
+
|
|
31
34
|
const platformInfo = getPlatformInfo();
|
|
32
35
|
|
|
33
36
|
// Handle save all services
|
|
@@ -62,12 +65,8 @@ export async function saveCommand(name: string, options: SaveOptions): Promise<v
|
|
|
62
65
|
// Parse service configuration to extract startup parameters
|
|
63
66
|
const config = parseServiceConfig(serviceConfig, statusOutput);
|
|
64
67
|
|
|
65
|
-
// Create backup directory if it doesn't exist
|
|
66
|
-
const backupDir = join(platformInfo.configDir, 'backups');
|
|
67
|
-
require('node:fs').mkdirSync(backupDir, { recursive: true });
|
|
68
|
-
|
|
69
68
|
// Save configuration to backup
|
|
70
|
-
const backupFile = join(backupDir, `${escapedName}.json`);
|
|
69
|
+
const backupFile = join(platformInfo.backupDir, `${escapedName}.json`);
|
|
71
70
|
const backupData = {
|
|
72
71
|
name: name,
|
|
73
72
|
file: extractFileFromConfig(serviceConfig),
|
|
@@ -89,7 +88,7 @@ export async function saveCommand(name: string, options: SaveOptions): Promise<v
|
|
|
89
88
|
if (options.backup) {
|
|
90
89
|
// Create additional backup with timestamp
|
|
91
90
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
92
|
-
const timestampedBackup = join(backupDir, `${escapedName}-${timestamp}.json`);
|
|
91
|
+
const timestampedBackup = join(platformInfo.backupDir, `${escapedName}-${timestamp}.json`);
|
|
93
92
|
require('node:fs').writeFileSync(timestampedBackup, JSON.stringify(backupData, null, 2));
|
|
94
93
|
console.log(`đĻ Additional backup created: ${timestampedBackup}`);
|
|
95
94
|
}
|
|
@@ -118,6 +117,9 @@ async function saveAllServices(platformInfo: any, options: SaveOptions): Promise
|
|
|
118
117
|
try {
|
|
119
118
|
console.log("đž Saving all BS9 service configurations...");
|
|
120
119
|
|
|
120
|
+
// Initialize platform directories
|
|
121
|
+
initializePlatformDirectories();
|
|
122
|
+
|
|
121
123
|
if (platformInfo.isLinux) {
|
|
122
124
|
// Get all BS9 services
|
|
123
125
|
const listOutput = execSync("systemctl --user list-units --type=service --no-pager --no-legend", { encoding: "utf-8" });
|
|
@@ -144,10 +146,6 @@ async function saveAllServices(platformInfo: any, options: SaveOptions): Promise
|
|
|
144
146
|
|
|
145
147
|
console.log(`Found ${bs9Services.length} BS9 services to save...`);
|
|
146
148
|
|
|
147
|
-
// Create backup directory
|
|
148
|
-
const backupDir = join(platformInfo.configDir, 'backups');
|
|
149
|
-
require('node:fs').mkdirSync(backupDir, { recursive: true });
|
|
150
|
-
|
|
151
149
|
for (const serviceName of bs9Services) {
|
|
152
150
|
try {
|
|
153
151
|
const serviceFile = join(platformInfo.serviceDir, `${serviceName}.service`);
|
|
@@ -157,7 +155,7 @@ async function saveAllServices(platformInfo: any, options: SaveOptions): Promise
|
|
|
157
155
|
const statusOutput = execSync(`systemctl --user show "${serviceName}"`, { encoding: "utf-8" });
|
|
158
156
|
const config = parseServiceConfig(serviceConfig, statusOutput);
|
|
159
157
|
|
|
160
|
-
const backupFile = join(backupDir, `${serviceName}.json`);
|
|
158
|
+
const backupFile = join(platformInfo.backupDir, `${serviceName}.json`);
|
|
161
159
|
const backupData = {
|
|
162
160
|
name: serviceName,
|
|
163
161
|
file: extractFileFromConfig(serviceConfig),
|
package/src/platform/detect.ts
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* https://github.com/xarhang/bs9
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { platform } from "node:os";
|
|
12
|
+
import { platform, homedir } from "node:os";
|
|
13
|
+
import { join } from "node:path";
|
|
13
14
|
|
|
14
15
|
export type Platform = 'linux' | 'darwin' | 'win32';
|
|
15
16
|
|
|
@@ -22,10 +23,12 @@ export interface PlatformInfo {
|
|
|
22
23
|
configDir: string;
|
|
23
24
|
logDir: string;
|
|
24
25
|
serviceDir: string;
|
|
26
|
+
backupDir: string;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
export function getPlatformInfo(): PlatformInfo {
|
|
28
30
|
const currentPlatform = platform() as Platform;
|
|
31
|
+
const userHome = homedir();
|
|
29
32
|
|
|
30
33
|
const baseInfo: PlatformInfo = {
|
|
31
34
|
platform: currentPlatform,
|
|
@@ -35,29 +38,33 @@ export function getPlatformInfo(): PlatformInfo {
|
|
|
35
38
|
serviceManager: 'systemd',
|
|
36
39
|
configDir: '',
|
|
37
40
|
logDir: '',
|
|
38
|
-
serviceDir: ''
|
|
41
|
+
serviceDir: '',
|
|
42
|
+
backupDir: ''
|
|
39
43
|
};
|
|
40
44
|
|
|
41
45
|
switch (currentPlatform) {
|
|
42
46
|
case 'linux':
|
|
43
47
|
baseInfo.serviceManager = 'systemd';
|
|
44
|
-
baseInfo.configDir =
|
|
45
|
-
baseInfo.logDir =
|
|
46
|
-
baseInfo.serviceDir =
|
|
48
|
+
baseInfo.configDir = join(userHome, '.config', 'bs9');
|
|
49
|
+
baseInfo.logDir = join(userHome, '.local', 'share', 'bs9', 'logs');
|
|
50
|
+
baseInfo.serviceDir = join(userHome, '.config', 'systemd', 'user');
|
|
51
|
+
baseInfo.backupDir = join(baseInfo.configDir, 'backups');
|
|
47
52
|
break;
|
|
48
53
|
|
|
49
54
|
case 'darwin':
|
|
50
55
|
baseInfo.serviceManager = 'launchd';
|
|
51
|
-
baseInfo.configDir =
|
|
52
|
-
baseInfo.logDir =
|
|
53
|
-
baseInfo.serviceDir =
|
|
56
|
+
baseInfo.configDir = join(userHome, '.bs9');
|
|
57
|
+
baseInfo.logDir = join(userHome, '.bs9', 'logs');
|
|
58
|
+
baseInfo.serviceDir = join(userHome, 'Library', 'LaunchAgents');
|
|
59
|
+
baseInfo.backupDir = join(baseInfo.configDir, 'backups');
|
|
54
60
|
break;
|
|
55
61
|
|
|
56
62
|
case 'win32':
|
|
57
63
|
baseInfo.serviceManager = 'windows-service';
|
|
58
|
-
baseInfo.configDir =
|
|
59
|
-
baseInfo.logDir =
|
|
60
|
-
baseInfo.serviceDir =
|
|
64
|
+
baseInfo.configDir = join(userHome, '.bs9');
|
|
65
|
+
baseInfo.logDir = join(userHome, '.bs9', 'logs');
|
|
66
|
+
baseInfo.serviceDir = join(userHome, '.bs9', 'services');
|
|
67
|
+
baseInfo.backupDir = join(baseInfo.configDir, 'backups');
|
|
61
68
|
break;
|
|
62
69
|
|
|
63
70
|
default:
|
|
@@ -77,13 +84,13 @@ export function getPlatformSpecificCommands(): string[] {
|
|
|
77
84
|
|
|
78
85
|
switch (currentPlatform) {
|
|
79
86
|
case 'linux':
|
|
80
|
-
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'loadbalancer', 'dbpool'];
|
|
87
|
+
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'delete', 'save', 'resurrect', 'loadbalancer', 'dbpool'];
|
|
81
88
|
|
|
82
89
|
case 'darwin':
|
|
83
|
-
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'loadbalancer', 'dbpool', 'macos'];
|
|
90
|
+
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'delete', 'save', 'resurrect', 'loadbalancer', 'dbpool', 'macos'];
|
|
84
91
|
|
|
85
92
|
case 'win32':
|
|
86
|
-
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'loadbalancer', 'dbpool', 'windows'];
|
|
93
|
+
return ['start', 'stop', 'restart', 'status', 'logs', 'monit', 'web', 'alert', 'export', 'deps', 'profile', 'delete', 'save', 'resurrect', 'loadbalancer', 'dbpool', 'windows'];
|
|
87
94
|
|
|
88
95
|
default:
|
|
89
96
|
return [];
|
|
@@ -144,3 +151,19 @@ Windows-specific:
|
|
|
144
151
|
return `â Platform ${currentPlatform} is not supported`;
|
|
145
152
|
}
|
|
146
153
|
}
|
|
154
|
+
|
|
155
|
+
// Auto-detect and initialize platform-specific directories
|
|
156
|
+
export function initializePlatformDirectories(): void {
|
|
157
|
+
const platformInfo = getPlatformInfo();
|
|
158
|
+
|
|
159
|
+
// Create directories if they don't exist
|
|
160
|
+
const fs = require('node:fs');
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
fs.mkdirSync(platformInfo.configDir, { recursive: true });
|
|
164
|
+
fs.mkdirSync(platformInfo.logDir, { recursive: true });
|
|
165
|
+
fs.mkdirSync(platformInfo.backupDir, { recursive: true });
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.warn(`â ī¸ Warning: Could not create platform directories: ${error}`);
|
|
168
|
+
}
|
|
169
|
+
}
|