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.
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:
$HOME/.deno/bin
) will automatically be added to path. Additional paths can be supplied by passing a colon separated list to--path
.PATH
that your shell have.generate
before install
, that way you can visually inspect the generated configuration before installing it.sudo
or
the tool of your choice.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 };
Add Package
deno add jsr:@cross/service
Import symbol
import * as service from "@cross/service";
Import directly with a jsr specifier
import * as service from "jsr:@cross/service";
Add Package
pnpm i jsr:@cross/service
pnpm dlx jsr add @cross/service
Import symbol
import * as service from "@cross/service";
Add Package
yarn add jsr:@cross/service
yarn dlx jsr add @cross/service
Import symbol
import * as service from "@cross/service";
Add Package
npx jsr add @cross/service
Import symbol
import * as service from "@cross/service";
Add Package
bunx jsr add @cross/service
Import symbol
import * as service from "@cross/service";