@ulyssedu45/service_api 1.0.5

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 ADDED
@@ -0,0 +1,177 @@
1
+ # service_api
2
+
3
+ Cross-platform Node.js library to **check the existence and status of OS services** using native system APIs.
4
+
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
+
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** | `systemctl` (systemd), with a fallback to the legacy SysV `service` command. |
11
+
12
+ ---
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @ulyssedu45/service_api
18
+ ```
19
+
20
+ > **Requirements**: Node.js ≥ 18. koffi ships pre-built binaries for Windows and Linux (x64 / arm64) — no compilation step is needed.
21
+
22
+ ---
23
+
24
+ ## Usage
25
+
26
+ The import and every function call look **identical** on Windows and Linux:
27
+
28
+ ```js
29
+ const { serviceExists, getServiceStatus } = require("@ulyssedu45/service_api");
30
+
31
+ // ── Check whether a service exists ───────────────────────────────────────────
32
+ const exists = await serviceExists("myService");
33
+ console.log(exists); // true | false
34
+
35
+ // ── Get the full status ───────────────────────────────────────────────────────
36
+ const status = await getServiceStatus("myService");
37
+ console.log(status);
38
+ // {
39
+ // name: 'myService',
40
+ // exists: true,
41
+ // state: 'RUNNING', // normalized — same values on both platforms
42
+ // pid: 12345,
43
+ // rawCode: ... // raw OS value: ActiveState string (Linux) or dwCurrentState number (Windows)
44
+ // }
45
+ ```
46
+
47
+ ### Service name convention
48
+
49
+ | Platform | Name to use | Examples |
50
+ | -------- | -------------------------------------- | ------------------------------------ |
51
+ | Windows | Short service name | `"wuauserv"`, `"spooler"`, `"W3SVC"` |
52
+ | Linux | systemd unit name (without `.service`) | `"nginx"`, `"sshd"`, `"cron"` |
53
+
54
+ ---
55
+
56
+ ## Examples
57
+
58
+ ### Check existence and react to state
59
+
60
+ ```js
61
+ const { serviceExists, getServiceStatus } = require("@ulyssedu45/service_api");
62
+
63
+ async function checkService(name) {
64
+ if (!(await serviceExists(name))) {
65
+ console.log(`${name} is not installed.`);
66
+ return;
67
+ }
68
+
69
+ const { state, pid } = await getServiceStatus(name);
70
+
71
+ if (state === "RUNNING") {
72
+ console.log(`${name} is running (PID ${pid}).`);
73
+ } else if (state === "STOPPED") {
74
+ console.log(`${name} is stopped.`);
75
+ } else {
76
+ console.log(`${name} state: ${state}`);
77
+ }
78
+ }
79
+
80
+ // Windows
81
+ checkService("spooler");
82
+
83
+ // Linux
84
+ checkService("nginx");
85
+ ```
86
+
87
+ ### Check multiple services at once
88
+
89
+ ```js
90
+ const { getServiceStatus } = require("@ulyssedu45/service_api");
91
+
92
+ const services =
93
+ process.platform === "win32"
94
+ ? ["spooler", "wuauserv", "W3SVC"] // Windows
95
+ : ["nginx", "sshd", "cron"]; // Linux
96
+
97
+ const results = await Promise.all(services.map((name) => getServiceStatus(name).catch((err) => ({ name, exists: false, error: err.message }))));
98
+
99
+ for (const s of results) {
100
+ if (!s.exists) {
101
+ console.log(`${s.name}: not found`);
102
+ } else {
103
+ console.log(`${s.name}: ${s.state} (PID ${s.pid || "-"})`);
104
+ }
105
+ }
106
+ ```
107
+
108
+ ### Runnable demo
109
+
110
+ ```bash
111
+ # Uses a sensible default service for the current OS
112
+ node examples/check-service.js
113
+
114
+ # Pass any service name as an argument
115
+ node examples/check-service.js nginx # Linux
116
+ node examples/check-service.js spooler # Windows
117
+ ```
118
+
119
+ ---
120
+
121
+ ## API
122
+
123
+ ### `serviceExists(serviceName) → Promise<boolean>`
124
+
125
+ Returns `true` if the service is registered with the OS service manager, `false` if it does not exist.
126
+
127
+ - Throws `TypeError` if `serviceName` is not a non-empty string.
128
+ - Throws `Error` if the service manager cannot be contacted.
129
+
130
+ ### `getServiceStatus(serviceName) → Promise<ServiceStatus>`
131
+
132
+ Returns a `ServiceStatus` object:
133
+
134
+ | Field | Type | Description |
135
+ | --------- | ---------------- | --------------------------------------------------------------------------------- |
136
+ | `name` | `string` | The service name as provided. |
137
+ | `exists` | `boolean` | Always `true` (throws if the service is missing). |
138
+ | `state` | `string` | Normalized state — see table below. |
139
+ | `pid` | `number` | Main process ID (`0` when the service is not running). |
140
+ | `rawCode` | `string\|number` | Raw OS value: `ActiveState` string on Linux, `dwCurrentState` integer on Windows. |
141
+
142
+ - Throws `Error` if the service does not exist or cannot be queried.
143
+
144
+ ### State values
145
+
146
+ | `state` | Linux (ActiveState) | Windows (dwCurrentState) |
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` |
155
+
156
+ ---
157
+
158
+ ## How it works on Windows
159
+
160
+ The library uses [koffi](https://koffi.dev/) to call `advapi32.dll` functions directly from Node.js — no PowerShell, no `sc.exe`, no child processes:
161
+
162
+ 1. **`OpenSCManagerW`** — opens a connection to the local SCM.
163
+ 2. **`OpenServiceW`** — opens a handle to the named service.
164
+ 3. **`QueryServiceStatusEx`** — fills a `SERVICE_STATUS_PROCESS` structure with the current state and PID.
165
+ 4. **`CloseServiceHandle`** — releases both handles.
166
+
167
+ If `OpenServiceW` fails with error `1060` (`ERROR_SERVICE_DOES_NOT_EXIST`), `serviceExists` returns `false` rather than throwing.
168
+
169
+ ---
170
+
171
+ ## Running the tests
172
+
173
+ ```bash
174
+ npm test
175
+ ```
176
+
177
+ Tests use Node.js's built-in `node:test` runner (no extra dependencies).
package/index.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * service_api — cross-platform Node.js library to check Windows/Linux service
3
+ * existence and status.
4
+ *
5
+ * On Windows the library calls the Service Control Manager (SCM) via the
6
+ * advapi32.dll Windows API using koffi FFI bindings (no PowerShell, no sc.exe).
7
+ *
8
+ * On Linux the library queries systemd via systemctl, falling back to the
9
+ * legacy SysV `service` command on non-systemd systems.
10
+ *
11
+ * @module service_api
12
+ */
13
+ import { ServiceStatus } from './src/types';
14
+ /**
15
+ * Checks whether a service exists on the current operating system.
16
+ *
17
+ * @param serviceName
18
+ * - **Windows**: the short service name (e.g. `"wuauserv"`, `"spooler"`).
19
+ * - **Linux**: the systemd unit name without the `.service` suffix
20
+ * (e.g. `"nginx"`, `"sshd"`).
21
+ *
22
+ * @returns `true` if the service is registered, `false` otherwise.
23
+ * @throws {TypeError} If `serviceName` is not a non-empty string.
24
+ * @throws {Error} If the service manager cannot be contacted.
25
+ */
26
+ declare const serviceExists: (serviceName: string) => Promise<boolean>;
27
+ /**
28
+ * Returns the current status of a service.
29
+ *
30
+ * @param serviceName - See {@link serviceExists} for naming convention.
31
+ * @returns The service status.
32
+ * @throws {TypeError} If `serviceName` is not a non-empty string.
33
+ * @throws {Error} If the service does not exist or cannot be queried.
34
+ */
35
+ declare const getServiceStatus: (serviceName: string) => Promise<ServiceStatus>;
36
+ export { serviceExists, getServiceStatus, ServiceStatus };
37
+ //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAiB,MAAM,aAAa,CAAC;AAc3D;;;;;;;;;;;GAWG;AACH,QAAA,MAAM,aAAa,2CAAqB,CAAC;AAEzC;;;;;;;GAOG;AACH,QAAA,MAAM,gBAAgB,iDAAwB,CAAC;AAE/C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,CAAC"}
package/index.js ADDED
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getServiceStatus = exports.serviceExists = void 0;
4
+ const platform = process.platform;
5
+ let impl;
6
+ if (platform === 'win32') {
7
+ impl = require('./src/windows');
8
+ }
9
+ else if (platform === 'linux' || platform === 'darwin') {
10
+ impl = require('./src/linux');
11
+ }
12
+ else {
13
+ throw new Error(`service_api: unsupported platform "${platform}"`);
14
+ }
15
+ /**
16
+ * Checks whether a service exists on the current operating system.
17
+ *
18
+ * @param serviceName
19
+ * - **Windows**: the short service name (e.g. `"wuauserv"`, `"spooler"`).
20
+ * - **Linux**: the systemd unit name without the `.service` suffix
21
+ * (e.g. `"nginx"`, `"sshd"`).
22
+ *
23
+ * @returns `true` if the service is registered, `false` otherwise.
24
+ * @throws {TypeError} If `serviceName` is not a non-empty string.
25
+ * @throws {Error} If the service manager cannot be contacted.
26
+ */
27
+ const serviceExists = impl.serviceExists;
28
+ exports.serviceExists = serviceExists;
29
+ /**
30
+ * Returns the current status of a service.
31
+ *
32
+ * @param serviceName - See {@link serviceExists} for naming convention.
33
+ * @returns The service status.
34
+ * @throws {TypeError} If `serviceName` is not a non-empty string.
35
+ * @throws {Error} If the service does not exist or cannot be queried.
36
+ */
37
+ const getServiceStatus = impl.getServiceStatus;
38
+ exports.getServiceStatus = getServiceStatus;
39
+ //# sourceMappingURL=index.js.map
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAiBb,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;AAElC,IAAI,IAAmB,CAAC;AAExB,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;IACzB,IAAI,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;AAClC,CAAC;KAAM,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;IACzD,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;AAChC,CAAC;KAAM,CAAC;IACN,MAAM,IAAI,KAAK,CAAC,sCAAsC,QAAQ,GAAG,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;AAYhC,sCAAa;AAVtB;;;;;;;GAOG;AACH,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;AAEvB,4CAAgB"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@ulyssedu45/service_api",
3
+ "version": "1.0.5",
4
+ "description": "Cross-platform Node.js library to check Windows/Linux service existence and status via native OS APIs",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/ulyssedu45/service_api.git"
10
+ },
11
+ "keywords": [
12
+ "windows",
13
+ "service",
14
+ "linux",
15
+ "systemd",
16
+ "scm",
17
+ "winapi",
18
+ "ffi"
19
+ ],
20
+ "author": "",
21
+ "license": "ISC",
22
+ "engines": {
23
+ "node": ">=18.0.0"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/ulyssedu45/service_api/issues"
27
+ },
28
+ "homepage": "https://github.com/ulyssedu45/service_api#readme",
29
+ "dependencies": {
30
+ "koffi": "^2.15.1"
31
+ }
32
+ }
package/src/linux.d.ts ADDED
@@ -0,0 +1,23 @@
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
+ import { ServiceStatus } from './types';
7
+ /**
8
+ * Checks whether a Linux service exists.
9
+ *
10
+ * @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.
13
+ */
14
+ export declare function serviceExists(serviceName: string): Promise<boolean>;
15
+ /**
16
+ * Returns the current status of a Linux service.
17
+ *
18
+ * @param serviceName - The service name (e.g. "nginx", "sshd").
19
+ * @returns The service status.
20
+ * @throws If the service does not exist or cannot be queried.
21
+ */
22
+ export declare function getServiceStatus(serviceName: string): Promise<ServiceStatus>;
23
+ //# sourceMappingURL=linux.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linux.d.ts","sourceRoot":"","sources":["../../src/linux.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AA6GxC;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAkBzE;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqClF"}
package/src/linux.js ADDED
@@ -0,0 +1,149 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serviceExists = serviceExists;
4
+ exports.getServiceStatus = getServiceStatus;
5
+ /**
6
+ * Thin async wrapper around child_process.execFile.
7
+ */
8
+ function execFileAsync(cmd, args, opts) {
9
+ return new Promise((resolve, reject) => {
10
+ require('child_process').execFile(cmd, args, opts, (err, stdout, stderr) => {
11
+ if (err) {
12
+ err.stdout = stdout;
13
+ err.stderr = stderr;
14
+ reject(err);
15
+ }
16
+ else {
17
+ resolve({ stdout: stdout || '', stderr: stderr || '' });
18
+ }
19
+ });
20
+ });
21
+ }
22
+ // ─── 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
+ const SYSTEMD_STATE_MAP = {
28
+ active: 'RUNNING',
29
+ activating: 'START_PENDING',
30
+ deactivating: 'STOP_PENDING',
31
+ inactive: 'STOPPED',
32
+ failed: 'STOPPED',
33
+ reloading: 'CONTINUE_PENDING'
34
+ };
35
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
36
+ /**
37
+ * Detects whether the current system runs systemd.
38
+ */
39
+ async function isSystemd() {
40
+ try {
41
+ await execFileAsync('systemctl', ['--version'], { timeout: 3000 });
42
+ return true;
43
+ }
44
+ catch {
45
+ return false;
46
+ }
47
+ }
48
+ /**
49
+ * Queries a service via systemctl (systemd).
50
+ */
51
+ async function querySystemd(serviceName) {
52
+ const { stdout } = await execFileAsync('systemctl', [
53
+ 'show',
54
+ '--no-pager',
55
+ '--property=LoadState,ActiveState,SubState,MainPID',
56
+ `${serviceName}.service`
57
+ ], { timeout: 5000 });
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
+ };
71
+ }
72
+ /**
73
+ * Queries a service via the legacy SysV `service` command.
74
+ */
75
+ async function querySysV(serviceName) {
76
+ try {
77
+ await execFileAsync('service', [serviceName, 'status'], { timeout: 5000 });
78
+ return { running: true };
79
+ }
80
+ catch {
81
+ return { running: false };
82
+ }
83
+ }
84
+ // ─── Public API ───────────────────────────────────────────────────────────────
85
+ /**
86
+ * Checks whether a Linux service exists.
87
+ *
88
+ * @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.
91
+ */
92
+ async function serviceExists(serviceName) {
93
+ if (!serviceName || typeof serviceName !== 'string') {
94
+ throw new TypeError('serviceName must be a non-empty string');
95
+ }
96
+ if (await isSystemd()) {
97
+ const { loadState } = await querySystemd(serviceName);
98
+ return loadState !== 'not-found' && loadState !== '';
99
+ }
100
+ // SysV fallback: check if an init script is present.
101
+ const { access: fsAccess } = require('fs').promises;
102
+ try {
103
+ await fsAccess(`/etc/init.d/${serviceName}`);
104
+ return true;
105
+ }
106
+ catch {
107
+ return false;
108
+ }
109
+ }
110
+ /**
111
+ * Returns the current status of a Linux service.
112
+ *
113
+ * @param serviceName - The service name (e.g. "nginx", "sshd").
114
+ * @returns The service status.
115
+ * @throws If the service does not exist or cannot be queried.
116
+ */
117
+ async function getServiceStatus(serviceName) {
118
+ if (!serviceName || typeof serviceName !== 'string') {
119
+ throw new TypeError('serviceName must be a non-empty string');
120
+ }
121
+ if (await isSystemd()) {
122
+ const { loadState, activeState, subState, mainPid } = await querySystemd(serviceName);
123
+ if (loadState === 'not-found' || loadState === '') {
124
+ throw new Error(`Service "${serviceName}" does not exist`);
125
+ }
126
+ const state = SYSTEMD_STATE_MAP[activeState] || `UNKNOWN(${activeState})`;
127
+ return {
128
+ name: serviceName,
129
+ exists: true,
130
+ state,
131
+ pid: mainPid,
132
+ rawCode: activeState
133
+ };
134
+ }
135
+ // SysV fallback
136
+ const exists = await serviceExists(serviceName);
137
+ if (!exists) {
138
+ throw new Error(`Service "${serviceName}" does not exist`);
139
+ }
140
+ const { running } = await querySysV(serviceName);
141
+ return {
142
+ name: serviceName,
143
+ exists: true,
144
+ state: running ? 'RUNNING' : 'STOPPED',
145
+ pid: 0,
146
+ rawCode: running ? 'active' : 'inactive'
147
+ };
148
+ }
149
+ //# sourceMappingURL=linux.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linux.js","sourceRoot":"","sources":["../../src/linux.ts"],"names":[],"mappings":"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"}
package/src/types.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Represents the status of an OS service.
3
+ */
4
+ export interface ServiceStatus {
5
+ /** The service name as provided. */
6
+ name: string;
7
+ /** Always `true` (throws if the service is missing). */
8
+ exists: boolean;
9
+ /**
10
+ * One of: RUNNING | STOPPED | START_PENDING |
11
+ * STOP_PENDING | CONTINUE_PENDING | PAUSE_PENDING |
12
+ * PAUSED | UNKNOWN(<raw>).
13
+ */
14
+ state: string;
15
+ /** Main process ID (0 when the service is stopped). */
16
+ pid: number;
17
+ /** The raw state value from the OS. */
18
+ rawCode: string | number;
19
+ }
20
+ /**
21
+ * The platform-specific module contract.
22
+ */
23
+ export interface ServiceModule {
24
+ serviceExists(serviceName: string): Promise<boolean>;
25
+ getServiceStatus(serviceName: string): Promise<ServiceStatus>;
26
+ }
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,MAAM,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CAC/D"}
package/src/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ import { ServiceStatus } from './types';
2
+ /**
3
+ * Checks whether a Windows service exists in the SCM database.
4
+ *
5
+ * @param serviceName - The short name of the service (e.g. "wuauserv").
6
+ * @returns Resolves to `true` if the service exists.
7
+ * @throws If the SCM cannot be opened.
8
+ */
9
+ export declare function serviceExists(serviceName: string): Promise<boolean>;
10
+ /**
11
+ * Returns the current status of a Windows service.
12
+ *
13
+ * @param serviceName - The short name of the service (e.g. "wuauserv").
14
+ * @returns The service status.
15
+ * @throws If the service does not exist or cannot be queried.
16
+ */
17
+ export declare function getServiceStatus(serviceName: string): Promise<ServiceStatus>;
18
+ //# sourceMappingURL=windows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows.d.ts","sourceRoot":"","sources":["../../src/windows.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AA4FxC;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAwBzE;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAiDlF"}
package/src/windows.js ADDED
@@ -0,0 +1,156 @@
1
+ 'use strict';
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.serviceExists = serviceExists;
7
+ exports.getServiceStatus = getServiceStatus;
8
+ /**
9
+ * Windows implementation of service_api.
10
+ * Uses the Windows Service Control Manager (SCM) via koffi FFI bindings
11
+ * to call advapi32.dll directly — no PowerShell or sc.exe involved.
12
+ */
13
+ const koffi_1 = __importDefault(require("koffi"));
14
+ // ─── Windows API constants ────────────────────────────────────────────────────
15
+ /** Right to connect to the SCM. */
16
+ const SC_MANAGER_CONNECT = 0x0001;
17
+ /** Right to query the service status. */
18
+ const SERVICE_QUERY_STATUS = 0x0004;
19
+ /** QueryServiceStatusEx InfoLevel: returns a SERVICE_STATUS_PROCESS structure. */
20
+ const SC_STATUS_PROCESS_INFO = 0;
21
+ /** GetLastError code when the named service does not exist in the SCM database. */
22
+ const ERROR_SERVICE_DOES_NOT_EXIST = 1060;
23
+ // ─── Service state map ────────────────────────────────────────────────────────
24
+ /** Maps dwCurrentState values to human-readable strings. */
25
+ const SERVICE_STATES = {
26
+ 1: 'STOPPED',
27
+ 2: 'START_PENDING',
28
+ 3: 'STOP_PENDING',
29
+ 4: 'RUNNING',
30
+ 5: 'CONTINUE_PENDING',
31
+ 6: 'PAUSE_PENDING',
32
+ 7: 'PAUSED'
33
+ };
34
+ // ─── koffi type definitions ───────────────────────────────────────────────────
35
+ /**
36
+ * SERVICE_STATUS_PROCESS structure (winapi).
37
+ * @see https://learn.microsoft.com/en-us/windows/win32/api/winsvc/ns-winsvc-service_status_process
38
+ */
39
+ const SERVICE_STATUS_PROCESS = koffi_1.default.struct('SERVICE_STATUS_PROCESS', {
40
+ dwServiceType: 'uint32',
41
+ dwCurrentState: 'uint32',
42
+ dwControlsAccepted: 'uint32',
43
+ dwWin32ExitCode: 'uint32',
44
+ dwServiceSpecificExitCode: 'uint32',
45
+ dwCheckPoint: 'uint32',
46
+ dwWaitHint: 'uint32',
47
+ dwProcessId: 'uint32',
48
+ dwServiceFlags: 'uint32'
49
+ });
50
+ // ─── DLL loading (lazy — only executed on Windows at require() time) ──────────
51
+ const advapi32 = koffi_1.default.load('advapi32');
52
+ const kernel32 = koffi_1.default.load('kernel32');
53
+ /**
54
+ * Opens a connection to the service control manager.
55
+ */
56
+ const OpenSCManagerW = advapi32.func('void *OpenSCManagerW(str16 lpMachineName, str16 lpDatabaseName, uint32 dwDesiredAccess)');
57
+ /**
58
+ * Opens an existing service object.
59
+ */
60
+ const OpenServiceW = advapi32.func('void *OpenServiceW(void *hSCManager, str16 lpServiceName, uint32 dwDesiredAccess)');
61
+ /**
62
+ * Retrieves the current status of the specified service.
63
+ */
64
+ const QueryServiceStatusEx = advapi32.func('bool QueryServiceStatusEx(void *hService, int32 InfoLevel, _Out_ SERVICE_STATUS_PROCESS *lpBuffer, uint32 cbBufSize, _Out_ uint32 *pcbBytesNeeded)');
65
+ /** Closes an open handle to a service or the SCM. */
66
+ const CloseServiceHandle = advapi32.func('bool CloseServiceHandle(void *hSCObject)');
67
+ /** Returns the last Win32 error code for the calling thread. */
68
+ const GetLastError = kernel32.func('uint32 GetLastError()');
69
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
70
+ /**
71
+ * Returns true when a koffi pointer value represents a NULL handle.
72
+ */
73
+ function isNullHandle(handle) {
74
+ return handle === null || handle === 0;
75
+ }
76
+ // ─── Public API ───────────────────────────────────────────────────────────────
77
+ /**
78
+ * Checks whether a Windows service exists in the SCM database.
79
+ *
80
+ * @param serviceName - The short name of the service (e.g. "wuauserv").
81
+ * @returns Resolves to `true` if the service exists.
82
+ * @throws If the SCM cannot be opened.
83
+ */
84
+ async function serviceExists(serviceName) {
85
+ if (!serviceName || typeof serviceName !== 'string') {
86
+ throw new TypeError('serviceName must be a non-empty string');
87
+ }
88
+ const hSCM = OpenSCManagerW(null, null, SC_MANAGER_CONNECT);
89
+ if (isNullHandle(hSCM)) {
90
+ throw new Error(`OpenSCManagerW failed (GetLastError=${GetLastError()})`);
91
+ }
92
+ try {
93
+ const hService = OpenServiceW(hSCM, serviceName, SERVICE_QUERY_STATUS);
94
+ if (isNullHandle(hService)) {
95
+ const err = GetLastError();
96
+ if (err === ERROR_SERVICE_DOES_NOT_EXIST) {
97
+ return false;
98
+ }
99
+ throw new Error(`OpenServiceW failed (GetLastError=${err})`);
100
+ }
101
+ CloseServiceHandle(hService);
102
+ return true;
103
+ }
104
+ finally {
105
+ CloseServiceHandle(hSCM);
106
+ }
107
+ }
108
+ /**
109
+ * Returns the current status of a Windows service.
110
+ *
111
+ * @param serviceName - The short name of the service (e.g. "wuauserv").
112
+ * @returns The service status.
113
+ * @throws If the service does not exist or cannot be queried.
114
+ */
115
+ async function getServiceStatus(serviceName) {
116
+ if (!serviceName || typeof serviceName !== 'string') {
117
+ throw new TypeError('serviceName must be a non-empty string');
118
+ }
119
+ const hSCM = OpenSCManagerW(null, null, SC_MANAGER_CONNECT);
120
+ if (isNullHandle(hSCM)) {
121
+ throw new Error(`OpenSCManagerW failed (GetLastError=${GetLastError()})`);
122
+ }
123
+ try {
124
+ const hService = OpenServiceW(hSCM, serviceName, SERVICE_QUERY_STATUS);
125
+ if (isNullHandle(hService)) {
126
+ const err = GetLastError();
127
+ if (err === ERROR_SERVICE_DOES_NOT_EXIST) {
128
+ throw new Error(`Service "${serviceName}" does not exist`);
129
+ }
130
+ throw new Error(`OpenServiceW failed (GetLastError=${err})`);
131
+ }
132
+ try {
133
+ const statusBuf = {};
134
+ const bytesNeeded = [0];
135
+ const ok = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, statusBuf, koffi_1.default.sizeof(SERVICE_STATUS_PROCESS), bytesNeeded);
136
+ if (!ok) {
137
+ throw new Error(`QueryServiceStatusEx failed (GetLastError=${GetLastError()})`);
138
+ }
139
+ const stateCode = statusBuf.dwCurrentState;
140
+ return {
141
+ name: serviceName,
142
+ exists: true,
143
+ state: SERVICE_STATES[stateCode] || `UNKNOWN(${stateCode})`,
144
+ pid: statusBuf.dwProcessId,
145
+ rawCode: stateCode
146
+ };
147
+ }
148
+ finally {
149
+ CloseServiceHandle(hService);
150
+ }
151
+ }
152
+ finally {
153
+ CloseServiceHandle(hSCM);
154
+ }
155
+ }
156
+ //# sourceMappingURL=windows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows.js","sourceRoot":"","sources":["../../src/windows.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.test.d.ts","sourceRoot":"","sources":["../../test/service.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,227 @@
1
+ 'use strict';
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ /**
37
+ * Tests for the Linux implementation (src/linux.ts).
38
+ * These tests mock child_process.execFile and fs.promises.access to avoid
39
+ * requiring a real system service manager.
40
+ */
41
+ const node_test_1 = require("node:test");
42
+ const assert = __importStar(require("node:assert/strict"));
43
+ // ─── Tests ───────────────────────────────────────────────────────────────────
44
+ (0, node_test_1.describe)('Linux implementation — serviceExists', () => {
45
+ (0, node_test_1.it)('returns true for an existing systemd service', async () => {
46
+ const cp = require('child_process');
47
+ const orig = cp.execFile;
48
+ let callCount = 0;
49
+ cp.execFile = function (cmd, args, opts, cb) {
50
+ callCount++;
51
+ if (callCount === 1) {
52
+ // isSystemd() probe
53
+ cb(null, 'systemd 252\n', '');
54
+ }
55
+ else {
56
+ // querySystemd — service is loaded and running
57
+ cb(null, 'LoadState=loaded\nActiveState=active\nSubState=running\nMainPID=1234\n', '');
58
+ }
59
+ return { kill: () => { } };
60
+ };
61
+ try {
62
+ delete require.cache[require.resolve('../src/linux')];
63
+ const { serviceExists } = require('../src/linux');
64
+ const result = await serviceExists('nginx');
65
+ assert.equal(result, true);
66
+ }
67
+ finally {
68
+ cp.execFile = orig;
69
+ delete require.cache[require.resolve('../src/linux')];
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');
90
+ const result = await serviceExists('doesnotexist');
91
+ 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);
104
+ });
105
+ });
106
+ (0, node_test_1.describe)('Linux implementation — getServiceStatus', () => {
107
+ (0, node_test_1.it)('returns RUNNING status for an active service', async () => {
108
+ const cp = require('child_process');
109
+ const orig = cp.execFile;
110
+ let callCount = 0;
111
+ cp.execFile = function (cmd, args, opts, cb) {
112
+ callCount++;
113
+ if (callCount === 1) {
114
+ cb(null, 'systemd 252\n', '');
115
+ }
116
+ else {
117
+ cb(null, 'LoadState=loaded\nActiveState=active\nSubState=running\nMainPID=4321\n', '');
118
+ }
119
+ return { kill: () => { } };
120
+ };
121
+ try {
122
+ delete require.cache[require.resolve('../src/linux')];
123
+ const { getServiceStatus } = require('../src/linux');
124
+ const status = await getServiceStatus('sshd');
125
+ assert.equal(status.name, 'sshd');
126
+ assert.equal(status.exists, true);
127
+ assert.equal(status.state, 'RUNNING');
128
+ assert.equal(status.pid, 4321);
129
+ assert.equal(status.rawCode, 'active');
130
+ }
131
+ finally {
132
+ cp.execFile = orig;
133
+ delete require.cache[require.resolve('../src/linux')];
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');
153
+ const status = await getServiceStatus('nginx');
154
+ assert.equal(status.state, 'STOPPED');
155
+ assert.equal(status.pid, 0);
156
+ }
157
+ finally {
158
+ cp.execFile = orig;
159
+ delete require.cache[require.resolve('../src/linux')];
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');
204
+ await assert.rejects(() => getServiceStatus('ghost'), (err) => err.message.includes('does not exist'));
205
+ }
206
+ finally {
207
+ cp.execFile = orig;
208
+ delete require.cache[require.resolve('../src/linux')];
209
+ }
210
+ });
211
+ (0, node_test_1.it)('throws TypeError for invalid serviceName', async () => {
212
+ delete require.cache[require.resolve('../src/linux')];
213
+ const { getServiceStatus } = require('../src/linux');
214
+ await assert.rejects(() => getServiceStatus(''), TypeError);
215
+ await assert.rejects(() => getServiceStatus(undefined), TypeError);
216
+ });
217
+ });
218
+ (0, node_test_1.describe)('index.ts — module contract', () => {
219
+ (0, node_test_1.it)('exports serviceExists and getServiceStatus functions', () => {
220
+ // On Linux (our CI), the main index loads linux.
221
+ delete require.cache[require.resolve('../index')];
222
+ const api = require('../index');
223
+ assert.equal(typeof api.serviceExists, 'function');
224
+ assert.equal(typeof api.getServiceStatus, 'function');
225
+ });
226
+ });
227
+ //# sourceMappingURL=service.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.test.js","sourceRoot":"","sources":["../../test/service.test.ts"],"names":[],"mappings":"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"}