systemd-ts 0.1.1 → 0.2.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 CHANGED
@@ -5,7 +5,7 @@ services and timers from TypeScript.
5
5
 
6
6
  ## Usage
7
7
 
8
- The example below installs a user-scoped service and timer for a small
8
+ The example below materializes a user-scoped service and timer for a small
9
9
  nightly backup job. The service does the work, the timer schedules it, and
10
10
  `Systemd` writes both unit files before enabling and starting the timer.
11
11
 
@@ -49,15 +49,26 @@ const systemd = new Systemd({
49
49
  linkUnits: true,
50
50
  });
51
51
 
52
- const installed = await systemd.install(service, timer);
52
+ const materialized = await systemd.materialize(service, timer);
53
+ if (!materialized.ok) {
54
+ throw materialized.error;
55
+ }
53
56
 
54
- console.log(installed.pathFor(service));
55
- console.log(installed.pathFor(timer));
57
+ console.log(systemd.pathFor(service));
58
+ console.log(systemd.pathFor(timer));
59
+ console.log(materialized.value.materialized);
56
60
 
57
- await systemd.enable(timer);
58
- await systemd.start(timer);
61
+ const enabled = await systemd.enable(timer);
62
+ if (!enabled.ok) {
63
+ throw enabled.error;
64
+ }
65
+
66
+ const started = await systemd.start(timer);
67
+ if (!started.ok) {
68
+ throw started.error;
69
+ }
59
70
  ```
60
71
 
61
- That will write `backup-db.service` and `backup-db.timer` into the user's unit
62
- directory, enable the timer under `timers.target`, and ask `systemd --user` to
63
- start waiting for the first scheduled run.
72
+ That will materialize `backup-db.service` and `backup-db.timer` into the user's
73
+ unit directory, enable the timer under `timers.target`, and ask `systemd --user`
74
+ to start waiting for the first scheduled run.
package/dist/index.d.mts CHANGED
@@ -1,3 +1,96 @@
1
+ declare namespace internal_d_exports {
2
+ export { Result, cloneUnitSection, defaultCommandExecutor, defaultUnitDirForScope, fileExists, freezeUnitOptions, normalizeUnitName, parseStartStatus, renderUnitFile, resolveTimerTargetUnit, sendNotify, shellQuote, validateServiceSection };
3
+ }
4
+ type Result<TValue, TError> = {
5
+ readonly ok: true;
6
+ readonly value: TValue;
7
+ } | {
8
+ readonly ok: false;
9
+ readonly error: TError;
10
+ };
11
+ type SectionLike = object;
12
+ declare function normalizeUnitName(name: string, suffix: `.service` | `.timer`): string;
13
+ declare function resolveTimerTargetUnit(options: SystemdTimerOptions): string;
14
+ declare function defaultUnitDirForScope(scope: `system` | `user`): string;
15
+ declare function freezeUnitOptions<TOptions extends SystemdServiceOptions | SystemdTimerOptions>(options: TOptions): Readonly<TOptions>;
16
+ declare function cloneUnitSection<TSection extends SectionLike | undefined>(section: TSection): TSection;
17
+ declare function validateServiceSection(service: SystemdServiceSection): Result<void, InvalidExecDirectiveError>;
18
+ declare function parseStartStatus(unit: string, output: string): StartStatus;
19
+ declare function renderUnitFile(sections: ReadonlyArray<readonly [string, SectionLike | undefined]>): Result<string, ExecutableInferenceError>;
20
+ declare function shellQuote(value: string): string;
21
+ declare function defaultCommandExecutor(command: string, args: readonly string[]): Promise<CommandOutput>;
22
+ declare function fileExists(path: string): Promise<boolean>;
23
+ declare function sendNotify(state: `READY=1` | `WATCHDOG=1`, options: NotifyOptions): Promise<void>;
24
+ //#endregion
25
+ //#region src/main/executable.d.ts
26
+ /**
27
+ * An immutable description of a runnable module entrypoint that can be used in
28
+ * executable-valued systemd unit directives.
29
+ *
30
+ * `Executable` captures three pieces of information:
31
+ * - the absolute runtime binary that should launch the module
32
+ * - the absolute path to the module itself
33
+ * - any additional arguments that should be passed after the module path
34
+ *
35
+ * Most consumers will create one via {@link defineExecutable} and then pass it
36
+ * into a {@link SystemdService} directive such as `ExecStart`, `ExecStop`, or
37
+ * `ExecReload`.
38
+ */
39
+ declare class Executable {
40
+ /** Additional arguments passed after the module path. */
41
+ readonly args: readonly string[];
42
+ /** Inference issue captured when no explicit module path was provided. */
43
+ readonly inferenceError: ExecutableInferenceError | undefined;
44
+ /** Absolute path to the module that should be executed. */
45
+ readonly modulePath: string;
46
+ /** Absolute path to the runtime binary that should launch the module. */
47
+ readonly runtimeEntrypoint: string;
48
+ /**
49
+ * Creates an executable description.
50
+ *
51
+ * When `modulePath` is omitted, the calling module is inferred from the
52
+ * current stack so `defineExecutable()` can be used inline from the module
53
+ * that should become runnable.
54
+ *
55
+ * When `runtimeEntrypoint` is omitted, the current process executable is
56
+ * used. This works well for the common case where the same runtime that is
57
+ * evaluating your module should also be used by systemd.
58
+ */
59
+ constructor(options?: ExecutableOptions);
60
+ /**
61
+ * Returns the executable as raw command parts.
62
+ *
63
+ * The first element is always the runtime entrypoint, followed by the module
64
+ * path and any configured arguments.
65
+ */
66
+ toCommandParts(): Result<readonly [string, ...string[]], ExecutableInferenceError>;
67
+ /**
68
+ * Renders the executable as a shell-quoted command string suitable for
69
+ * executable-valued systemd directives such as `ExecStart=`.
70
+ */
71
+ toExecStart(): Result<string, ExecutableInferenceError>;
72
+ }
73
+ /**
74
+ * Defines a module as a runnable executable and returns its immutable
75
+ * `Executable` description.
76
+ *
77
+ * This helper is designed for the pattern:
78
+ *
79
+ * ```ts
80
+ * export default defineExecutable(async () => {
81
+ * // do work here
82
+ * });
83
+ * ```
84
+ *
85
+ * When the defining module is executed as the main entrypoint, `fn` is invoked.
86
+ * When the module is merely imported, `fn` is not run and only the executable
87
+ * description is returned.
88
+ *
89
+ * Pass `options.runtimeEntrypoint` to override the default runtime binary when
90
+ * the current process is not the exact runtime you want systemd to use.
91
+ */
92
+ declare function defineExecutable(fn: () => void | Promise<void>, options?: ExecutableOptions): Executable;
93
+ //#endregion
1
94
  //#region src/main/systemd-service.d.ts
2
95
  /**
3
96
  * An immutable definition of a `.service` unit.
@@ -38,7 +131,7 @@ declare class SystemdService<const TOptions extends SystemdServiceOptions = Syst
38
131
  * and `ExecStop`, ensuring they use absolute runtime entrypoints as required
39
132
  * by systemd.
40
133
  */
41
- render(): string;
134
+ render(): Result<string, ExecutableInferenceError | InvalidExecDirectiveError>;
42
135
  }
43
136
  //#endregion
44
137
  //#region src/main/systemd-timer.d.ts
@@ -77,7 +170,7 @@ declare class SystemdTimer<const TOptions extends SystemdTimerOptions = SystemdT
77
170
  /** The canonical unit filename, including the `.timer` suffix. */
78
171
  get filename(): TimerFilename<TOptions[`name`]>;
79
172
  /** Renders the timer as a complete unit file. */
80
- render(): string;
173
+ render(): Result<string, ExecutableInferenceError>;
81
174
  }
82
175
  //#endregion
83
176
  //#region src/main/types.d.ts
@@ -963,14 +1056,6 @@ interface SystemdServiceSection extends CustomDirectiveSection {
963
1056
  /** Takes a directory path relative to the service's root directory specified by RootDirectory=, or the special value ~. Sets the working directory for executed processes. If set to ~, the home directory of the user specified in User= is used. If not set, defaults to the root directory when systemd is running as a system instance and the respective user's home directory if run as user. If the setting is prefixed with the - character, a missing working directory is not considered fatal. If RootDirectory=/RootImage= is not set, then WorkingDirectory= is relative to the root of the system running the service manager. Note that setting this parameter might result in additional dependencies to be added to the unit (see above). Source: systemd v260.1, `systemd.exec(5)`. */
964
1057
  readonly WorkingDirectory?: string;
965
1058
  }
966
- /**
967
- * @deprecated Use one of the specific section interfaces instead:
968
- * `SystemdUnitSection`, `SystemdInstallSection`, `SystemdServiceSection`, or
969
- * `SystemdTimerSection`.
970
- */
971
- interface UnitSection {
972
- readonly [key: string]: UnitSectionValue;
973
- }
974
1059
  interface SystemdServiceOptions {
975
1060
  readonly install?: SystemdInstallSection;
976
1061
  readonly name: string;
@@ -1001,11 +1086,11 @@ interface SystemdOptions {
1001
1086
  readonly scope?: `system` | `user`;
1002
1087
  readonly unitDir?: string;
1003
1088
  }
1004
- interface CommandResult {
1089
+ interface CommandOutput {
1005
1090
  readonly stderr: string;
1006
1091
  readonly stdout: string;
1007
1092
  }
1008
- type CommandExecutor = (command: string, args: readonly string[]) => Promise<CommandResult>;
1093
+ type CommandExecutor = (command: string, args: readonly string[]) => Promise<CommandOutput>;
1009
1094
  interface LogsOptions {
1010
1095
  readonly lines?: number;
1011
1096
  }
@@ -1015,7 +1100,7 @@ interface NotifyOptions {
1015
1100
  readonly socketPath?: string;
1016
1101
  readonly status?: string;
1017
1102
  }
1018
- interface StartResult {
1103
+ interface StartStatus {
1019
1104
  readonly activeState: string;
1020
1105
  readonly execMainStatus: number | undefined;
1021
1106
  readonly result: string;
@@ -1040,7 +1125,7 @@ type IsWideString<Value extends string> = string extends Value ? true : false;
1040
1125
  type AnySystemdService = SystemdService<SystemdServiceOptions>;
1041
1126
  type AnySystemdTimer = SystemdTimer<SystemdTimerOptions>;
1042
1127
  type SystemdUnit = AnySystemdService | AnySystemdTimer;
1043
- interface InstalledUnit<TUnit extends SystemdUnit = SystemdUnit> {
1128
+ interface MaterializedUnit<TUnit extends SystemdUnit = SystemdUnit> {
1044
1129
  readonly path: string;
1045
1130
  readonly unit: TUnit;
1046
1131
  }
@@ -1051,72 +1136,115 @@ type HasServices<TUnits extends readonly SystemdUnit[]> = [ServiceNamesIn<TUnits
1051
1136
  type HasMismatchedServiceTimerPairs<TUnits extends readonly SystemdUnit[]> = HasServices<TUnits> extends true ? [MismatchedTimers<TUnits>] extends [never] ? false : true : false;
1052
1137
  type ValidInstallUnits<TUnits extends readonly SystemdUnit[]> = HasMismatchedServiceTimerPairs<TUnits> extends true ? never : TUnits;
1053
1138
  //#endregion
1054
- //#region src/main/executable.d.ts
1055
- /**
1056
- * An immutable description of a runnable module entrypoint that can be used in
1057
- * executable-valued systemd unit directives.
1058
- *
1059
- * `Executable` captures three pieces of information:
1060
- * - the absolute runtime binary that should launch the module
1061
- * - the absolute path to the module itself
1062
- * - any additional arguments that should be passed after the module path
1063
- *
1064
- * Most consumers will create one via {@link defineExecutable} and then pass it
1065
- * into a {@link SystemdService} directive such as `ExecStart`, `ExecStop`, or
1066
- * `ExecReload`.
1067
- */
1068
- declare class Executable {
1069
- /** Additional arguments passed after the module path. */
1070
- readonly args: readonly string[];
1071
- /** Absolute path to the module that should be executed. */
1072
- readonly modulePath: string;
1073
- /** Absolute path to the runtime binary that should launch the module. */
1074
- readonly runtimeEntrypoint: string;
1075
- /**
1076
- * Creates an executable description.
1077
- *
1078
- * When `modulePath` is omitted, the calling module is inferred from the
1079
- * current stack so `defineExecutable()` can be used inline from the module
1080
- * that should become runnable.
1081
- *
1082
- * When `runtimeEntrypoint` is omitted, the current process executable is
1083
- * used. This works well for the common case where the same runtime that is
1084
- * evaluating your module should also be used by systemd.
1085
- */
1086
- constructor(options?: ExecutableOptions);
1087
- /**
1088
- * Returns the executable as raw command parts.
1089
- *
1090
- * The first element is always the runtime entrypoint, followed by the module
1091
- * path and any configured arguments.
1092
- */
1093
- toCommandParts(): readonly [string, ...string[]];
1094
- /**
1095
- * Renders the executable as a shell-quoted command string suitable for
1096
- * executable-valued systemd directives such as `ExecStart=`.
1097
- */
1098
- toExecStart(): string;
1139
+ //#region src/main/errors.d.ts
1140
+ type SystemdTsErrorCode = `SYSTEMD_TS_INVALID_EXEC_DIRECTIVE` | `SYSTEMD_TS_NO_UNITS_PROVIDED` | `SYSTEMD_TS_EXECUTABLE_INFERENCE` | `SYSTEMD_TS_UNIT_MATERIALIZATION` | `SYSTEMD_TS_UNIT_ENABLE` | `SYSTEMD_TS_UNIT_START` | `SYSTEMD_TS_UNIT_LOGS` | `SYSTEMD_TS_NOTIFY_SEND`;
1141
+ interface SystemdTsErrorOptions {
1142
+ readonly cause?: unknown;
1143
+ }
1144
+ interface SystemdCommandErrorOptions extends SystemdTsErrorOptions {
1145
+ readonly args?: readonly string[];
1146
+ readonly command?: string;
1147
+ readonly environmentReason?: SystemdCommandEnvironmentReason;
1148
+ readonly stage?: string;
1149
+ readonly unitName?: string;
1150
+ readonly unitPath?: string;
1151
+ }
1152
+ interface UnitStartDiagnostics {
1153
+ readonly showOutput?: string;
1154
+ readonly showStatus?: StartStatus;
1155
+ readonly statusOutput?: string;
1156
+ }
1157
+ interface UnitStartErrorOptions extends SystemdCommandErrorOptions {
1158
+ readonly diagnostics?: UnitStartDiagnostics;
1159
+ }
1160
+ interface UnitMaterializationErrorOptions extends SystemdTsErrorOptions {
1161
+ readonly reason?: UnitMaterializationErrorReason;
1162
+ readonly operation?: `create-directory` | `write-file`;
1163
+ readonly unitName?: string;
1164
+ readonly unitPath?: string;
1165
+ }
1166
+ type UnitMaterializationErrorReason = `file-system-failed` | `invalid-unit-directory` | `permission-denied`;
1167
+ interface UnitLogsReadErrorOptions extends SystemdCommandErrorOptions {
1168
+ readonly reason?: UnitLogsReadErrorReason;
1169
+ readonly unitPath?: string;
1170
+ }
1171
+ type UnitLogsReadErrorReason = `missing-log-file` | `log-file-read-failed` | `status-command-failed`;
1172
+ interface NotifySendErrorOptions extends SystemdCommandErrorOptions {
1173
+ readonly reason?: NotifySendErrorReason;
1174
+ }
1175
+ type NotifySendErrorReason = `executor-failed` | `systemd-notify-failed`;
1176
+ type SystemdCommandEnvironmentReason = `manager-unavailable` | `missing-command` | `permission-denied`;
1177
+ declare class SystemdTsError extends Error {
1178
+ readonly code: SystemdTsErrorCode;
1179
+ constructor(code: SystemdTsErrorCode, message: string, options?: SystemdTsErrorOptions);
1180
+ }
1181
+ declare class InvalidExecDirectiveError extends SystemdTsError {
1182
+ readonly directive: string;
1183
+ constructor(directive: string, options?: SystemdTsErrorOptions);
1184
+ }
1185
+ declare class NoUnitsProvidedError extends SystemdTsError {
1186
+ readonly operation: string;
1187
+ constructor(operation: string, options?: SystemdTsErrorOptions);
1188
+ }
1189
+ declare class ExecutableInferenceError extends SystemdTsError {
1190
+ constructor(options?: SystemdTsErrorOptions);
1191
+ }
1192
+ declare class UnitMaterializationError extends SystemdTsError {
1193
+ readonly operation: `create-directory` | `write-file` | undefined;
1194
+ readonly reason: UnitMaterializationErrorReason | undefined;
1195
+ readonly unitName: string | undefined;
1196
+ readonly unitPath: string | undefined;
1197
+ constructor(message: string, options?: UnitMaterializationErrorOptions);
1198
+ }
1199
+ declare class UnitEnableError extends SystemdTsError {
1200
+ readonly args: readonly string[] | undefined;
1201
+ readonly command: string | undefined;
1202
+ readonly environmentReason: SystemdCommandEnvironmentReason | undefined;
1203
+ readonly exitCode: number | undefined;
1204
+ readonly stage: string | undefined;
1205
+ readonly stderr: string | undefined;
1206
+ readonly stdout: string | undefined;
1207
+ readonly unitName: string | undefined;
1208
+ readonly unitPath: string | undefined;
1209
+ constructor(message: string, options?: SystemdCommandErrorOptions);
1210
+ }
1211
+ declare class UnitStartError extends SystemdTsError {
1212
+ readonly args: readonly string[] | undefined;
1213
+ readonly command: string | undefined;
1214
+ readonly diagnostics: UnitStartDiagnostics | undefined;
1215
+ readonly environmentReason: SystemdCommandEnvironmentReason | undefined;
1216
+ readonly exitCode: number | undefined;
1217
+ readonly stage: string | undefined;
1218
+ readonly stderr: string | undefined;
1219
+ readonly stdout: string | undefined;
1220
+ readonly unitName: string | undefined;
1221
+ readonly unitPath: string | undefined;
1222
+ constructor(message: string, options?: UnitStartErrorOptions);
1223
+ }
1224
+ declare class UnitLogsReadError extends SystemdTsError {
1225
+ readonly args: readonly string[] | undefined;
1226
+ readonly command: string | undefined;
1227
+ readonly environmentReason: SystemdCommandEnvironmentReason | undefined;
1228
+ readonly exitCode: number | undefined;
1229
+ readonly reason: UnitLogsReadErrorReason | undefined;
1230
+ readonly stage: string | undefined;
1231
+ readonly stderr: string | undefined;
1232
+ readonly stdout: string | undefined;
1233
+ readonly unitName: string | undefined;
1234
+ readonly unitPath: string | undefined;
1235
+ constructor(message: string, options?: UnitLogsReadErrorOptions);
1236
+ }
1237
+ declare class NotifySendError extends SystemdTsError {
1238
+ readonly args: readonly string[] | undefined;
1239
+ readonly command: string | undefined;
1240
+ readonly environmentReason: SystemdCommandEnvironmentReason | undefined;
1241
+ readonly exitCode: number | undefined;
1242
+ readonly reason: NotifySendErrorReason | undefined;
1243
+ readonly stage: string | undefined;
1244
+ readonly stderr: string | undefined;
1245
+ readonly stdout: string | undefined;
1246
+ constructor(message: string, options?: NotifySendErrorOptions);
1099
1247
  }
1100
- /**
1101
- * Defines a module as a runnable executable and returns its immutable
1102
- * `Executable` description.
1103
- *
1104
- * This helper is designed for the pattern:
1105
- *
1106
- * ```ts
1107
- * export default defineExecutable(async () => {
1108
- * // do work here
1109
- * });
1110
- * ```
1111
- *
1112
- * When the defining module is executed as the main entrypoint, `fn` is invoked.
1113
- * When the module is merely imported, `fn` is not run and only the executable
1114
- * description is returned.
1115
- *
1116
- * Pass `options.runtimeEntrypoint` to override the default runtime binary when
1117
- * the current process is not the exact runtime you want systemd to use.
1118
- */
1119
- declare function defineExecutable(fn: () => void | Promise<void>, options?: ExecutableOptions): Executable;
1120
1248
  //#endregion
1121
1249
  //#region src/main/notify.d.ts
1122
1250
  /**
@@ -1139,7 +1267,7 @@ declare const notify: {
1139
1267
  * ready to be considered fully started. If `options.status` is provided, it is
1140
1268
  * sent as an additional `STATUS=...` field.
1141
1269
  */
1142
- ready(options?: NotifyOptions): Promise<void>;
1270
+ ready(options?: NotifyOptions): Promise<Result<void, NotifySendError>>;
1143
1271
  /**
1144
1272
  * Sends `WATCHDOG=1` to systemd.
1145
1273
  *
@@ -1147,25 +1275,22 @@ declare const notify: {
1147
1275
  * watchdog heartbeat. If `options.pid` is provided, it is sent as
1148
1276
  * `MAINPID=...`, and `options.status` is forwarded as `STATUS=...`.
1149
1277
  */
1150
- watchdog(options?: NotifyOptions): Promise<void>;
1278
+ watchdog(options?: NotifyOptions): Promise<Result<void, NotifySendError>>;
1151
1279
  };
1152
1280
  //#endregion
1153
1281
  //#region src/main/systemd.d.ts
1154
1282
  /**
1155
- * The result of installing one or more units with {@link Systemd.install}.
1283
+ * A successful systemd unit materialization.
1156
1284
  *
1157
- * It records the installation directory and the on-disk path associated with
1158
- * each installed unit.
1285
+ * It records the target directory and the on-disk path associated with each
1286
+ * materialized unit.
1159
1287
  */
1160
- declare class SystemdInstallResult<TUnits extends readonly SystemdUnit[] = readonly SystemdUnit[]> {
1288
+ declare class SystemdMaterialization<TUnits extends readonly SystemdUnit[] = readonly SystemdUnit[]> {
1161
1289
  /** The directory units were written into. */
1162
1290
  readonly directory: string;
1163
- /** The installed units together with their resolved on-disk paths. */
1164
- readonly installed: readonly InstalledUnit<TUnits[number]>[];
1165
- private readonly pathByFilename;
1166
- constructor(directory: string, installed: readonly InstalledUnit<TUnits[number]>[]);
1167
- /** Returns the installed on-disk path for a previously installed unit. */
1168
- pathFor(unit: TUnits[number]): string;
1291
+ /** The materialized units together with their resolved on-disk paths. */
1292
+ readonly materialized: readonly MaterializedUnit<TUnits[number]>[];
1293
+ constructor(directory: string, materialized: readonly MaterializedUnit<TUnits[number]>[]);
1169
1294
  }
1170
1295
  /**
1171
1296
  * A configured interface to a specific systemd environment.
@@ -1198,19 +1323,17 @@ declare class Systemd {
1198
1323
  * Renders and writes one or more units into this instance's `unitDir`.
1199
1324
  *
1200
1325
  * This is intentionally a file-materialization step. It does not enable or
1201
- * start the units on its own. When both timers and services are installed
1202
- * together, compile-time and runtime attachment checks ensure the timer points
1203
- * at one of the accompanying services.
1326
+ * start the units on its own.
1204
1327
  */
1205
- install<const TUnits extends readonly SystemdUnit[]>(...units: TUnits & ValidInstallUnits<TUnits>): Promise<SystemdInstallResult<TUnits>>;
1328
+ materialize<const TUnits extends readonly SystemdUnit[]>(...units: TUnits & ValidInstallUnits<TUnits>): Promise<Result<SystemdMaterialization<TUnits>, ExecutableInferenceError | InvalidExecDirectiveError | NoUnitsProvidedError | UnitMaterializationError>>;
1206
1329
  /**
1207
1330
  * Enables one or more units via `systemctl enable`.
1208
1331
  *
1209
- * When `linkUnits` is enabled, this first links installed unit files into the
1332
+ * When `linkUnits` is enabled, this first links materialized unit files into the
1210
1333
  * target manager and reloads systemd so the units are visible before the
1211
1334
  * enable operation runs.
1212
1335
  */
1213
- enable(...units: readonly SystemdUnit[]): Promise<void>;
1336
+ enable(...units: readonly SystemdUnit[]): Promise<Result<void, NoUnitsProvidedError | UnitEnableError>>;
1214
1337
  /**
1215
1338
  * Starts a unit and returns a parsed `systemctl show` snapshot of its final
1216
1339
  * observed state.
@@ -1218,7 +1341,7 @@ declare class Systemd {
1218
1341
  * For oneshot services, a successful result commonly means `ActiveState` is
1219
1342
  * already back to `inactive` by the time the status snapshot is collected.
1220
1343
  */
1221
- start(unit: SystemdUnit): Promise<StartResult>;
1344
+ start(unit: SystemdUnit): Promise<Result<StartStatus, UnitStartError>>;
1222
1345
  /**
1223
1346
  * Reads recent output for a managed unit.
1224
1347
  *
@@ -1226,12 +1349,15 @@ declare class Systemd {
1226
1349
  * `StandardError`, this reads directly from that file. Otherwise it falls back
1227
1350
  * to `systemctl status --lines ...`.
1228
1351
  */
1229
- logs(unit: SystemdUnit, options?: LogsOptions): Promise<string>;
1352
+ logs(unit: SystemdUnit, options?: LogsOptions): Promise<Result<string, UnitLogsReadError>>;
1230
1353
  /** Returns the on-disk unit-file path this instance uses for the given unit. */
1231
1354
  pathFor(unit: SystemdUnit): string;
1232
1355
  private prepareUnits;
1233
1356
  private scopeArgs;
1357
+ private collectStartDiagnostics;
1234
1358
  private collectLinkPaths;
1359
+ private materializeUnits;
1360
+ private tryBestEffortCommand;
1235
1361
  }
1236
1362
  /**
1237
1363
  * Returns the lazily created default `Systemd` instance.
@@ -1240,23 +1366,6 @@ declare class Systemd {
1240
1366
  * command execution.
1241
1367
  */
1242
1368
  declare function defaultSystemd(): Systemd;
1243
- declare namespace internal_d_exports {
1244
- export { assertInstallableTogether, cloneUnitSection, defaultCommandExecutor, defaultUnitDirForScope, fileExists, freezeUnitOptions, normalizeUnitName, parseStartResult, renderUnitFile, resolveTimerTargetUnit, sendNotify, shellQuote, validateServiceSection };
1245
- }
1246
- type SectionLike = object;
1247
- declare function normalizeUnitName(name: string, suffix: `.service` | `.timer`): string;
1248
- declare function resolveTimerTargetUnit(options: SystemdTimerOptions): string;
1249
- declare function defaultUnitDirForScope(scope: `system` | `user`): string;
1250
- declare function freezeUnitOptions<TOptions extends SystemdServiceOptions | SystemdTimerOptions>(options: TOptions): Readonly<TOptions>;
1251
- declare function cloneUnitSection<TSection extends SectionLike | undefined>(section: TSection): TSection;
1252
- declare function validateServiceSection(service: SystemdServiceSection): void;
1253
- declare function assertInstallableTogether(units: readonly SystemdUnit[]): void;
1254
- declare function parseStartResult(unit: string, output: string): StartResult;
1255
- declare function renderUnitFile(sections: ReadonlyArray<readonly [string, SectionLike | undefined]>): string;
1256
- declare function shellQuote(value: string): string;
1257
- declare function defaultCommandExecutor(command: string, args: readonly string[]): Promise<CommandResult>;
1258
- declare function fileExists(path: string): Promise<boolean>;
1259
- declare function sendNotify(state: `READY=1` | `WATCHDOG=1`, options: NotifyOptions): Promise<void>;
1260
1369
  //#endregion
1261
1370
  //#region src/main/index.d.ts
1262
1371
  /**
@@ -1265,4 +1374,4 @@ declare function sendNotify(state: `READY=1` | `WATCHDOG=1`, options: NotifyOpti
1265
1374
  */
1266
1375
  declare const Internal: typeof internal_d_exports;
1267
1376
  //#endregion
1268
- export { type AnySystemdService, type AnySystemdTimer, type CommandExecutor, type CommandResult, Executable, type ExecutableOptions, type InstalledUnit, Internal, type LogsOptions, type NotifyOptions, type ServiceBaseName, type ServiceFilename, type StartResult, Systemd, SystemdInstallResult, type SystemdOptions, SystemdService, type SystemdServiceOptions, SystemdTimer, type SystemdTimerOptions, type SystemdUnit, type TimerBaseName, type TimerFilename, type TimerTargetServiceName, type TimerTargetUnit, type UnitSection, type UnitValue, type ValidInstallUnits, defaultSystemd, defineExecutable, notify };
1377
+ export { type AnySystemdService, type AnySystemdTimer, type CommandExecutor, type CommandOutput, Executable, ExecutableInferenceError, type ExecutableOptions, Internal, InvalidExecDirectiveError, type LogsOptions, type MaterializedUnit, NoUnitsProvidedError, type NotifyOptions, NotifySendError, type NotifySendErrorReason, type Result, type ServiceBaseName, type ServiceFilename, type StartStatus, Systemd, type SystemdCommandEnvironmentReason, SystemdMaterialization, type SystemdOptions, SystemdService, type SystemdServiceOptions, SystemdTimer, type SystemdTimerOptions, SystemdTsError, type SystemdUnit, type TimerBaseName, type TimerFilename, type TimerTargetServiceName, type TimerTargetUnit, UnitEnableError, UnitLogsReadError, type UnitLogsReadErrorReason, UnitMaterializationError, type UnitMaterializationErrorReason, UnitStartError, type UnitValue, type ValidInstallUnits, defaultSystemd, defineExecutable, notify };