@ulyssedu45/service_api 1.0.5 → 1.1.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 +47 -14
- package/package.json +3 -1
- package/src/linux.d.ts +4 -7
- package/src/linux.d.ts.map +1 -1
- package/src/linux.js +180 -81
- package/src/linux.js.map +1 -1
- package/test/service.test.js +186 -159
- package/test/service.test.js.map +1 -1
package/README.md
CHANGED
|
@@ -4,10 +4,10 @@ Cross-platform Node.js library to **check the existence and status of OS service
|
|
|
4
4
|
|
|
5
5
|
**The same code runs unchanged on Windows and Linux** — the library selects the correct OS backend automatically. No `if (platform === 'win32')` guards are needed in your application.
|
|
6
6
|
|
|
7
|
-
| Platform | Backend
|
|
8
|
-
| ----------- |
|
|
9
|
-
| **Windows** | `advapi32.dll` — calls the Windows Service Control Manager (SCM) directly via [koffi](https://koffi.dev/) FFI bindings. No PowerShell, no `sc.exe`.
|
|
10
|
-
| **Linux** |
|
|
7
|
+
| Platform | Backend |
|
|
8
|
+
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
9
|
+
| **Windows** | `advapi32.dll` — calls the Windows Service Control Manager (SCM) directly via [koffi](https://koffi.dev/) FFI bindings. No PowerShell, no `sc.exe`. |
|
|
10
|
+
| **Linux** | Auto-detected native backend — **zero `child_process`**, zero fork. See table below. |
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -49,7 +49,7 @@ console.log(status);
|
|
|
49
49
|
| Platform | Name to use | Examples |
|
|
50
50
|
| -------- | -------------------------------------- | ------------------------------------ |
|
|
51
51
|
| Windows | Short service name | `"wuauserv"`, `"spooler"`, `"W3SVC"` |
|
|
52
|
-
| Linux |
|
|
52
|
+
| Linux | Service unit name (without `.service` for systemd) | `"nginx"`, `"sshd"`, `"cron"` |
|
|
53
53
|
|
|
54
54
|
---
|
|
55
55
|
|
|
@@ -143,18 +143,51 @@ Returns a `ServiceStatus` object:
|
|
|
143
143
|
|
|
144
144
|
### State values
|
|
145
145
|
|
|
146
|
-
| `state` |
|
|
147
|
-
| ------------------ | --------------------- | ------------------------ |
|
|
148
|
-
| `RUNNING` | `active` | `4` (SERVICE_RUNNING) |
|
|
149
|
-
| `STOPPED` | `inactive` / `failed` | `1` (SERVICE_STOPPED) |
|
|
150
|
-
| `START_PENDING` | `activating` | `2` |
|
|
151
|
-
| `STOP_PENDING` | `deactivating` | `3` |
|
|
152
|
-
| `CONTINUE_PENDING` | `reloading` | `5` |
|
|
153
|
-
| `PAUSE_PENDING` | — | `6` |
|
|
154
|
-
| `PAUSED` | — | `7` |
|
|
146
|
+
| `state` | systemd (ActiveState) | OpenRC | Windows (dwCurrentState) |
|
|
147
|
+
| ------------------ | --------------------- | --------------------------- | ------------------------ |
|
|
148
|
+
| `RUNNING` | `active` | started | `4` (SERVICE_RUNNING) |
|
|
149
|
+
| `STOPPED` | `inactive` / `failed` | not started | `1` (SERVICE_STOPPED) |
|
|
150
|
+
| `START_PENDING` | `activating` | starting | `2` |
|
|
151
|
+
| `STOP_PENDING` | `deactivating` | stopping | `3` |
|
|
152
|
+
| `CONTINUE_PENDING` | `reloading` | — | `5` |
|
|
153
|
+
| `PAUSE_PENDING` | — | — | `6` |
|
|
154
|
+
| `PAUSED` | — | — | `7` |
|
|
155
155
|
|
|
156
156
|
---
|
|
157
157
|
|
|
158
|
+
## How it works on Linux
|
|
159
|
+
|
|
160
|
+
The Linux backend is selected automatically at runtime — **no `child_process`, no `systemctl`, no fork** of any kind.
|
|
161
|
+
|
|
162
|
+
| Init system | Distros | Detection | API used |
|
|
163
|
+
| ----------- | ------------------------------------------ | ---------------------------------- | ------------------------------------------ |
|
|
164
|
+
| **systemd** | Ubuntu, Debian, Fedora, RHEL, Arch, SUSE… | `/run/systemd/private` exists | `libsystemd.so.0` via koffi (sd_bus D-Bus) |
|
|
165
|
+
| **OpenRC** | Alpine, Gentoo, Artix… | `/run/openrc/softlevel` exists | `/run/openrc/started/` filesystem reads |
|
|
166
|
+
| **SysV** | legacy Debian, RHEL 6, embedded… | `/etc/init.d/` exists | `/etc/init.d/` + `/proc/<pid>` reads |
|
|
167
|
+
|
|
168
|
+
### systemd backend (koffi + libsystemd)
|
|
169
|
+
|
|
170
|
+
Uses [koffi](https://koffi.dev/) to call `libsystemd.so.0` directly — the same library that `systemctl` uses internally:
|
|
171
|
+
|
|
172
|
+
1. **`sd_bus_open_system`** — opens a connection to the D-Bus system bus.
|
|
173
|
+
2. **`sd_bus_get_property_string`** — reads `LoadState`, `ActiveState`, `SubState`, `MainPID` from the `org.freedesktop.systemd1.Unit` D-Bus interface.
|
|
174
|
+
3. **`sd_bus_unref`** — releases the bus connection.
|
|
175
|
+
|
|
176
|
+
If `libsystemd.so.0` is not available (containers, musl builds without systemd), the backend falls back silently to SysV-style checks via `/proc`.
|
|
177
|
+
|
|
178
|
+
### OpenRC backend (Alpine, Gentoo)
|
|
179
|
+
|
|
180
|
+
Pure filesystem reads — no library, no binary:
|
|
181
|
+
|
|
182
|
+
- **Existence**: `/etc/init.d/<name>` present
|
|
183
|
+
- **State**: `/run/openrc/started/<name>` → `RUNNING` · `/run/openrc/starting/<name>` → `START_PENDING` · `/run/openrc/stopping/<name>` → `STOP_PENDING`
|
|
184
|
+
- **PID**: `/run/<name>.pid` or `/var/run/<name>.pid`
|
|
185
|
+
|
|
186
|
+
### SysV backend (legacy systems)
|
|
187
|
+
|
|
188
|
+
- **Existence**: `/etc/init.d/<name>` present
|
|
189
|
+
- **Running**: PID file read + `/proc/<pid>` existence check
|
|
190
|
+
|
|
158
191
|
## How it works on Windows
|
|
159
192
|
|
|
160
193
|
The library uses [koffi](https://koffi.dev/) to call `advapi32.dll` functions directly from Node.js — no PowerShell, no `sc.exe`, no child processes:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ulyssedu45/service_api",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Cross-platform Node.js library to check Windows/Linux service existence and status via native OS APIs",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
"service",
|
|
14
14
|
"linux",
|
|
15
15
|
"systemd",
|
|
16
|
+
"openrc",
|
|
17
|
+
"sysv",
|
|
16
18
|
"scm",
|
|
17
19
|
"winapi",
|
|
18
20
|
"ffi"
|
package/src/linux.d.ts
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Linux implementation of service_api.
|
|
3
|
-
* Uses systemctl (systemd) to query service status, with a fallback to
|
|
4
|
-
* the legacy SysV `service` command for non-systemd systems.
|
|
5
|
-
*/
|
|
6
1
|
import { ServiceStatus } from './types';
|
|
2
|
+
type InitSystem = 'systemd' | 'openrc' | 'sysv';
|
|
3
|
+
export declare function detectInitSystem(): InitSystem;
|
|
7
4
|
/**
|
|
8
5
|
* Checks whether a Linux service exists.
|
|
9
6
|
*
|
|
10
7
|
* @param serviceName - The service name (e.g. "nginx", "sshd").
|
|
11
|
-
* @returns Resolves to `true` if the service is known.
|
|
12
|
-
* @throws If the service manager cannot be contacted.
|
|
8
|
+
* @returns Resolves to `true` if the service is known to the init system.
|
|
13
9
|
*/
|
|
14
10
|
export declare function serviceExists(serviceName: string): Promise<boolean>;
|
|
15
11
|
/**
|
|
@@ -20,4 +16,5 @@ export declare function serviceExists(serviceName: string): Promise<boolean>;
|
|
|
20
16
|
* @throws If the service does not exist or cannot be queried.
|
|
21
17
|
*/
|
|
22
18
|
export declare function getServiceStatus(serviceName: string): Promise<ServiceStatus>;
|
|
19
|
+
export {};
|
|
23
20
|
//# sourceMappingURL=linux.d.ts.map
|
package/src/linux.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linux.d.ts","sourceRoot":"","sources":["../../src/linux.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"linux.d.ts","sourceRoot":"","sources":["../../src/linux.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AA4BxC,KAAK,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEhD,wBAAgB,gBAAgB,IAAI,UAAU,CAQ7C;AAoID;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA0BzE;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAmDlF"}
|
package/src/linux.js
CHANGED
|
@@ -1,29 +1,53 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.detectInitSystem = detectInitSystem;
|
|
3
7
|
exports.serviceExists = serviceExists;
|
|
4
8
|
exports.getServiceStatus = getServiceStatus;
|
|
5
9
|
/**
|
|
6
|
-
*
|
|
10
|
+
* Linux implementation of service_api.
|
|
11
|
+
* Zero child_process / zero fork — uses three native backends in cascade:
|
|
12
|
+
* 1. systemd — libsystemd.so.0 via koffi (D-Bus sd_bus)
|
|
13
|
+
* 2. OpenRC — pure filesystem reads (/run/openrc/…)
|
|
14
|
+
* 3. SysV — /etc/init.d/ + /proc/<pid>
|
|
7
15
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
const fs_1 = __importDefault(require("fs"));
|
|
17
|
+
// ─── Filesystem helpers ───────────────────────────────────────────────────────
|
|
18
|
+
function fsExistsSync(p) {
|
|
19
|
+
try {
|
|
20
|
+
fs_1.default.accessSync(p);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function readPidFile(...paths) {
|
|
28
|
+
for (const p of paths) {
|
|
29
|
+
try {
|
|
30
|
+
const raw = fs_1.default.readFileSync(p, 'utf8').trim();
|
|
31
|
+
const pid = parseInt(raw, 10);
|
|
32
|
+
if (pid > 0)
|
|
33
|
+
return pid;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// try next
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
function detectInitSystem() {
|
|
42
|
+
if (fsExistsSync('/run/systemd/private') || fsExistsSync('/sys/fs/cgroup/systemd')) {
|
|
43
|
+
return 'systemd';
|
|
44
|
+
}
|
|
45
|
+
if (fsExistsSync('/run/openrc/softlevel') || fsExistsSync('/run/openrc')) {
|
|
46
|
+
return 'openrc';
|
|
47
|
+
}
|
|
48
|
+
return 'sysv';
|
|
21
49
|
}
|
|
22
50
|
// ─── Systemd state map ────────────────────────────────────────────────────────
|
|
23
|
-
/**
|
|
24
|
-
* Maps systemctl ActiveState values to the canonical state strings used
|
|
25
|
-
* by service_api (mirrors Windows SERVICE_STATES for a consistent API).
|
|
26
|
-
*/
|
|
27
51
|
const SYSTEMD_STATE_MAP = {
|
|
28
52
|
active: 'RUNNING',
|
|
29
53
|
activating: 'START_PENDING',
|
|
@@ -32,80 +56,125 @@ const SYSTEMD_STATE_MAP = {
|
|
|
32
56
|
failed: 'STOPPED',
|
|
33
57
|
reloading: 'CONTINUE_PENDING'
|
|
34
58
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
59
|
+
let _libsystemd = null;
|
|
60
|
+
let _libsystemdAvailable = null;
|
|
61
|
+
function tryLoadLibsystemd() {
|
|
62
|
+
if (_libsystemdAvailable !== null)
|
|
63
|
+
return _libsystemdAvailable;
|
|
40
64
|
try {
|
|
41
|
-
|
|
42
|
-
|
|
65
|
+
const koffi = require('koffi');
|
|
66
|
+
const lib = koffi.load('libsystemd.so.0');
|
|
67
|
+
_libsystemd = {
|
|
68
|
+
sd_bus_open_system: lib.func('int sd_bus_open_system(void **ret)'),
|
|
69
|
+
sd_bus_get_property_string: lib.func('int sd_bus_get_property_string(void *bus, str dest, str path, str iface, str member, void **error, char **ret)'),
|
|
70
|
+
sd_bus_unref: lib.func('void *sd_bus_unref(void *bus)')
|
|
71
|
+
};
|
|
72
|
+
_libsystemdAvailable = true;
|
|
43
73
|
}
|
|
44
74
|
catch {
|
|
45
|
-
|
|
75
|
+
_libsystemdAvailable = false;
|
|
46
76
|
}
|
|
77
|
+
return _libsystemdAvailable;
|
|
47
78
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const props = {};
|
|
59
|
-
for (const line of stdout.split('\n')) {
|
|
60
|
-
const idx = line.indexOf('=');
|
|
61
|
-
if (idx !== -1) {
|
|
62
|
-
props[line.slice(0, idx)] = line.slice(idx + 1);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
loadState: (props.LoadState || '').trim(),
|
|
67
|
-
activeState: (props.ActiveState || '').trim(),
|
|
68
|
-
subState: (props.SubState || '').trim(),
|
|
69
|
-
mainPid: parseInt(props.MainPID || '0', 10) || 0
|
|
70
|
-
};
|
|
79
|
+
const SYSTEMD_DEST = 'org.freedesktop.systemd1';
|
|
80
|
+
const UNIT_IFACE = 'org.freedesktop.systemd1.Unit';
|
|
81
|
+
function unitObjectPath(serviceName) {
|
|
82
|
+
const unit = serviceName.includes('.') ? serviceName : `${serviceName}.service`;
|
|
83
|
+
const encoded = Array.from(unit).map(c => {
|
|
84
|
+
if (/[A-Za-z0-9]/.test(c))
|
|
85
|
+
return c;
|
|
86
|
+
return `_${c.charCodeAt(0).toString(16).padStart(2, '0')}`;
|
|
87
|
+
}).join('');
|
|
88
|
+
return `/org/freedesktop/systemd1/unit/${encoded}`;
|
|
71
89
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
90
|
+
function queryLibsystemd(serviceName) {
|
|
91
|
+
const lib = _libsystemd;
|
|
92
|
+
const busRef = [null];
|
|
93
|
+
if (lib.sd_bus_open_system(busRef) < 0 || busRef[0] === null) {
|
|
94
|
+
throw new Error('sd_bus_open_system failed');
|
|
95
|
+
}
|
|
96
|
+
const bus = busRef[0];
|
|
97
|
+
const path = unitObjectPath(serviceName);
|
|
98
|
+
function getProp(member) {
|
|
99
|
+
const retRef = [null];
|
|
100
|
+
const r = lib.sd_bus_get_property_string(bus, SYSTEMD_DEST, path, UNIT_IFACE, member, [null], retRef);
|
|
101
|
+
if (r < 0)
|
|
102
|
+
return '';
|
|
103
|
+
return retRef[0] ? String(retRef[0]) : '';
|
|
104
|
+
}
|
|
76
105
|
try {
|
|
77
|
-
|
|
78
|
-
|
|
106
|
+
const loadState = getProp('LoadState');
|
|
107
|
+
const activeState = getProp('ActiveState');
|
|
108
|
+
const subState = getProp('SubState');
|
|
109
|
+
const mainPidStr = getProp('MainPID');
|
|
110
|
+
return {
|
|
111
|
+
loadState,
|
|
112
|
+
activeState,
|
|
113
|
+
subState,
|
|
114
|
+
mainPid: parseInt(mainPidStr, 10) || 0
|
|
115
|
+
};
|
|
79
116
|
}
|
|
80
|
-
|
|
81
|
-
|
|
117
|
+
finally {
|
|
118
|
+
lib.sd_bus_unref(bus);
|
|
82
119
|
}
|
|
83
120
|
}
|
|
121
|
+
// ─── OpenRC backend ───────────────────────────────────────────────────────────
|
|
122
|
+
function openrcExists(serviceName) {
|
|
123
|
+
return (fsExistsSync(`/etc/init.d/${serviceName}`) ||
|
|
124
|
+
fsExistsSync(`/etc/runlevels/default/${serviceName}`));
|
|
125
|
+
}
|
|
126
|
+
function openrcState(serviceName) {
|
|
127
|
+
if (fsExistsSync(`/run/openrc/started/${serviceName}`))
|
|
128
|
+
return 'RUNNING';
|
|
129
|
+
if (fsExistsSync(`/run/openrc/starting/${serviceName}`))
|
|
130
|
+
return 'START_PENDING';
|
|
131
|
+
if (fsExistsSync(`/run/openrc/stopping/${serviceName}`))
|
|
132
|
+
return 'STOP_PENDING';
|
|
133
|
+
return 'STOPPED';
|
|
134
|
+
}
|
|
135
|
+
// ─── SysV backend ─────────────────────────────────────────────────────────────
|
|
136
|
+
function sysvExists(serviceName) {
|
|
137
|
+
return fsExistsSync(`/etc/init.d/${serviceName}`);
|
|
138
|
+
}
|
|
139
|
+
function sysvRunning(serviceName) {
|
|
140
|
+
const pid = readPidFile(`/var/run/${serviceName}.pid`, `/run/${serviceName}.pid`);
|
|
141
|
+
if (pid > 0) {
|
|
142
|
+
return { running: fsExistsSync(`/proc/${pid}`), pid };
|
|
143
|
+
}
|
|
144
|
+
const hasLock = fsExistsSync(`/var/run/${serviceName}.lock`) ||
|
|
145
|
+
fsExistsSync(`/run/${serviceName}.lock`);
|
|
146
|
+
return { running: hasLock, pid: 0 };
|
|
147
|
+
}
|
|
84
148
|
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
85
149
|
/**
|
|
86
150
|
* Checks whether a Linux service exists.
|
|
87
151
|
*
|
|
88
152
|
* @param serviceName - The service name (e.g. "nginx", "sshd").
|
|
89
|
-
* @returns Resolves to `true` if the service is known.
|
|
90
|
-
* @throws If the service manager cannot be contacted.
|
|
153
|
+
* @returns Resolves to `true` if the service is known to the init system.
|
|
91
154
|
*/
|
|
92
155
|
async function serviceExists(serviceName) {
|
|
93
156
|
if (!serviceName || typeof serviceName !== 'string') {
|
|
94
157
|
throw new TypeError('serviceName must be a non-empty string');
|
|
95
158
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
159
|
+
const init = detectInitSystem();
|
|
160
|
+
if (init === 'systemd') {
|
|
161
|
+
if (tryLoadLibsystemd()) {
|
|
162
|
+
try {
|
|
163
|
+
const { loadState } = queryLibsystemd(serviceName);
|
|
164
|
+
return loadState !== 'not-found' && loadState !== '';
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// fall through to SysV
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// libsystemd unavailable or query failed — fallback to SysV
|
|
171
|
+
return sysvExists(serviceName);
|
|
105
172
|
}
|
|
106
|
-
|
|
107
|
-
return
|
|
173
|
+
if (init === 'openrc') {
|
|
174
|
+
return openrcExists(serviceName);
|
|
108
175
|
}
|
|
176
|
+
// SysV
|
|
177
|
+
return sysvExists(serviceName);
|
|
109
178
|
}
|
|
110
179
|
/**
|
|
111
180
|
* Returns the current status of a Linux service.
|
|
@@ -118,31 +187,61 @@ async function getServiceStatus(serviceName) {
|
|
|
118
187
|
if (!serviceName || typeof serviceName !== 'string') {
|
|
119
188
|
throw new TypeError('serviceName must be a non-empty string');
|
|
120
189
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
190
|
+
const init = detectInitSystem();
|
|
191
|
+
// ── systemd ────────────────────────────────────────────────────────────────
|
|
192
|
+
if (init === 'systemd') {
|
|
193
|
+
if (tryLoadLibsystemd()) {
|
|
194
|
+
let result;
|
|
195
|
+
try {
|
|
196
|
+
result = queryLibsystemd(serviceName);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
// libsystemd query failed — fall through to SysV
|
|
200
|
+
return _sysvStatus(serviceName);
|
|
201
|
+
}
|
|
202
|
+
const { loadState, activeState, mainPid } = result;
|
|
203
|
+
if (loadState === 'not-found' || loadState === '') {
|
|
204
|
+
throw new Error(`Service "${serviceName}" does not exist`);
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
name: serviceName,
|
|
208
|
+
exists: true,
|
|
209
|
+
state: SYSTEMD_STATE_MAP[activeState] || `UNKNOWN(${activeState})`,
|
|
210
|
+
pid: mainPid,
|
|
211
|
+
rawCode: activeState
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
// libsystemd unavailable — fall through to SysV
|
|
215
|
+
return _sysvStatus(serviceName);
|
|
216
|
+
}
|
|
217
|
+
// ── OpenRC ─────────────────────────────────────────────────────────────────
|
|
218
|
+
if (init === 'openrc') {
|
|
219
|
+
if (!openrcExists(serviceName)) {
|
|
124
220
|
throw new Error(`Service "${serviceName}" does not exist`);
|
|
125
221
|
}
|
|
126
|
-
const state =
|
|
222
|
+
const state = openrcState(serviceName);
|
|
223
|
+
const pid = readPidFile(`/run/${serviceName}.pid`, `/var/run/${serviceName}.pid`);
|
|
127
224
|
return {
|
|
128
225
|
name: serviceName,
|
|
129
226
|
exists: true,
|
|
130
227
|
state,
|
|
131
|
-
pid
|
|
132
|
-
rawCode:
|
|
228
|
+
pid,
|
|
229
|
+
rawCode: state.toLowerCase()
|
|
133
230
|
};
|
|
134
231
|
}
|
|
135
|
-
// SysV
|
|
136
|
-
|
|
137
|
-
|
|
232
|
+
// ── SysV ───────────────────────────────────────────────────────────────────
|
|
233
|
+
return _sysvStatus(serviceName);
|
|
234
|
+
}
|
|
235
|
+
function _sysvStatus(serviceName) {
|
|
236
|
+
if (!sysvExists(serviceName)) {
|
|
138
237
|
throw new Error(`Service "${serviceName}" does not exist`);
|
|
139
238
|
}
|
|
140
|
-
const { running } =
|
|
239
|
+
const { running, pid } = sysvRunning(serviceName);
|
|
141
240
|
return {
|
|
142
241
|
name: serviceName,
|
|
143
242
|
exists: true,
|
|
144
243
|
state: running ? 'RUNNING' : 'STOPPED',
|
|
145
|
-
pid
|
|
244
|
+
pid,
|
|
146
245
|
rawCode: running ? 'active' : 'inactive'
|
|
147
246
|
};
|
|
148
247
|
}
|
package/src/linux.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linux.js","sourceRoot":"","sources":["../../src/linux.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC
|
|
1
|
+
{"version":3,"file":"linux.js","sourceRoot":"","sources":["../../src/linux.ts"],"names":[],"mappings":"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"}
|
package/test/service.test.js
CHANGED
|
@@ -32,192 +32,219 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
35
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
39
|
/**
|
|
37
40
|
* Tests for the Linux implementation (src/linux.ts).
|
|
38
|
-
*
|
|
39
|
-
* requiring a real system service manager.
|
|
41
|
+
* Mocks fs.accessSync and fs.readFileSync to avoid requiring a real init system.
|
|
40
42
|
*/
|
|
41
43
|
const node_test_1 = require("node:test");
|
|
42
44
|
const assert = __importStar(require("node:assert/strict"));
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
45
|
+
const fs_1 = __importDefault(require("fs"));
|
|
46
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
47
|
+
/**
|
|
48
|
+
* Runs `fn` with fs.accessSync and fs.readFileSync patched.
|
|
49
|
+
* `existsSet` is the set of paths that "exist" (accessSync succeeds for them).
|
|
50
|
+
* `pidMap` maps pid-file paths to their string contents.
|
|
51
|
+
*
|
|
52
|
+
* NOTE: requireLinux() must be called BEFORE withFsMock so that Node.js's
|
|
53
|
+
* module loader uses the real fs to read the .js file.
|
|
54
|
+
*/
|
|
55
|
+
async function withFsMock(existsSet, pidMap, fn) {
|
|
56
|
+
const origAccess = fs_1.default.accessSync;
|
|
57
|
+
const origReadFile = fs_1.default.readFileSync;
|
|
58
|
+
fs_1.default.accessSync = (p) => {
|
|
59
|
+
if (existsSet.has(String(p)))
|
|
60
|
+
return;
|
|
61
|
+
const err = new Error(`ENOENT: ${p}`);
|
|
62
|
+
err.code = 'ENOENT';
|
|
63
|
+
throw err;
|
|
64
|
+
};
|
|
65
|
+
fs_1.default.readFileSync = (p, enc) => {
|
|
66
|
+
const key = String(p);
|
|
67
|
+
if (key in pidMap)
|
|
68
|
+
return pidMap[key];
|
|
69
|
+
const err = new Error(`ENOENT: ${p}`);
|
|
70
|
+
err.code = 'ENOENT';
|
|
71
|
+
throw err;
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
await fn();
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
fs_1.default.accessSync = origAccess;
|
|
78
|
+
fs_1.default.readFileSync = origReadFile;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** Re-require linux module with a fresh cache entry. */
|
|
82
|
+
function requireLinux() {
|
|
83
|
+
delete require.cache[require.resolve('../src/linux')];
|
|
84
|
+
return require('../src/linux');
|
|
85
|
+
}
|
|
86
|
+
// ─── detectInitSystem ─────────────────────────────────────────────────────────
|
|
87
|
+
(0, node_test_1.describe)('Linux implementation — detectInitSystem', () => {
|
|
88
|
+
(0, node_test_1.it)('returns systemd when /run/systemd/private exists', async () => {
|
|
89
|
+
const { detectInitSystem } = requireLinux();
|
|
90
|
+
await withFsMock(new Set(['/run/systemd/private']), {}, () => {
|
|
91
|
+
assert.equal(detectInitSystem(), 'systemd');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
(0, node_test_1.it)('returns openrc when /run/openrc/softlevel exists', async () => {
|
|
95
|
+
const { detectInitSystem } = requireLinux();
|
|
96
|
+
await withFsMock(new Set(['/run/openrc/softlevel']), {}, () => {
|
|
97
|
+
assert.equal(detectInitSystem(), 'openrc');
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
(0, node_test_1.it)('returns sysv when only /etc/init.d exists', async () => {
|
|
101
|
+
const { detectInitSystem } = requireLinux();
|
|
102
|
+
await withFsMock(new Set(['/etc/init.d']), {}, () => {
|
|
103
|
+
assert.equal(detectInitSystem(), 'sysv');
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
// ─── serviceExists — systemd (libsystemd unavailable → SysV fallback) ─────────
|
|
108
|
+
(0, node_test_1.describe)('Linux implementation — serviceExists (systemd via libsystemd)', () => {
|
|
109
|
+
(0, node_test_1.it)('returns true when libsystemd unavailable and /etc/init.d/<name> exists (fallback SysV)', async () => {
|
|
110
|
+
const { serviceExists } = requireLinux();
|
|
111
|
+
await withFsMock(new Set(['/run/systemd/private', '/etc/init.d/nginx']), {}, async () => {
|
|
64
112
|
const result = await serviceExists('nginx');
|
|
65
113
|
assert.equal(result, true);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
(0, node_test_1.it)('returns false for a non-existent systemd service', async () => {
|
|
73
|
-
const cp = require('child_process');
|
|
74
|
-
const orig = cp.execFile;
|
|
75
|
-
let callCount = 0;
|
|
76
|
-
cp.execFile = function (cmd, args, opts, cb) {
|
|
77
|
-
callCount++;
|
|
78
|
-
if (callCount === 1) {
|
|
79
|
-
cb(null, 'systemd 252\n', '');
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
// systemd reports not-found
|
|
83
|
-
cb(null, 'LoadState=not-found\nActiveState=inactive\nSubState=dead\nMainPID=0\n', '');
|
|
84
|
-
}
|
|
85
|
-
return { kill: () => { } };
|
|
86
|
-
};
|
|
87
|
-
try {
|
|
88
|
-
delete require.cache[require.resolve('../src/linux')];
|
|
89
|
-
const { serviceExists } = require('../src/linux');
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
(0, node_test_1.it)('returns false when libsystemd unavailable and /etc/init.d/<name> absent', async () => {
|
|
117
|
+
const { serviceExists } = requireLinux();
|
|
118
|
+
await withFsMock(new Set(['/run/systemd/private']), {}, async () => {
|
|
90
119
|
const result = await serviceExists('doesnotexist');
|
|
91
120
|
assert.equal(result, false);
|
|
92
|
-
}
|
|
93
|
-
finally {
|
|
94
|
-
cp.execFile = orig;
|
|
95
|
-
delete require.cache[require.resolve('../src/linux')];
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
(0, node_test_1.it)('throws TypeError for invalid serviceName', async () => {
|
|
99
|
-
delete require.cache[require.resolve('../src/linux')];
|
|
100
|
-
const { serviceExists } = require('../src/linux');
|
|
101
|
-
await assert.rejects(() => serviceExists(''), TypeError);
|
|
102
|
-
await assert.rejects(() => serviceExists(null), TypeError);
|
|
103
|
-
await assert.rejects(() => serviceExists(42), TypeError);
|
|
121
|
+
});
|
|
104
122
|
});
|
|
105
123
|
});
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
+
// ─── serviceExists — OpenRC ───────────────────────────────────────────────────
|
|
125
|
+
(0, node_test_1.describe)('Linux implementation — serviceExists (OpenRC)', () => {
|
|
126
|
+
(0, node_test_1.it)('returns true when /etc/init.d/<name> exists', async () => {
|
|
127
|
+
const { serviceExists } = requireLinux();
|
|
128
|
+
await withFsMock(new Set(['/run/openrc/softlevel', '/etc/init.d/nginx']), {}, async () => {
|
|
129
|
+
assert.equal(await serviceExists('nginx'), true);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
(0, node_test_1.it)('returns false when /etc/init.d/<name> does not exist', async () => {
|
|
133
|
+
const { serviceExists } = requireLinux();
|
|
134
|
+
await withFsMock(new Set(['/run/openrc/softlevel']), {}, async () => {
|
|
135
|
+
assert.equal(await serviceExists('ghost'), false);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
// ─── serviceExists — SysV ────────────────────────────────────────────────────
|
|
140
|
+
(0, node_test_1.describe)('Linux implementation — serviceExists (SysV)', () => {
|
|
141
|
+
(0, node_test_1.it)('returns true when /etc/init.d/<name> exists', async () => {
|
|
142
|
+
const { serviceExists } = requireLinux();
|
|
143
|
+
await withFsMock(new Set(['/etc/init.d/cron']), {}, async () => {
|
|
144
|
+
assert.equal(await serviceExists('cron'), true);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
(0, node_test_1.it)('returns false when /etc/init.d/<name> does not exist', async () => {
|
|
148
|
+
const { serviceExists } = requireLinux();
|
|
149
|
+
await withFsMock(new Set([]), {}, async () => {
|
|
150
|
+
assert.equal(await serviceExists('ghost'), false);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
// ─── getServiceStatus — systemd (libsystemd unavailable → SysV fallback) ──────
|
|
155
|
+
(0, node_test_1.describe)('Linux implementation — getServiceStatus (systemd via libsystemd)', () => {
|
|
156
|
+
(0, node_test_1.it)('RUNNING: /etc/init.d exists and /proc/<pid> exists (fallback SysV)', async () => {
|
|
157
|
+
const { getServiceStatus } = requireLinux();
|
|
158
|
+
await withFsMock(new Set(['/run/systemd/private', '/etc/init.d/sshd', '/proc/4321']), { '/var/run/sshd.pid': '4321\n' }, async () => {
|
|
124
159
|
const status = await getServiceStatus('sshd');
|
|
125
160
|
assert.equal(status.name, 'sshd');
|
|
126
161
|
assert.equal(status.exists, true);
|
|
127
162
|
assert.equal(status.state, 'RUNNING');
|
|
128
163
|
assert.equal(status.pid, 4321);
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
(0, node_test_1.it)('returns STOPPED status for an inactive service', async () => {
|
|
137
|
-
const cp = require('child_process');
|
|
138
|
-
const orig = cp.execFile;
|
|
139
|
-
let callCount = 0;
|
|
140
|
-
cp.execFile = function (cmd, args, opts, cb) {
|
|
141
|
-
callCount++;
|
|
142
|
-
if (callCount === 1) {
|
|
143
|
-
cb(null, 'systemd 252\n', '');
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
cb(null, 'LoadState=loaded\nActiveState=inactive\nSubState=dead\nMainPID=0\n', '');
|
|
147
|
-
}
|
|
148
|
-
return { kill: () => { } };
|
|
149
|
-
};
|
|
150
|
-
try {
|
|
151
|
-
delete require.cache[require.resolve('../src/linux')];
|
|
152
|
-
const { getServiceStatus } = require('../src/linux');
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
(0, node_test_1.it)('STOPPED: /etc/init.d exists but no pid/proc (fallback SysV)', async () => {
|
|
167
|
+
const { getServiceStatus } = requireLinux();
|
|
168
|
+
await withFsMock(new Set(['/run/systemd/private', '/etc/init.d/nginx']), {}, async () => {
|
|
153
169
|
const status = await getServiceStatus('nginx');
|
|
154
170
|
assert.equal(status.state, 'STOPPED');
|
|
155
171
|
assert.equal(status.pid, 0);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
(0, node_test_1.it)('returns START_PENDING for an activating service', async () => {
|
|
163
|
-
const cp = require('child_process');
|
|
164
|
-
const orig = cp.execFile;
|
|
165
|
-
let callCount = 0;
|
|
166
|
-
cp.execFile = function (cmd, args, opts, cb) {
|
|
167
|
-
callCount++;
|
|
168
|
-
if (callCount === 1) {
|
|
169
|
-
cb(null, 'systemd 252\n', '');
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
cb(null, 'LoadState=loaded\nActiveState=activating\nSubState=start\nMainPID=0\n', '');
|
|
173
|
-
}
|
|
174
|
-
return { kill: () => { } };
|
|
175
|
-
};
|
|
176
|
-
try {
|
|
177
|
-
delete require.cache[require.resolve('../src/linux')];
|
|
178
|
-
const { getServiceStatus } = require('../src/linux');
|
|
179
|
-
const status = await getServiceStatus('myservice');
|
|
180
|
-
assert.equal(status.state, 'START_PENDING');
|
|
181
|
-
}
|
|
182
|
-
finally {
|
|
183
|
-
cp.execFile = orig;
|
|
184
|
-
delete require.cache[require.resolve('../src/linux')];
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
(0, node_test_1.it)('throws when the service does not exist', async () => {
|
|
188
|
-
const cp = require('child_process');
|
|
189
|
-
const orig = cp.execFile;
|
|
190
|
-
let callCount = 0;
|
|
191
|
-
cp.execFile = function (cmd, args, opts, cb) {
|
|
192
|
-
callCount++;
|
|
193
|
-
if (callCount === 1) {
|
|
194
|
-
cb(null, 'systemd 252\n', '');
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
cb(null, 'LoadState=not-found\nActiveState=inactive\nSubState=dead\nMainPID=0\n', '');
|
|
198
|
-
}
|
|
199
|
-
return { kill: () => { } };
|
|
200
|
-
};
|
|
201
|
-
try {
|
|
202
|
-
delete require.cache[require.resolve('../src/linux')];
|
|
203
|
-
const { getServiceStatus } = require('../src/linux');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
(0, node_test_1.it)('throws when /etc/init.d/<name> does not exist (fallback SysV)', async () => {
|
|
175
|
+
const { getServiceStatus } = requireLinux();
|
|
176
|
+
await withFsMock(new Set(['/run/systemd/private']), {}, async () => {
|
|
204
177
|
await assert.rejects(() => getServiceStatus('ghost'), (err) => err.message.includes('does not exist'));
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
// ─── getServiceStatus — OpenRC ────────────────────────────────────────────────
|
|
182
|
+
(0, node_test_1.describe)('Linux implementation — getServiceStatus (OpenRC)', () => {
|
|
183
|
+
(0, node_test_1.it)('RUNNING when /run/openrc/started/<name> exists', async () => {
|
|
184
|
+
const { getServiceStatus } = requireLinux();
|
|
185
|
+
await withFsMock(new Set(['/run/openrc/softlevel', '/etc/init.d/nginx', '/run/openrc/started/nginx']), { '/run/nginx.pid': '9999\n' }, async () => {
|
|
186
|
+
const status = await getServiceStatus('nginx');
|
|
187
|
+
assert.equal(status.state, 'RUNNING');
|
|
188
|
+
assert.equal(status.pid, 9999);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
(0, node_test_1.it)('STOPPED when no openrc state files present', async () => {
|
|
192
|
+
const { getServiceStatus } = requireLinux();
|
|
193
|
+
await withFsMock(new Set(['/run/openrc/softlevel', '/etc/init.d/nginx']), {}, async () => {
|
|
194
|
+
const status = await getServiceStatus('nginx');
|
|
195
|
+
assert.equal(status.state, 'STOPPED');
|
|
196
|
+
assert.equal(status.pid, 0);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
(0, node_test_1.it)('pid read from /run/<name>.pid', async () => {
|
|
200
|
+
const { getServiceStatus } = requireLinux();
|
|
201
|
+
await withFsMock(new Set(['/run/openrc/softlevel', '/etc/init.d/sshd', '/run/openrc/started/sshd']), { '/run/sshd.pid': '1234\n' }, async () => {
|
|
202
|
+
const status = await getServiceStatus('sshd');
|
|
203
|
+
assert.equal(status.pid, 1234);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
// ─── getServiceStatus — SysV ──────────────────────────────────────────────────
|
|
208
|
+
(0, node_test_1.describe)('Linux implementation — getServiceStatus (SysV)', () => {
|
|
209
|
+
(0, node_test_1.it)('RUNNING when /etc/init.d/<name> exists and /proc/<pid> exists', async () => {
|
|
210
|
+
const { getServiceStatus } = requireLinux();
|
|
211
|
+
await withFsMock(new Set(['/etc/init.d/cron', '/proc/5678']), { '/var/run/cron.pid': '5678\n' }, async () => {
|
|
212
|
+
const status = await getServiceStatus('cron');
|
|
213
|
+
assert.equal(status.state, 'RUNNING');
|
|
214
|
+
assert.equal(status.pid, 5678);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
(0, node_test_1.it)('STOPPED when pid=0 and no lock file', async () => {
|
|
218
|
+
const { getServiceStatus } = requireLinux();
|
|
219
|
+
await withFsMock(new Set(['/etc/init.d/cron']), {}, async () => {
|
|
220
|
+
const status = await getServiceStatus('cron');
|
|
221
|
+
assert.equal(status.state, 'STOPPED');
|
|
222
|
+
assert.equal(status.pid, 0);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
// ─── TypeError guards ─────────────────────────────────────────────────────────
|
|
227
|
+
(0, node_test_1.describe)('Linux implementation — TypeError guards', () => {
|
|
228
|
+
(0, node_test_1.it)('serviceExists("") → TypeError', async () => {
|
|
229
|
+
const { serviceExists } = requireLinux();
|
|
230
|
+
await assert.rejects(() => serviceExists(''), TypeError);
|
|
231
|
+
});
|
|
232
|
+
(0, node_test_1.it)('serviceExists(null) → TypeError', async () => {
|
|
233
|
+
const { serviceExists } = requireLinux();
|
|
234
|
+
await assert.rejects(() => serviceExists(null), TypeError);
|
|
235
|
+
});
|
|
236
|
+
(0, node_test_1.it)('getServiceStatus("") → TypeError', async () => {
|
|
237
|
+
const { getServiceStatus } = requireLinux();
|
|
214
238
|
await assert.rejects(() => getServiceStatus(''), TypeError);
|
|
239
|
+
});
|
|
240
|
+
(0, node_test_1.it)('getServiceStatus(undefined) → TypeError', async () => {
|
|
241
|
+
const { getServiceStatus } = requireLinux();
|
|
215
242
|
await assert.rejects(() => getServiceStatus(undefined), TypeError);
|
|
216
243
|
});
|
|
217
244
|
});
|
|
245
|
+
// ─── index.ts — module contract ───────────────────────────────────────────────
|
|
218
246
|
(0, node_test_1.describe)('index.ts — module contract', () => {
|
|
219
247
|
(0, node_test_1.it)('exports serviceExists and getServiceStatus functions', () => {
|
|
220
|
-
// On Linux (our CI), the main index loads linux.
|
|
221
248
|
delete require.cache[require.resolve('../index')];
|
|
222
249
|
const api = require('../index');
|
|
223
250
|
assert.equal(typeof api.serviceExists, 'function');
|
package/test/service.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.test.js","sourceRoot":"","sources":["../../test/service.test.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC
|
|
1
|
+
{"version":3,"file":"service.test.js","sourceRoot":"","sources":["../../test/service.test.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEb;;;GAGG;AAEH,yCAAyC;AACzC,2DAA6C;AAC7C,4CAAoB;AAEpB,iFAAiF;AAEjF;;;;;;;GAOG;AACH,KAAK,UAAU,UAAU,CACvB,SAAsB,EACtB,MAA8B,EAC9B,EAAiB;IAEjB,MAAM,UAAU,GAAK,YAAE,CAAC,UAAU,CAAC;IACnC,MAAM,YAAY,GAAG,YAAE,CAAC,YAAY,CAAC;IAErC,YAAE,CAAC,UAAU,GAAG,CAAC,CAAM,EAAE,EAAE;QACzB,IAAI,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO;QACrC,MAAM,GAAG,GAAQ,IAAI,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC3C,GAAG,CAAC,IAAI,GAAG,QAAQ,CAAC;QACpB,MAAM,GAAG,CAAC;IACZ,CAAC,CAAC;IACD,YAAU,CAAC,YAAY,GAAG,CAAC,CAAM,EAAE,GAAS,EAAE,EAAE;QAC/C,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,GAAG,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,GAAG,GAAQ,IAAI,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC3C,GAAG,CAAC,IAAI,GAAG,QAAQ,CAAC;QACpB,MAAM,GAAG,CAAC;IACZ,CAAC,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,CAAC;IACb,CAAC;YAAS,CAAC;QACT,YAAE,CAAC,UAAU,GAAU,UAAU,CAAC;QACjC,YAAU,CAAC,YAAY,GAAG,YAAY,CAAC;IAC1C,CAAC;AACH,CAAC;AAED,wDAAwD;AACxD,SAAS,YAAY;IACnB,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;IACtD,OAAO,OAAO,CAAC,cAAc,CAAC,CAAC;AACjC,CAAC;AAED,iFAAiF;AAEjF,IAAA,oBAAQ,EAAC,yCAAyC,EAAE,GAAG,EAAE;IACvD,IAAA,cAAE,EAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,UAAU,CAAC,IAAI,GAAG,CAAC,CAAC,sBAAsB,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE;YAC3D,MAAM,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,SAAS,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,UAAU,CAAC,IAAI,GAAG,CAAC,CAAC,uBAAuB,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE;YAC5D,MAAM,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,UAAU,CAAC,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE;YAClD,MAAM,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,MAAM,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iFAAiF;AAEjF,IAAA,oBAAQ,EAAC,+DAA+D,EAAE,GAAG,EAAE;IAC7E,IAAA,cAAE,EAAC,wFAAwF,EAAE,KAAK,IAAI,EAAE;QACtG,MAAM,EAAE,aAAa,EAAE,GAAG,YAAY,EAAE,CAAC;QACzC,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAC,EACtD,EAAE,EACF,KAAK,IAAI,EAAE;YACT,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;YAC5C,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC7B,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;QACvF,MAAM,EAAE,aAAa,EAAE,GAAG,YAAY,EAAE,CAAC;QACzC,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,sBAAsB,CAAC,CAAC,EACjC,EAAE,EACF,KAAK,IAAI,EAAE;YACT,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,cAAc,CAAC,CAAC;YACnD,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC9B,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iFAAiF;AAEjF,IAAA,oBAAQ,EAAC,+CAA+C,EAAE,GAAG,EAAE;IAC7D,IAAA,cAAE,EAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,EAAE,aAAa,EAAE,GAAG,YAAY,EAAE,CAAC;QACzC,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,uBAAuB,EAAE,mBAAmB,CAAC,CAAC,EACvD,EAAE,EACF,KAAK,IAAI,EAAE;YACT,MAAM,CAAC,KAAK,CAAC,MAAM,aAAa,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;QACnD,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,EAAE,aAAa,EAAE,GAAG,YAAY,EAAE,CAAC;QACzC,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,uBAAuB,CAAC,CAAC,EAClC,EAAE,EACF,KAAK,IAAI,EAAE;YACT,MAAM,CAAC,KAAK,CAAC,MAAM,aAAa,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;QACpD,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,gFAAgF;AAEhF,IAAA,oBAAQ,EAAC,6CAA6C,EAAE,GAAG,EAAE;IAC3D,IAAA,cAAE,EAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,EAAE,aAAa,EAAE,GAAG,YAAY,EAAE,CAAC;QACzC,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,kBAAkB,CAAC,CAAC,EAC7B,EAAE,EACF,KAAK,IAAI,EAAE;YACT,MAAM,CAAC,KAAK,CAAC,MAAM,aAAa,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;QAClD,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,EAAE,aAAa,EAAE,GAAG,YAAY,EAAE,CAAC;QACzC,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,EAAE,CAAC,EACX,EAAE,EACF,KAAK,IAAI,EAAE;YACT,MAAM,CAAC,KAAK,CAAC,MAAM,aAAa,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;QACpD,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iFAAiF;AAEjF,IAAA,oBAAQ,EAAC,kEAAkE,EAAE,GAAG,EAAE;IAChF,IAAA,cAAE,EAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,sBAAsB,EAAE,kBAAkB,EAAE,YAAY,CAAC,CAAC,EACnE,EAAE,mBAAmB,EAAE,QAAQ,EAAE,EACjC,KAAK,IAAI,EAAE;YACT,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAClC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAC,EACtD,EAAE,EACF,KAAK,IAAI,EAAE;YACT,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAC/C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC9B,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,sBAAsB,CAAC,CAAC,EACjC,EAAE,EACF,KAAK,IAAI,EAAE;YACT,MAAM,MAAM,CAAC,OAAO,CAClB,GAAG,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAC/B,CAAC,GAAU,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CACvD,CAAC;QACJ,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iFAAiF;AAEjF,IAAA,oBAAQ,EAAC,kDAAkD,EAAE,GAAG,EAAE;IAChE,IAAA,cAAE,EAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,uBAAuB,EAAE,mBAAmB,EAAE,2BAA2B,CAAC,CAAC,EACpF,EAAE,gBAAgB,EAAE,QAAQ,EAAE,EAC9B,KAAK,IAAI,EAAE;YACT,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAC/C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,uBAAuB,EAAE,mBAAmB,CAAC,CAAC,EACvD,EAAE,EACF,KAAK,IAAI,EAAE;YACT,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAC/C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC9B,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,uBAAuB,EAAE,kBAAkB,EAAE,0BAA0B,CAAC,CAAC,EAClF,EAAE,eAAe,EAAE,QAAQ,EAAE,EAC7B,KAAK,IAAI,EAAE;YACT,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iFAAiF;AAEjF,IAAA,oBAAQ,EAAC,gDAAgD,EAAE,GAAG,EAAE;IAC9D,IAAA,cAAE,EAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC,EAC3C,EAAE,mBAAmB,EAAE,QAAQ,EAAE,EACjC,KAAK,IAAI,EAAE;YACT,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,UAAU,CACd,IAAI,GAAG,CAAC,CAAC,kBAAkB,CAAC,CAAC,EAC7B,EAAE,EACF,KAAK,IAAI,EAAE;YACT,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC9B,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iFAAiF;AAEjF,IAAA,oBAAQ,EAAC,yCAAyC,EAAE,GAAG,EAAE;IACvD,IAAA,cAAE,EAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,EAAE,aAAa,EAAE,GAAG,YAAY,EAAE,CAAC;QACzC,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,EAAE,aAAa,EAAE,GAAG,YAAY,EAAE,CAAC;QACzC,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,IAAW,CAAC,EAAE,SAAS,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAAC;QAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,SAAgB,CAAC,EAAE,SAAS,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iFAAiF;AAEjF,IAAA,oBAAQ,EAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,IAAA,cAAE,EAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;QAClD,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|