@ebowwa/pkg-ops 0.1.20 → 0.1.22
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 -2
- package/rust/src/lib.rs +3 -1
- package/src/bridge.ts +0 -506
- package/src/config.ts +0 -364
- package/src/health-server.ts +0 -280
- package/src/index.ts +0 -1187
- package/src/service-manager.ts +0 -216
- package/src/types.ts +0 -240
package/src/service-manager.ts
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Service management using @ebowwa/installations.
|
|
3
|
-
*
|
|
4
|
-
* Wraps systemd operations for package operations.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```typescript
|
|
8
|
-
* import { ServiceManager } from "@ebowwa/pkg-ops/service-manager";
|
|
9
|
-
*
|
|
10
|
-
* const manager = new ServiceManager();
|
|
11
|
-
*
|
|
12
|
-
* // Start a service
|
|
13
|
-
* await manager.start("stack");
|
|
14
|
-
*
|
|
15
|
-
* // Check status
|
|
16
|
-
* const status = await manager.status("stack");
|
|
17
|
-
* console.log(status.active ? "Running" : "Stopped");
|
|
18
|
-
*
|
|
19
|
-
* // View logs
|
|
20
|
-
* const logs = await manager.logs("stack", { lines: 50 });
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
import {
|
|
25
|
-
startService,
|
|
26
|
-
stopService,
|
|
27
|
-
restartService,
|
|
28
|
-
getServiceStatus,
|
|
29
|
-
enableService,
|
|
30
|
-
disableService,
|
|
31
|
-
serviceExists,
|
|
32
|
-
getServiceLogs,
|
|
33
|
-
type ServiceStatus,
|
|
34
|
-
} from "@ebowwa/installations/systemd";
|
|
35
|
-
|
|
36
|
-
import type { SudoOptions } from "@ebowwa/installations";
|
|
37
|
-
|
|
38
|
-
// Re-export ServiceStatus for other modules
|
|
39
|
-
export type { ServiceStatus } from "@ebowwa/installations/systemd";
|
|
40
|
-
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
42
|
-
// Types
|
|
43
|
-
// ---------------------------------------------------------------------------
|
|
44
|
-
|
|
45
|
-
export interface ServiceInfo {
|
|
46
|
-
/** Service name (without .service suffix) */
|
|
47
|
-
name: string;
|
|
48
|
-
/** Whether the service exists */
|
|
49
|
-
exists: boolean;
|
|
50
|
-
/** Service status */
|
|
51
|
-
status: ServiceStatus;
|
|
52
|
-
/** Associated package (if known) */
|
|
53
|
-
package?: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface ServiceLogsOptions {
|
|
57
|
-
/** Number of lines to show (default: 100) */
|
|
58
|
-
lines?: number;
|
|
59
|
-
/** Show logs since timestamp */
|
|
60
|
-
since?: string;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// ---------------------------------------------------------------------------
|
|
64
|
-
// Service Manager Class
|
|
65
|
-
// ---------------------------------------------------------------------------
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Manages systemd services for packages.
|
|
69
|
-
*/
|
|
70
|
-
export class ServiceManager {
|
|
71
|
-
private sudoOptions: SudoOptions;
|
|
72
|
-
|
|
73
|
-
constructor(sudoOptions?: SudoOptions) {
|
|
74
|
-
this.sudoOptions = sudoOptions ?? { context: { type: "local" } };
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Start a service.
|
|
79
|
-
*/
|
|
80
|
-
async start(name: string): Promise<{ success: boolean; message: string }> {
|
|
81
|
-
const result = await startService(name, this.sudoOptions);
|
|
82
|
-
return {
|
|
83
|
-
success: result.ok,
|
|
84
|
-
message: result.ok ? `Service ${name} started` : result.stderr || result.stdout,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Stop a service.
|
|
90
|
-
*/
|
|
91
|
-
async stop(name: string): Promise<{ success: boolean; message: string }> {
|
|
92
|
-
const result = await stopService(name, this.sudoOptions);
|
|
93
|
-
return {
|
|
94
|
-
success: result.ok,
|
|
95
|
-
message: result.ok ? `Service ${name} stopped` : result.stderr || result.stdout,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Restart a service.
|
|
101
|
-
*/
|
|
102
|
-
async restart(name: string): Promise<{ success: boolean; message: string }> {
|
|
103
|
-
const result = await restartService(name, this.sudoOptions);
|
|
104
|
-
return {
|
|
105
|
-
success: result.ok,
|
|
106
|
-
message: result.ok ? `Service ${name} restarted` : result.stderr || result.stdout,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Get service status.
|
|
112
|
-
*/
|
|
113
|
-
async status(name: string): Promise<ServiceStatus> {
|
|
114
|
-
return getServiceStatus(name, this.sudoOptions);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Enable a service to start on boot.
|
|
119
|
-
*/
|
|
120
|
-
async enable(name: string): Promise<{ success: boolean; message: string }> {
|
|
121
|
-
const result = await enableService(name, this.sudoOptions);
|
|
122
|
-
return {
|
|
123
|
-
success: result.ok,
|
|
124
|
-
message: result.ok ? `Service ${name} enabled` : result.stderr || result.stdout,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Disable a service from starting on boot.
|
|
130
|
-
*/
|
|
131
|
-
async disable(name: string): Promise<{ success: boolean; message: string }> {
|
|
132
|
-
const result = await disableService(name, this.sudoOptions);
|
|
133
|
-
return {
|
|
134
|
-
success: result.ok,
|
|
135
|
-
message: result.ok ? `Service ${name} disabled` : result.stderr || result.stdout,
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Check if a service exists.
|
|
141
|
-
*/
|
|
142
|
-
async exists(name: string): Promise<boolean> {
|
|
143
|
-
return serviceExists(name, this.sudoOptions);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Get service logs.
|
|
148
|
-
*/
|
|
149
|
-
async logs(name: string, options?: ServiceLogsOptions): Promise<string> {
|
|
150
|
-
return getServiceLogs(name, {
|
|
151
|
-
...this.sudoOptions,
|
|
152
|
-
lines: options?.lines ?? 100,
|
|
153
|
-
since: options?.since,
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Get comprehensive service info.
|
|
159
|
-
*/
|
|
160
|
-
async info(name: string): Promise<ServiceInfo> {
|
|
161
|
-
const [existsResult, statusResult] = await Promise.all([
|
|
162
|
-
this.exists(name),
|
|
163
|
-
this.status(name),
|
|
164
|
-
]);
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
name,
|
|
168
|
-
exists: existsResult,
|
|
169
|
-
status: statusResult,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Check if a service is healthy (running and active).
|
|
175
|
-
*/
|
|
176
|
-
async isHealthy(name: string): Promise<boolean> {
|
|
177
|
-
const status = await this.status(name);
|
|
178
|
-
return status.active && status.subState === "running";
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Wait for a service to become healthy.
|
|
183
|
-
*/
|
|
184
|
-
async waitForHealthy(
|
|
185
|
-
name: string,
|
|
186
|
-
options?: { timeout?: number; interval?: number }
|
|
187
|
-
): Promise<boolean> {
|
|
188
|
-
const timeout = options?.timeout ?? 30000;
|
|
189
|
-
const interval = options?.interval ?? 1000;
|
|
190
|
-
const start = Date.now();
|
|
191
|
-
|
|
192
|
-
while (Date.now() - start < timeout) {
|
|
193
|
-
const healthy = await this.isHealthy(name);
|
|
194
|
-
if (healthy) return true;
|
|
195
|
-
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// ---------------------------------------------------------------------------
|
|
203
|
-
// Singleton Instance
|
|
204
|
-
// ---------------------------------------------------------------------------
|
|
205
|
-
|
|
206
|
-
let defaultManager: ServiceManager | null = null;
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Get the default service manager instance.
|
|
210
|
-
*/
|
|
211
|
-
export function getServiceManager(): ServiceManager {
|
|
212
|
-
if (!defaultManager) {
|
|
213
|
-
defaultManager = new ServiceManager();
|
|
214
|
-
}
|
|
215
|
-
return defaultManager;
|
|
216
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type definitions for PkgOps multi-version support.
|
|
3
|
-
*
|
|
4
|
-
* @module @ebowwa/pkg-ops/types
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// ---------------------------------------------------------------------------
|
|
8
|
-
// Package Version Types
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Metadata for an installed package version.
|
|
13
|
-
*/
|
|
14
|
-
export interface VersionInfo {
|
|
15
|
-
/** Semver version string */
|
|
16
|
-
version: string;
|
|
17
|
-
/** ISO timestamp when this version was installed */
|
|
18
|
-
installedAt: string;
|
|
19
|
-
/** Size of the dist directory in bytes */
|
|
20
|
-
distSizeBytes: number | null;
|
|
21
|
-
/** Number of files in the dist directory */
|
|
22
|
-
fileCount: number | null;
|
|
23
|
-
/** Whether this is the currently active version */
|
|
24
|
-
active: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Configuration for a managed package with multi-version support.
|
|
29
|
-
*/
|
|
30
|
-
export interface PackageConfig {
|
|
31
|
-
/** Currently active version */
|
|
32
|
-
version: string;
|
|
33
|
-
/** All installed versions with metadata */
|
|
34
|
-
versions: Record<string, VersionMetadata>;
|
|
35
|
-
/** Associated systemd service name (without .service suffix) */
|
|
36
|
-
service?: string;
|
|
37
|
-
/** Whether to auto-start the service after install */
|
|
38
|
-
autoStart?: boolean;
|
|
39
|
-
/** Custom environment variables for the service */
|
|
40
|
-
environment?: Record<string, string>;
|
|
41
|
-
/** Maximum number of versions to keep (default: 3) */
|
|
42
|
-
maxVersions?: number;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Metadata stored for each installed version.
|
|
47
|
-
*/
|
|
48
|
-
export interface VersionMetadata {
|
|
49
|
-
/** ISO timestamp when this version was installed */
|
|
50
|
-
installedAt: string;
|
|
51
|
-
/** Size of the dist directory in bytes */
|
|
52
|
-
distSizeBytes: number | null;
|
|
53
|
-
/** Number of files in the dist directory */
|
|
54
|
-
fileCount: number | null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// ---------------------------------------------------------------------------
|
|
58
|
-
// Result Types
|
|
59
|
-
// ---------------------------------------------------------------------------
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Result of listing versions for a package.
|
|
63
|
-
*/
|
|
64
|
-
export interface VersionsListResult {
|
|
65
|
-
packageName: string;
|
|
66
|
-
versions: VersionInfo[];
|
|
67
|
-
activeVersion: string;
|
|
68
|
-
maxVersions: number;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Result of switching to a different version.
|
|
73
|
-
*/
|
|
74
|
-
export interface SwitchVersionResult {
|
|
75
|
-
success: boolean;
|
|
76
|
-
packageName: string;
|
|
77
|
-
previousVersion: string;
|
|
78
|
-
newVersion: string;
|
|
79
|
-
serviceRestarted: boolean;
|
|
80
|
-
message: string;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Result of pruning old versions.
|
|
85
|
-
*/
|
|
86
|
-
export interface PruneResult {
|
|
87
|
-
success: boolean;
|
|
88
|
-
packageName: string;
|
|
89
|
-
removedVersions: string[];
|
|
90
|
-
keptVersions: string[];
|
|
91
|
-
freedBytes: number;
|
|
92
|
-
message: string;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Result of installing a package (updated for multi-version).
|
|
97
|
-
*/
|
|
98
|
-
export interface InstallResult {
|
|
99
|
-
success: boolean;
|
|
100
|
-
version: string;
|
|
101
|
-
previousVersion?: string;
|
|
102
|
-
/** Whether this was a new version install or reinstall */
|
|
103
|
-
isNew: boolean;
|
|
104
|
-
/** Total versions now installed */
|
|
105
|
-
totalVersions: number;
|
|
106
|
-
message: string;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Result of rolling back a package.
|
|
111
|
-
*/
|
|
112
|
-
export interface RollbackResult {
|
|
113
|
-
success: boolean;
|
|
114
|
-
previousVersion: string;
|
|
115
|
-
currentVersion: string;
|
|
116
|
-
/** Available versions to rollback to */
|
|
117
|
-
availableVersions: string[];
|
|
118
|
-
message: string;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Package info with version details.
|
|
123
|
-
*/
|
|
124
|
-
export interface PackageInfo {
|
|
125
|
-
name: string;
|
|
126
|
-
version: string;
|
|
127
|
-
installed: boolean;
|
|
128
|
-
service?: string;
|
|
129
|
-
/** Total installed versions */
|
|
130
|
-
totalVersions?: number;
|
|
131
|
-
/** All installed versions */
|
|
132
|
-
versions?: VersionInfo[];
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// ---------------------------------------------------------------------------
|
|
136
|
-
// Config Types
|
|
137
|
-
// ---------------------------------------------------------------------------
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Main configuration structure.
|
|
141
|
-
*/
|
|
142
|
-
export interface PkgOpsConfig {
|
|
143
|
-
/** Managed packages */
|
|
144
|
-
packages: Record<string, PackageConfig>;
|
|
145
|
-
/** Health check HTTP port (default: 8914) */
|
|
146
|
-
healthPort?: number;
|
|
147
|
-
/** Working directory for installations (default: /root) */
|
|
148
|
-
workDir?: string;
|
|
149
|
-
/** Log level (default: "info") */
|
|
150
|
-
logLevel?: "debug" | "info" | "warn" | "error";
|
|
151
|
-
/** Default max versions to keep per package */
|
|
152
|
-
defaultMaxVersions?: number;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// ---------------------------------------------------------------------------
|
|
156
|
-
// Bridge Types
|
|
157
|
-
// ---------------------------------------------------------------------------
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* JSON-RPC request structure.
|
|
161
|
-
*/
|
|
162
|
-
export interface JsonRpcRequest {
|
|
163
|
-
jsonrpc: "2.0";
|
|
164
|
-
id: string;
|
|
165
|
-
method: string;
|
|
166
|
-
params?: Record<string, unknown>;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* JSON-RPC response structure.
|
|
171
|
-
*/
|
|
172
|
-
export interface JsonRpcResponse {
|
|
173
|
-
jsonrpc: "2.0";
|
|
174
|
-
id: string;
|
|
175
|
-
result?: unknown;
|
|
176
|
-
error?: {
|
|
177
|
-
code: number;
|
|
178
|
-
message: string;
|
|
179
|
-
data?: unknown;
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// ---------------------------------------------------------------------------
|
|
184
|
-
// Audit/Verify Types
|
|
185
|
-
// ---------------------------------------------------------------------------
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Vulnerability audit result.
|
|
189
|
-
*/
|
|
190
|
-
export interface AuditResult {
|
|
191
|
-
packageName: string;
|
|
192
|
-
severity: string;
|
|
193
|
-
vulnerability: string;
|
|
194
|
-
description: string;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Package verification result.
|
|
199
|
-
*/
|
|
200
|
-
export interface VerifyResult {
|
|
201
|
-
packageName: string;
|
|
202
|
-
version: string;
|
|
203
|
-
success: boolean;
|
|
204
|
-
distExists: boolean;
|
|
205
|
-
checksum: string | null;
|
|
206
|
-
message: string;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Bundle size info.
|
|
211
|
-
*/
|
|
212
|
-
export interface BundleSize {
|
|
213
|
-
packageName: string;
|
|
214
|
-
version: string;
|
|
215
|
-
distSizeBytes: number;
|
|
216
|
-
fileCount: number;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Installed package detailed info.
|
|
221
|
-
*/
|
|
222
|
-
export interface InstalledPackageInfo {
|
|
223
|
-
packageName: string;
|
|
224
|
-
version: string;
|
|
225
|
-
distSizeBytes: number | null;
|
|
226
|
-
installedAt: string | null;
|
|
227
|
-
totalVersions?: number;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Health check result.
|
|
232
|
-
*/
|
|
233
|
-
export interface HealthCheckResult {
|
|
234
|
-
healthy: boolean;
|
|
235
|
-
services: Array<{
|
|
236
|
-
name: string;
|
|
237
|
-
status: string;
|
|
238
|
-
pid: number;
|
|
239
|
-
}>;
|
|
240
|
-
}
|