Service is a JavaScript/TypeScript module for managing system services. It offers a convenient way to install, uninstall, and generate service configurations for various service managers. It can be used as either a command line tool, or a typescript library for direct integration in other Node/Deno/Bun programs.
Part of the @cross suite - check out our growing collection of cross-runtime tools at github.com/cross-org.
- Easy-to-use CLI for managing services
- Library usage for custom integrations
- Install, uninstall, and generate service configurations
- Compatible with systemd, sysvinit, docker-init, upstart (Linux), launchd (macOS) and SCM (Windows) service managers
- Installs any script as service on any system.
- Cross-Runtime and Cross-Platform.
To use Service as a CLI program, you can install or upgrade it using Deno:
deno install -frA --global --name cross-service jsr:@cross/service/install
For library usage in Node, Deno or Bun - install according to the instructions at jsr.io/@cross/service and simply import the installService()
function from the:
import { installService } from "@cross/service";
To use the service library from the command line, follow these steps:
Install a command as a service:
# Using deno
cross-service install --name my-service --cmd "deno run --allow-net /full/path/to/server.ts"
# ... or a generic executable (with arguments and extra paths)
cross-service install --name my-service --cmd "/full/path/to/executable --optional-arg /full/path/to/config.ext" --path "/add/this/to/path:/and/this"
Uninstall a service:
cross-service uninstall --name my-service
Generate a service configuration file without installing it:
cross-service generate --name my-service --cmd "deno run --allow-net /full/path/to/server.ts --arg /full/path/to/config.ext"
Note:
- The deno install path (e.g.
$HOME/.deno/bin
) will automatically be added to path. Additional paths can be supplied by passing a colon separated list to--path
. - If you have any problems, always use full paths when registering a service. Services do not have the
PATH
that your shell have. - Use
generate
beforeinstall
, that way you can visually inspect the generated configuration before installing it. - Steps requiring elevated access (like installing a system wide service) will not be performed automatically, you will insted get step by step instruction to make the required steps using
sudo
or the tool of your choice. - You can force service to generate configuration for a manager that is not installed, using systemd as an example:
generate --force systemd
To use the service library programmatically, you can import and use the installService
, generateConfig
and uninstallService
functions.
Install for your runtime according to the instructions at [https://jsr.io/@cross/service].
This is the interface for the options used by the installService
function:
interface InstallServiceOptions {
system: boolean;
name: string;
cmd: string;
user?: string;
home?: string;
cwd?: string;
path?: string[];
env?: string[];
}
The interface for the uninstallService
function is very similar:
interface UninstallServiceOptions {
system: boolean;
name: string;
home?: string;
}
The installService
function installs a command as a service, using the current service manager:
import { installService } from "@cross/service";
await installService({
system: false, // Use user mode if available (default) or force system mode
name: "my-service",
cmd: "deno run --allow-net server.ts",
user: "username", // Optional, defaults to current user
home: "/home/username", // Optional, defaults to current user's home
cwd: "/path/to/working/directory", // Optional, defaults to current working directory
path: ["/extra/path", "/extra/path/2"], // Optional
env: ["KEY=VALUE", "KEY2=VALUE2"], // Optional
});
The uninstallService
function uninstalls a command from a service, using the currently installed service manager:
import { uninstallService } from "@cross/service";
await uninstallService({
system: false, // Use user mode if available (default) or force system mode
name: "my-service",
home: "/home/username", // Optional, defaults to current user's home, used in case of user services
});
The generateConfig
function generates a service configuration string for the specified service:
import { generateConfig } from "@cross/service";
const config = await generateConfig({
system: false, // Use user mode if available (default) or force system mode
name: "my-service",
cmd: "deno run --allow-net server.ts",
user: "username", // Optional, defaults to current user
home: "/home/username", // Optional, defaults to current user's home
cwd: "/path/to/working/directory", // Optional, defaults to current working directory,
path: ["/extra/path", "/extra/path/2"], // Optional
env: ["KEY=VALUE", "KEY2=VALUE2"], // Optional
});
console.log(config);
Contributions are welcome! Please feel free to submit issues or pull requests.
Before submitting a pull request, please ensure your code follows the project's coding style and passes all tests.
/**
* @file lib/managers/name_of_manager.ts
*
* This module provides a template for implementing new manager classes
* for various init systems. The template contains the structure and descriptions
* of the required methods for a manager class. Replace 'ManagerTemplate' with the
* name of the new manager class and implement the necessary methods according
* to the target init system.
*
* When done, add this new implementation to lib/service.ts
*/
import { InstallServiceOptions, UninstallServiceOptions } from "../service.ts";
class ManagerTemplate {
/**
* Generates the configuration file content based on the given options.
* @param config - The configuration options for the service.
* @returns The generated configuration file content.
*/
generateConfig(config: InstallServiceOptions): string {
// TODO: Implement this method for the target init system.
throw new Error("Not implemented");
}
/**
* Installs the service based on the given options.
* @param config - The configuration options for the service.
* @param onlyGenerate - A flag indicating whether to only generate the configuration or
* also install the service. The difference between install with onlyGenerate and the
* generateConfig function, is that install with onlyGenerate should console.log additional
* steps needed to finish the installation, such as `sudo systemctl daemon-reload`.
* generateConfig do only output the base configuration file.
*/
async install(config: InstallServiceOptions, onlyGenerate: boolean): Promise<InstallServiceOptions> {
/*
* ToDo: Implement this method for the target init system.
*
return {
servicePath,
serviceFileContent,
manualSteps: null,
}; */
throw new Error("Not implemented");
}
/**
* Uninstalls the service based on the given options.
* @param config - The configuration options for uninstalling the service.
*/
async uninstall(config: UninstallServiceOptions): Promise<UninstallServiceOptions> {
/*
* TODO: Implement this method for the target init system.
*
return {
pathToServiceFile,
manualSteps: null,
};
*/
throw new Error("Not implemented");
}
}
export { ManagerTemplate };