@push.rocks/smartdaemon 2.2.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.smartconfig.json CHANGED
@@ -19,18 +19,37 @@
19
19
  ]
20
20
  },
21
21
  "release": {
22
- "registries": [
23
- "https://verdaccio.lossless.digital",
24
- "https://registry.npmjs.org"
25
- ],
26
- "accessLevel": "public"
27
- }
22
+ "preflight": {
23
+ "test": true,
24
+ "build": true
25
+ },
26
+ "targets": {
27
+ "git": {
28
+ "enabled": true,
29
+ "remote": "origin",
30
+ "pushBranch": true,
31
+ "pushTags": true
32
+ },
33
+ "npm": {
34
+ "enabled": true,
35
+ "registries": [
36
+ "https://verdaccio.lossless.digital",
37
+ "https://registry.npmjs.org"
38
+ ],
39
+ "accessLevel": "public",
40
+ "alreadyPublished": "success"
41
+ },
42
+ "docker": {
43
+ "enabled": false
44
+ }
45
+ }
46
+ },
47
+ "schemaVersion": 2
28
48
  },
29
49
  "@git.zone/tsdoc": {
30
50
  "legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
31
51
  },
32
52
  "@ship.zone/szci": {
33
- "npmGlobalTools": [],
34
- "npmRegistryUrl": "registry.npmjs.org"
53
+ "npmGlobalTools": []
35
54
  }
36
55
  }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartdaemon',
6
- version: '2.2.0',
6
+ version: '2.4.0',
7
7
  description: 'Start scripts as long running daemons and manage them.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx5QkFBeUI7SUFDL0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLHdEQUF3RDtDQUN0RSxDQUFBIn0=
@@ -0,0 +1,22 @@
1
+ export interface ISystemdServiceDefinitionOptions {
2
+ unitName: string;
3
+ description: string;
4
+ executable: string;
5
+ args: readonly string[];
6
+ workingDirectory: string;
7
+ user: string;
8
+ group: string;
9
+ restart: 'no' | 'on-failure' | 'always';
10
+ killMode: 'mixed' | 'control-group';
11
+ timeoutStopSeconds: number;
12
+ }
13
+ export declare class SystemdServiceDefinitionError extends Error {
14
+ constructor();
15
+ }
16
+ /** Literal direct-execution definition; never introduces a shell or environment expansion. */
17
+ export declare class SystemdServiceDefinition {
18
+ readonly unitName: string;
19
+ readonly content: string;
20
+ readonly sha256: string;
21
+ constructor(options: ISystemdServiceDefinitionOptions);
22
+ }
@@ -0,0 +1,93 @@
1
+ import * as plugins from './smartdaemon.plugins.js';
2
+ export class SystemdServiceDefinitionError extends Error {
3
+ constructor() {
4
+ super('Invalid direct systemd service definition.');
5
+ this.name = 'SystemdServiceDefinitionError';
6
+ }
7
+ }
8
+ /** Literal direct-execution definition; never introduces a shell or environment expansion. */
9
+ export class SystemdServiceDefinition {
10
+ constructor(options) {
11
+ const requireValue = (value) => {
12
+ if (!value)
13
+ throw new SystemdServiceDefinitionError();
14
+ };
15
+ const text = (value, maximum = 4096) => typeof value === 'string' && value.length <= maximum && !/[\x00-\x1f\x7f]/.test(value) &&
16
+ !/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/u.test(value);
17
+ const absolute = (value) => text(value) && plugins.path.isAbsolute(value) &&
18
+ plugins.path.normalize(value) === value;
19
+ const keys = [
20
+ 'unitName',
21
+ 'description',
22
+ 'executable',
23
+ 'args',
24
+ 'workingDirectory',
25
+ 'user',
26
+ 'group',
27
+ 'restart',
28
+ 'killMode',
29
+ 'timeoutStopSeconds',
30
+ ];
31
+ requireValue(options && Object.getPrototypeOf(options) === Object.prototype &&
32
+ Reflect.ownKeys(options).length === keys.length && keys.every((key) => {
33
+ const descriptor = Object.getOwnPropertyDescriptor(options, key);
34
+ return descriptor && 'value' in descriptor;
35
+ }));
36
+ requireValue(typeof options.unitName === 'string' &&
37
+ /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,230}\.service$/.test(options.unitName));
38
+ requireValue(text(options.description, 1024) && options.description.length > 0 &&
39
+ options.description.trim() === options.description && !options.description.includes('\\'));
40
+ requireValue(absolute(options.executable) && options.executable !== '/' &&
41
+ !/[\\"']/.test(options.executable) && !options.executable.endsWith('/') &&
42
+ absolute(options.workingDirectory) &&
43
+ options.workingDirectory.trim() === options.workingDirectory &&
44
+ !options.workingDirectory.includes('\\'));
45
+ requireValue(Array.isArray(options.args) && Object.getPrototypeOf(options.args) === Array.prototype &&
46
+ options.args.length <= 128 &&
47
+ Reflect.ownKeys(options.args).length === options.args.length + 1 &&
48
+ Array.from({ length: options.args.length }, (_, index) => Object.getOwnPropertyDescriptor(options.args, String(index)))
49
+ .every((descriptor) => descriptor && 'value' in descriptor && text(descriptor.value)));
50
+ requireValue([options.user, options.group].every((value) => typeof value === 'string' && /^[a-zA-Z_][a-zA-Z0-9_-]{0,63}$/.test(value)));
51
+ requireValue(['no', 'on-failure', 'always'].includes(options.restart) &&
52
+ ['mixed', 'control-group'].includes(options.killMode) &&
53
+ Number.isSafeInteger(options.timeoutStopSeconds) &&
54
+ options.timeoutStopSeconds >= 1 && options.timeoutStopSeconds <= 600);
55
+ // Quoting and percent/dollar escaping follow systemd.syntax and systemd.service.
56
+ const quote = (value, command = false) => '"' + value
57
+ .replaceAll('\\', '\\\\').replaceAll('"', '\\"').replaceAll('%', '%%')
58
+ .replaceAll('$', () => command ? '$$' : '$') +
59
+ '"';
60
+ this.unitName = options.unitName;
61
+ this.content = [
62
+ '[Unit]',
63
+ `Description=${options.description.replaceAll('%', '%%')}`,
64
+ 'After=local-fs.target',
65
+ '',
66
+ '[Service]',
67
+ 'Type=exec',
68
+ `User=${options.user}`,
69
+ `Group=${options.group}`,
70
+ `ExecStart=${[quote(options.executable), ...options.args.map((value) => quote(value, true))].join(' ')}`,
71
+ // WorkingDirectory is a raw path value, not an ExecStart word list.
72
+ `WorkingDirectory=${options.workingDirectory.replaceAll('%', '%%')}`,
73
+ `Restart=${options.restart}`,
74
+ `KillMode=${options.killMode}`,
75
+ 'KillSignal=SIGTERM',
76
+ 'FinalKillSignal=SIGKILL',
77
+ 'SendSIGKILL=yes',
78
+ 'SendSIGHUP=no',
79
+ `TimeoutStopSec=${options.timeoutStopSeconds}s`,
80
+ 'StandardInput=null',
81
+ 'StandardOutput=journal',
82
+ 'StandardError=journal',
83
+ '',
84
+ '[Install]',
85
+ 'WantedBy=multi-user.target',
86
+ '',
87
+ ].join('\n');
88
+ requireValue(Buffer.byteLength(this.content) <= 16384);
89
+ this.sha256 = plugins.crypto.createHash('sha256').update(this.content).digest('hex');
90
+ Object.freeze(this);
91
+ }
92
+ }
93
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zeXN0ZW1kc2VydmljZWRlZmluaXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLnN5c3RlbWRzZXJ2aWNlZGVmaW5pdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLDBCQUEwQixDQUFDO0FBZXBELE1BQU0sT0FBTyw2QkFBOEIsU0FBUSxLQUFLO0lBQ3REO1FBQ0UsS0FBSyxDQUFDLDRDQUE0QyxDQUFDLENBQUM7UUFDcEQsSUFBSSxDQUFDLElBQUksR0FBRywrQkFBK0IsQ0FBQztJQUM5QyxDQUFDO0NBQ0Y7QUFFRCw4RkFBOEY7QUFDOUYsTUFBTSxPQUFPLHdCQUF3QjtJQUtuQyxZQUFZLE9BQXlDO1FBQ25ELE1BQU0sWUFBWSxHQUFHLENBQUMsS0FBYyxFQUFRLEVBQUU7WUFDNUMsSUFBSSxDQUFDLEtBQUs7Z0JBQUUsTUFBTSxJQUFJLDZCQUE2QixFQUFFLENBQUM7UUFDeEQsQ0FBQyxDQUFDO1FBQ0YsTUFBTSxJQUFJLEdBQUcsQ0FBQyxLQUFjLEVBQUUsT0FBTyxHQUFHLElBQUksRUFBbUIsRUFBRSxDQUMvRCxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE1BQU0sSUFBSSxPQUFPLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDO1lBQ3RGLENBQUMseUVBQXlFLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3pGLE1BQU0sUUFBUSxHQUFHLENBQUMsS0FBYyxFQUFFLEVBQUUsQ0FDbEMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQztZQUM3QyxPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsS0FBSyxLQUFLLENBQUM7UUFDMUMsTUFBTSxJQUFJLEdBQUc7WUFDWCxVQUFVO1lBQ1YsYUFBYTtZ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
@@ -0,0 +1,49 @@
1
+ export interface ISystemdUnitOptions {
2
+ unitName: string;
3
+ /** Absolute executable path supplied by trusted owning code. */
4
+ systemctlPath?: string;
5
+ /** Bounds the systemctl client, not the server-side job. Defaults to 120 seconds. */
6
+ commandTimeoutMs?: number;
7
+ }
8
+ export interface ISystemdUnitState {
9
+ readonly unitName: string;
10
+ readonly loadState: string;
11
+ readonly activeState: string;
12
+ readonly subState: string;
13
+ readonly unitFileState: string;
14
+ readonly mainPid: number;
15
+ readonly controlPid: number;
16
+ readonly controlGroup: string;
17
+ readonly killMode: string;
18
+ /** Empty when no systemd job is pending; otherwise systemctl's job description. */
19
+ readonly job: string;
20
+ }
21
+ export interface ISystemdUnitConfigurationState {
22
+ readonly unitName: string;
23
+ readonly fragmentPath: string;
24
+ /** Opaque systemctl path list. An empty value proves no effective drop-ins. */
25
+ readonly dropInPaths: string;
26
+ readonly needsReload: boolean;
27
+ }
28
+ export declare class SystemdUnitError extends Error {
29
+ readonly code: 'invalid_options' | 'command_failed' | 'invalid_state';
30
+ constructor(code: 'invalid_options' | 'command_failed' | 'invalid_state');
31
+ }
32
+ /** Controls an existing system unit without creating files, changing enablement or escalating privileges. */
33
+ export declare class SystemdUnit {
34
+ private readonly unitName;
35
+ private readonly executable;
36
+ private readonly timeout;
37
+ constructor(optionsArg: ISystemdUnitOptions);
38
+ /** Snapshot only. Callers own application-specific admission and restart policy. */
39
+ inspect(): Promise<ISystemdUnitState>;
40
+ /** Await the systemd job, then inspect. This does not enable or unmask the unit. */
41
+ start(): Promise<ISystemdUnitState>;
42
+ /** Await the systemd job, then inspect. The snapshot alone is not an application data-drain proof. */
43
+ stop(): Promise<ISystemdUnitState>;
44
+ /** Reports the manager's selected definition without reading or changing its contents. */
45
+ inspectConfiguration(): Promise<ISystemdUnitConfigurationState>;
46
+ /** Reloads unit definitions globally; does not enable, unmask, start or stop a unit. */
47
+ reloadConfiguration(): Promise<ISystemdUnitConfigurationState>;
48
+ private command;
49
+ }
@@ -0,0 +1,125 @@
1
+ import * as plugins from './smartdaemon.plugins.js';
2
+ export class SystemdUnitError extends Error {
3
+ constructor(code) {
4
+ super(`Systemd unit operation failed: ${code}.`);
5
+ this.code = code;
6
+ this.name = 'SystemdUnitError';
7
+ }
8
+ }
9
+ const properties = [
10
+ 'Id',
11
+ 'LoadState',
12
+ 'ActiveState',
13
+ 'SubState',
14
+ 'UnitFileState',
15
+ 'MainPID',
16
+ 'ControlPID',
17
+ 'ControlGroup',
18
+ 'KillMode',
19
+ 'Job',
20
+ ];
21
+ /** Controls an existing system unit without creating files, changing enablement or escalating privileges. */
22
+ export class SystemdUnit {
23
+ constructor(optionsArg) {
24
+ this.unitName = optionsArg?.unitName;
25
+ this.executable = optionsArg?.systemctlPath ?? '/usr/bin/systemctl';
26
+ this.timeout = optionsArg?.commandTimeoutMs ?? 120000;
27
+ if (typeof this.unitName !== 'string' ||
28
+ !/^[a-zA-Z0-9][a-zA-Z0-9_.:@-]{0,230}\.service$/.test(this.unitName) ||
29
+ typeof this.executable !== 'string' || !plugins.path.isAbsolute(this.executable) ||
30
+ this.executable.includes('\0') || !Number.isSafeInteger(this.timeout) ||
31
+ this.timeout < 1 || this.timeout > 600000)
32
+ throw new SystemdUnitError('invalid_options');
33
+ }
34
+ /** Snapshot only. Callers own application-specific admission and restart policy. */
35
+ async inspect() {
36
+ const stdout = await this.command([
37
+ 'show',
38
+ this.unitName,
39
+ `--property=${properties.join(',')}`,
40
+ '--all',
41
+ ]);
42
+ const fields = new Map();
43
+ for (const line of stdout.trimEnd().split('\n')) {
44
+ const separator = line.indexOf('=');
45
+ const key = line.slice(0, separator);
46
+ if (separator < 1 || !properties.includes(key) || fields.has(key)) {
47
+ throw new SystemdUnitError('invalid_state');
48
+ }
49
+ fields.set(key, line.slice(separator + 1));
50
+ }
51
+ if (fields.size !== properties.length || fields.get('Id') !== this.unitName ||
52
+ ['LoadState', 'ActiveState', 'SubState'].some((key) => !fields.get(key)) ||
53
+ ['MainPID', 'ControlPID'].some((key) => !/^(0|[1-9]\d*)$/.test(fields.get(key)) || !Number.isSafeInteger(Number(fields.get(key)))))
54
+ throw new SystemdUnitError('invalid_state');
55
+ return Object.freeze({
56
+ unitName: this.unitName,
57
+ loadState: fields.get('LoadState'),
58
+ activeState: fields.get('ActiveState'),
59
+ subState: fields.get('SubState'),
60
+ unitFileState: fields.get('UnitFileState'),
61
+ mainPid: Number(fields.get('MainPID')),
62
+ controlPid: Number(fields.get('ControlPID')),
63
+ controlGroup: fields.get('ControlGroup'),
64
+ killMode: fields.get('KillMode'),
65
+ job: fields.get('Job'),
66
+ });
67
+ }
68
+ /** Await the systemd job, then inspect. This does not enable or unmask the unit. */
69
+ async start() {
70
+ await this.command(['start', this.unitName]);
71
+ return this.inspect();
72
+ }
73
+ /** Await the systemd job, then inspect. The snapshot alone is not an application data-drain proof. */
74
+ async stop() {
75
+ await this.command(['stop', this.unitName]);
76
+ return this.inspect();
77
+ }
78
+ /** Reports the manager's selected definition without reading or changing its contents. */
79
+ async inspectConfiguration() {
80
+ const keys = ['Id', 'FragmentPath', 'DropInPaths', 'NeedDaemonReload'];
81
+ const stdout = await this.command(['show', this.unitName, `--property=${keys.join(',')}`, '--all']);
82
+ const fields = new Map();
83
+ for (const line of stdout.trimEnd().split('\n')) {
84
+ const separator = line.indexOf('='), key = line.slice(0, separator);
85
+ if (separator < 1 || !keys.includes(key) || fields.has(key)) {
86
+ throw new SystemdUnitError('invalid_state');
87
+ }
88
+ fields.set(key, line.slice(separator + 1));
89
+ }
90
+ if (fields.size !== keys.length || fields.get('Id') !== this.unitName ||
91
+ !['yes', 'no'].includes(fields.get('NeedDaemonReload'))) {
92
+ throw new SystemdUnitError('invalid_state');
93
+ }
94
+ return Object.freeze({
95
+ unitName: this.unitName,
96
+ fragmentPath: fields.get('FragmentPath'),
97
+ dropInPaths: fields.get('DropInPaths'),
98
+ needsReload: fields.get('NeedDaemonReload') === 'yes',
99
+ });
100
+ }
101
+ /** Reloads unit definitions globally; does not enable, unmask, start or stop a unit. */
102
+ async reloadConfiguration() {
103
+ await this.command(['daemon-reload']);
104
+ return this.inspectConfiguration();
105
+ }
106
+ command(argsArg) {
107
+ return new Promise((resolve, reject) => {
108
+ plugins.childProcess.execFile(this.executable, ['--system', '--no-ask-password', '--no-pager', ...argsArg], {
109
+ encoding: 'utf8',
110
+ timeout: this.timeout,
111
+ killSignal: 'SIGKILL',
112
+ maxBuffer: 16384,
113
+ windowsHide: true,
114
+ env: { PATH: '/usr/bin:/bin', LANG: 'C', LC_ALL: 'C' },
115
+ }, (error, stdout) => {
116
+ // execFile settles after the client closes. A timed-out client's remote job may continue.
117
+ if (error)
118
+ reject(new SystemdUnitError('command_failed'));
119
+ else
120
+ resolve(stdout);
121
+ });
122
+ });
123
+ }
124
+ }
125
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zeXN0ZW1kdW5pdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMuc3lzdGVtZHVuaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQWdDcEQsTUFBTSxPQUFPLGdCQUFpQixTQUFRLEtBQUs7SUFDekMsWUFBNEIsSUFBNEQ7UUFDdEYsS0FBSyxDQUFDLGtDQUFrQyxJQUFJLEdBQUcsQ0FBQyxDQUFDO1FBRHZCLFNBQUksR0FBSixJQUFJLENBQXdEO1FBRXRGLElBQUksQ0FBQyxJQUFJLEdBQUcsa0JBQWtCLENBQUM7SUFDakMsQ0FBQztDQUNGO0FBRUQsTUFBTSxVQUFVLEdBQUc7SUFDakIsSUFBSTtJQUNKLFdBQVc7SUFDWCxhQUFhO0lBQ2IsVUFBVTtJQUNWLGVBQWU7SUFDZixTQUFTO0lBQ1QsWUFBWTtJQUNaLGNBQWM7SUFDZCxVQUFVO0lBQ1YsS0FBSztDQUNHLENBQUM7QUFFWCw2R0FBNkc7QUFDN0csTUFBTSxPQUFPLFdBQVc7SUFLdEIsWUFBWSxVQUErQjtRQUN6QyxJQUFJLENBQUMsUUFBUSxHQUFHLFVBQVUsRUFBRSxRQUFRLENBQUM7UUFDckMsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLEVBQUUsYUFBYSxJQUFJLG9CQUFvQixDQUFDO1FBQ3BFLElBQUksQ0FBQyxPQUFPLEdBQUcsVUFBVSxFQUFFLGdCQUFnQixJQUFJLE1BQU0sQ0FBQztRQUN0RCxJQUNFLE9BQU8sSUFBSSxDQUFDLFFBQVEsS0FBSyxRQUFRO1lBQ2pDLENBQUMsK0NBQStDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUM7WUFDcEUsT0FBTyxJQUFJLENBQUMsVUFBVSxLQUFLLFFBQVEsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7WUFDaEYsSUFBSSxDQUFDLFVBQVUsQ0FBQyxR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
@@ -0,0 +1,45 @@
1
+ import { SystemdServiceDefinition } from './classes.systemdservicedefinition.js';
2
+ import { type ISystemdUnitOptions } from './classes.systemdunit.js';
3
+ export interface ISystemdUnitFileOptions extends ISystemdUnitOptions {
4
+ /** Local vendor definitions can be installed without removing an administrator's mask. */
5
+ unitDirectory?: string;
6
+ /** Trusted owning-code qualification only. Defaults to root. */
7
+ expectedUid?: number;
8
+ }
9
+ export interface ISystemdUnitFileRecord {
10
+ readonly path: string;
11
+ readonly sha256: string;
12
+ }
13
+ export declare class SystemdUnitFileError extends Error {
14
+ readonly code: 'invalid_options' | 'unsafe_path' | 'busy' | 'changed' | 'unsafe_unit' | 'write_failed' | 'reload_failed';
15
+ constructor(code: 'invalid_options' | 'unsafe_path' | 'busy' | 'changed' | 'unsafe_unit' | 'write_failed' | 'reload_failed');
16
+ }
17
+ /**
18
+ * Protected code/config installation, inside the caller's cross-process installation ownership scope.
19
+ * Other privileged writers must be serialized by that owner. Never changes enablement or masks.
20
+ */
21
+ export declare class SystemdUnitFile {
22
+ readonly path: string;
23
+ private readonly directory;
24
+ private readonly uid;
25
+ private readonly unit;
26
+ private readonly name;
27
+ private busy;
28
+ constructor(options: ISystemdUnitFileOptions);
29
+ /** Reads only the exact protected definition; no systemd or filesystem mutation. */
30
+ inspect(): Promise<ISystemdUnitFileRecord | null>;
31
+ /**
32
+ * Expected previous digest is mandatory; null admits an absent file. Exact desired bytes are idempotent.
33
+ * Retains changed definitions beside the unit before replacement. A failed reload never rolls code back.
34
+ */
35
+ install(definition: SystemdServiceDefinition, expectedSha256: string | null): Promise<Readonly<{
36
+ changed: boolean;
37
+ record: ISystemdUnitFileRecord;
38
+ masked: boolean;
39
+ }>>;
40
+ private admit;
41
+ private directories;
42
+ private read;
43
+ private create;
44
+ private flushDirectory;
45
+ }