unitup 0.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.
- package/LICENSE +21 -0
- package/README.md +387 -0
- package/bin/unitup.js +4 -0
- package/index.d.ts +378 -0
- package/package.json +28 -0
- package/src/cli.js +351 -0
- package/src/doctor.js +109 -0
- package/src/index.js +70 -0
- package/src/systemd.js +506 -0
- package/src/unit.js +207 -0
- package/src/utils.js +184 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* unitup - Minimal systemd user service wrapper for Node.js scripts
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ChildProcess } from 'node:child_process';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for creating/adding a Node.js systemd user service.
|
|
9
|
+
*/
|
|
10
|
+
export interface CreateServiceOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Name of the service (e.g., 'api' or 'my-app').
|
|
13
|
+
* Safe characters: lowercase letters, numbers, hyphens, underscores.
|
|
14
|
+
*/
|
|
15
|
+
name: string;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Absolute or relative path to the target Node.js script.
|
|
19
|
+
*/
|
|
20
|
+
script: string;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Working directory path for the service execution (defaults to script directory).
|
|
24
|
+
*/
|
|
25
|
+
cwd?: string;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Absolute path to explicit Node.js executable binary (defaults to process.execPath).
|
|
29
|
+
*/
|
|
30
|
+
nodePath?: string;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Key-value map of environment variables to inject into the systemd unit.
|
|
34
|
+
*/
|
|
35
|
+
env?: Record<string, string>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Path to an environment file (adds EnvironmentFile=... directive).
|
|
39
|
+
*/
|
|
40
|
+
envFile?: string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Systemd restart policy directive (e.g., 'on-failure', 'always', 'no', 'on-abnormal').
|
|
44
|
+
* @default 'on-failure'
|
|
45
|
+
*/
|
|
46
|
+
restart?: string;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Positional arguments to pass to the script execution line.
|
|
50
|
+
*/
|
|
51
|
+
args?: string[];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Automatically enables and starts the service immediately upon creation.
|
|
55
|
+
* @default false
|
|
56
|
+
*/
|
|
57
|
+
start?: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Options for retrieving journalctl log output.
|
|
62
|
+
*/
|
|
63
|
+
export interface LogOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Live streaming follow mode (-f).
|
|
66
|
+
* @default false
|
|
67
|
+
*/
|
|
68
|
+
follow?: boolean;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Number of journal log lines to return (-n).
|
|
72
|
+
* @default 100
|
|
73
|
+
*/
|
|
74
|
+
lines?: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Parsed compact service status summary.
|
|
79
|
+
*/
|
|
80
|
+
export interface ServiceStatus {
|
|
81
|
+
/**
|
|
82
|
+
* Clean service name (e.g. 'api').
|
|
83
|
+
*/
|
|
84
|
+
name: string;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Full systemd unit filename (e.g. 'unitup-api.service').
|
|
88
|
+
*/
|
|
89
|
+
unitFile: string;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Status overview ('running', 'stopped', 'failed', 'exited', etc.).
|
|
93
|
+
*/
|
|
94
|
+
status: string;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Raw ActiveState string from systemctl show.
|
|
98
|
+
*/
|
|
99
|
+
activeState: string;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Raw SubState string from systemctl show.
|
|
103
|
+
*/
|
|
104
|
+
subState: string;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Main Process ID (PID) of the service, or '-' if stopped.
|
|
108
|
+
*/
|
|
109
|
+
pid: string;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Total number of restarts recorded by systemd.
|
|
113
|
+
*/
|
|
114
|
+
restarts: string;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Relative formatted uptime/started string (e.g. '12 minutes ago').
|
|
118
|
+
*/
|
|
119
|
+
started: string;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Raw timestamp from systemctl show.
|
|
123
|
+
*/
|
|
124
|
+
startedRaw?: string;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Path to target script parsed from unit file.
|
|
128
|
+
*/
|
|
129
|
+
script: string;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Working directory parsed from unit file.
|
|
133
|
+
*/
|
|
134
|
+
cwd: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Service item in list overview.
|
|
139
|
+
*/
|
|
140
|
+
export interface ListServiceItem {
|
|
141
|
+
/**
|
|
142
|
+
* Service name.
|
|
143
|
+
*/
|
|
144
|
+
name: string;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Status overview ('running', 'stopped', 'failed', etc.).
|
|
148
|
+
*/
|
|
149
|
+
status: string;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Enabled status ('yes' or 'no').
|
|
153
|
+
*/
|
|
154
|
+
enabled: string;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Diagnostic results for Node.js runtime environment.
|
|
159
|
+
*/
|
|
160
|
+
export interface NodeDiagnostics {
|
|
161
|
+
/**
|
|
162
|
+
* True if Node.js binary was found.
|
|
163
|
+
*/
|
|
164
|
+
found: boolean;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* True if Node.js binary is executable and runs -v.
|
|
168
|
+
*/
|
|
169
|
+
executable: boolean;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Resolved Node.js executable path.
|
|
173
|
+
*/
|
|
174
|
+
execPath: string;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Path returned by which/where node.
|
|
178
|
+
*/
|
|
179
|
+
whichPath: string;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Node.js version string (e.g. 'v20.11.0').
|
|
183
|
+
*/
|
|
184
|
+
version: string;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* True if node binary is in system PATH environment.
|
|
188
|
+
*/
|
|
189
|
+
inPath: boolean;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Diagnostic error message if check failed.
|
|
193
|
+
*/
|
|
194
|
+
error: string | null;
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Troubleshooting solution recommendation.
|
|
198
|
+
*/
|
|
199
|
+
solution: string | null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Diagnostic report object from unitup doctor.
|
|
204
|
+
*/
|
|
205
|
+
export interface DoctorInfo {
|
|
206
|
+
/**
|
|
207
|
+
* True if OS is Linux.
|
|
208
|
+
*/
|
|
209
|
+
linux: boolean;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* True if systemctl binary is found in PATH.
|
|
213
|
+
*/
|
|
214
|
+
systemctl: boolean;
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* True if systemd is running as PID 1.
|
|
218
|
+
*/
|
|
219
|
+
systemdRunning: boolean;
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* True if systemd user session bus is accessible.
|
|
223
|
+
*/
|
|
224
|
+
userSystemdAvailable: boolean;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Node.js runtime diagnostics.
|
|
228
|
+
*/
|
|
229
|
+
nodeDiag: NodeDiagnostics;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Resolved Node.js executable path.
|
|
233
|
+
*/
|
|
234
|
+
nodePath: string;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Node.js version string.
|
|
238
|
+
*/
|
|
239
|
+
nodeVersion: string;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Systemd user unit directory path.
|
|
243
|
+
*/
|
|
244
|
+
unitDir: string;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* True if unit directory is writable.
|
|
248
|
+
*/
|
|
249
|
+
unitDirWritable: boolean;
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* True if user lingering is enabled (loginctl enable-linger).
|
|
253
|
+
*/
|
|
254
|
+
lingering: boolean;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Current OS username.
|
|
258
|
+
*/
|
|
259
|
+
username: string;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Result returned when creating/adding a new unitup service.
|
|
264
|
+
*/
|
|
265
|
+
export interface AddServiceResult {
|
|
266
|
+
/**
|
|
267
|
+
* Cleaned service name.
|
|
268
|
+
*/
|
|
269
|
+
name: string;
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Path to created unit file.
|
|
273
|
+
*/
|
|
274
|
+
unitPath: string;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Parsed systemd unit file content metadata.
|
|
279
|
+
*/
|
|
280
|
+
export interface ParsedUnitContent {
|
|
281
|
+
script?: string;
|
|
282
|
+
cwd?: string;
|
|
283
|
+
restart?: string;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Command runner function definition used for internal mocking.
|
|
288
|
+
*/
|
|
289
|
+
export type CommandRunnerFn = (
|
|
290
|
+
cmd: string,
|
|
291
|
+
args: string[],
|
|
292
|
+
opts?: Record<string, unknown>
|
|
293
|
+
) => Promise<{ stdout: string; stderr: string; code: number }>;
|
|
294
|
+
|
|
295
|
+
// ---------------------------------------------------------------------------
|
|
296
|
+
// Programmatic API Function Declarations
|
|
297
|
+
// ---------------------------------------------------------------------------
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Creates and writes a systemd user service unit file, then reloads the systemd daemon.
|
|
301
|
+
*/
|
|
302
|
+
export function createService(options: CreateServiceOptions): Promise<AddServiceResult>;
|
|
303
|
+
export function addService(options: CreateServiceOptions): Promise<AddServiceResult>;
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Starts a systemd user service unit.
|
|
307
|
+
* @param name Service name (e.g. 'api')
|
|
308
|
+
* @param enable If true, enables the service on boot (--enable)
|
|
309
|
+
*/
|
|
310
|
+
export function startService(name: string, enable?: boolean): Promise<boolean>;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Stops a running systemd user service unit.
|
|
314
|
+
*/
|
|
315
|
+
export function stopService(name: string): Promise<boolean>;
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Restarts a systemd user service unit.
|
|
319
|
+
*/
|
|
320
|
+
export function restartService(name: string): Promise<boolean>;
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Stops, disables, and deletes a systemd user service unit file, then reloads daemon.
|
|
324
|
+
*/
|
|
325
|
+
export function removeService(name: string): Promise<boolean>;
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Retrieves compact parsed status information for a service.
|
|
329
|
+
*/
|
|
330
|
+
export function getServiceStatus(name: string): Promise<ServiceStatus>;
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Retrieves raw string output of systemctl --user status.
|
|
334
|
+
*/
|
|
335
|
+
export function getServiceStatusRaw(name: string): Promise<string>;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Lists all unitup-*.service user units.
|
|
339
|
+
*/
|
|
340
|
+
export function listServices(): Promise<ListServiceItem[]>;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Fetches or streams journalctl logs for a service.
|
|
344
|
+
*/
|
|
345
|
+
export function getServiceLogs(name: string, options?: LogOptions): Promise<string | ChildProcess>;
|
|
346
|
+
|
|
347
|
+
// ---------------------------------------------------------------------------
|
|
348
|
+
// System Diagnostics & Doctor
|
|
349
|
+
// ---------------------------------------------------------------------------
|
|
350
|
+
|
|
351
|
+
export function isSystemdAvailable(): Promise<boolean>;
|
|
352
|
+
export function isSystemctlAvailable(): Promise<boolean>;
|
|
353
|
+
export function isLinux(): boolean;
|
|
354
|
+
export function isSystemdPID1(): Promise<boolean>;
|
|
355
|
+
export function isUserSystemdAvailable(): Promise<boolean>;
|
|
356
|
+
export function checkUserLinger(): Promise<boolean>;
|
|
357
|
+
export function checkNodeDiagnostics(customNodePath?: string): Promise<NodeDiagnostics>;
|
|
358
|
+
export function findNodeExecutable(customPath?: string): Promise<string | null>;
|
|
359
|
+
export function getDoctorInfo(): Promise<DoctorInfo>;
|
|
360
|
+
|
|
361
|
+
// ---------------------------------------------------------------------------
|
|
362
|
+
// Unit File & Path Helpers
|
|
363
|
+
// ---------------------------------------------------------------------------
|
|
364
|
+
|
|
365
|
+
export function getUserUnitDir(): string;
|
|
366
|
+
export function getUnitPath(name: string): string;
|
|
367
|
+
export function unitFileExists(name: string): boolean;
|
|
368
|
+
export function parseUnitContent(content: string): ParsedUnitContent;
|
|
369
|
+
export function sanitizeServiceName(name: string): string;
|
|
370
|
+
export function getUnitFilename(name: string): string;
|
|
371
|
+
export function getServiceNameFromUnit(unitFilename: string): string;
|
|
372
|
+
|
|
373
|
+
// ---------------------------------------------------------------------------
|
|
374
|
+
// Runner Override Helpers for Testing
|
|
375
|
+
// ---------------------------------------------------------------------------
|
|
376
|
+
|
|
377
|
+
export function setCommandRunner(runner: CommandRunnerFn): void;
|
|
378
|
+
export function resetCommandRunner(): void;
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "unitup",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Minimal systemd user service wrapper for Node.js scripts",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "./index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"unitup": "./bin/unitup.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "node --test test/*.test.js"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"systemd",
|
|
16
|
+
"service",
|
|
17
|
+
"user-service",
|
|
18
|
+
"systemctl",
|
|
19
|
+
"node",
|
|
20
|
+
"cli",
|
|
21
|
+
"process-manager"
|
|
22
|
+
],
|
|
23
|
+
"author": "",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20.0.0"
|
|
27
|
+
}
|
|
28
|
+
}
|