npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@simplysm/sd-cli

v13.0.67

Published

심플리즘 패키지 - CLI 도구

Downloads

8,332

Readme

@simplysm/sd-cli

The CLI tool for the Simplysm framework. It provides project initialization, ESLint/Stylelint linting, TypeScript type-checking, combined check (typecheck + lint + test), library/client/server package builds, development mode, deployment, Android device execution, and Electron desktop app build capabilities.

Installation

npm install --save-dev @simplysm/sd-cli
# or
pnpm add -D @simplysm/sd-cli

Main Commands

The CLI binary name is sd-cli. All commands support the --debug option to output detailed logs.

lint

Runs ESLint and Stylelint. ESLint lints .ts/.tsx/.js/.jsx files; Stylelint lints .css files (only when a Stylelint config file is present). Extracts globalIgnores patterns from eslint.config.ts. Caches results in .cache/eslint.cache and .cache/stylelint.cache.

# Lint all
sd-cli lint

# Lint specific path
sd-cli lint packages/core-common

# Lint multiple paths
sd-cli lint packages/core-common tests/orm

# Auto-fix
sd-cli lint --fix

# Output rule execution times
sd-cli lint --timing

Options:

| Option | Description | Default | | ---------- | ---------------------------------------------------------- | ------- | | --fix | Auto-fix | false | | --timing | Output rule execution times (sets ESLint TIMING env var) | false | | --debug | Output debug logs | false |

typecheck

Runs TypeScript type-checking. It performs parallel type-checking per package environment (node/browser) based on tsconfig.json and sd.config.ts. Uses worker threads to run concurrently up to 7/8 of CPU cores.

# Type-check all
sd-cli typecheck

# Type-check specific path
sd-cli typecheck packages/core-common

# Type-check multiple paths
sd-cli typecheck packages/core-common tests/orm

# Pass options to sd.config.ts
sd-cli typecheck -o key=value

Options:

| Option | Description | Default | | ----------------- | ---------------------------------------------------------- | ------- | | --options, -o | Additional options to pass to sd.config.ts (multi-use) | [] | | --debug | Output debug logs | false |

Type-check environment by target:

| Target | Environment | | ------------------- | ----------------------- | | node | node environment once | | browser, client | browser environment once | | neutral | node + browser environment twice | | scripts | Excluded from type-check |

check

Runs typecheck, lint, and test in parallel and prints a consolidated summary. Lint auto-fix is always enabled when run via check. Exits with code 1 if any check fails.

# Run all checks (typecheck + lint + test)
sd-cli check

# Run specific check types
sd-cli check --type typecheck,lint

# Filter paths
sd-cli check packages/core-common

Options:

| Option | Description | Default | | ---------- | -------------------------------------------------------------------- | ------------------------ | | --type | Comma-separated list of check types to run: typecheck, lint, test | typecheck,lint,test | | --debug | Output debug logs | false |

Output format:

Each check type prints a section header followed by its result summary. A final SUMMARY section lists overall pass/fail status and total error/warning counts.

watch

Watches library packages (node/browser/neutral targets) in watch mode. Automatically rebuilds on file changes and generates .d.ts type definition files.

Note: Use the dev command for client/server targets.

# Watch all library packages
sd-cli watch

# Watch specific package
sd-cli watch solid

# Watch multiple packages
sd-cli watch solid core-common

Options:

| Option | Description | Default | | ----------------- | ---------------------------------------------------------- | ------- | | --options, -o | Additional options to pass to sd.config.ts (multi-use) | [] | | --debug | Output debug logs | false |

dev

Runs Client and Server packages in development mode. client targets run with Vite dev server, and server targets run with Server Build Worker + Server Runtime Worker. Supports Server-Client proxy connection and Capacitor initialization.

# Run all client/server packages
sd-cli dev

# Run specific package
sd-cli dev solid-demo

# Run multiple packages
sd-cli dev solid-demo my-server

Options:

| Option | Description | Default | | ----------------- | ---------------------------------------------------------- | ------- | | --options, -o | Additional options to pass to sd.config.ts (multi-use) | [] | | --debug | Output debug logs | false |

How it works:

  • client target: Starts Vite dev server. If server config is a string (package name), connects proxy to that server
  • server target: Builds in esbuild watch mode, then runs server runtime in separate Worker. Auto-rebuilds and restarts server on file changes
  • Client packages with Capacitor config perform Capacitor initialization after build completes
  • Client packages with Electron config launch Electron in dev mode after build completes
  • Terminates on SIGINT/SIGTERM signals

Scope Package HMR:

When using replaceDeps to develop scope packages locally, the Vite dev server automatically watches scope package dist files and triggers HMR when they change. This allows changes to @simplysm/* packages to be reflected in the dev app without manual reload.

build

Runs production build. Performs lint, dist folder cleanup, and build sequentially.

# Build all packages
sd-cli build

# Build specific packages
sd-cli build solid core-common

Options:

| Option | Description | Default | | ----------------- | ---------------------------------------------------------- | ------- | | --options, -o | Additional options to pass to sd.config.ts (multi-use) | [] | | --debug | Output debug logs | false |

Build behavior by target:

| Target | JS build | .d.ts generation | Type-check | Note | | -------------------------- | --------------- | ---------------- | ---------- | ------------------------------------- | | node/browser/neutral | esbuild | O | O | Library package | | client | Vite production | X | O | Client app (+ Capacitor/Electron build) | | server | esbuild | X | X | Server app | | scripts | Excluded | Excluded | Excluded | - |

Public Files & Assets:

Both client and server packages support serving static files from a public/ directory:

  • Client packages (dev mode): Vite serves public/ at the configured base path (/{name}/)
  • Server packages (dev mode): Copies public/ to dist/, watches for changes, and automatically rebuilds
  • Server packages (build mode): Copies public/ to dist/ (production deployment)
  • Client packages (dev mode only): Optional public-dev/ directory files are served with priority over public/ files, allowing dev-specific overrides without affecting production builds

Directory structure:

packages/my-server/
├── public/              # Static files (both dev and build)
│   ├── index.html
│   ├── style.css
│   └── assets/
└── public-dev/          # Dev-only overrides (dev mode only, ignored in build)
    └── index.html       # Overrides public/index.html in dev

How it works:

  • In dev mode, both public/ and public-dev/ are copied to dist/, with public-dev/ changes taking priority
  • If a public-dev/ file is deleted, the corresponding public/ file is served as fallback
  • In build mode, only public/ is copied to dist/ (no public-dev/)
  • The copy operation preserves directory structure

Runtime Configuration File (.config.json):

If a server or client package defines a configs field in sd.config.ts, the build automatically generates dist/.config.json containing that configuration. This is useful for storing environment-specific settings (database config, API endpoints, etc.) that are read at runtime via ctx.getConfig() in service-server.

Server Build: Externals & Production Deployment Files:

Server builds (target: "server") automatically detect modules that cannot be bundled by esbuild and mark them as external. Three sources of externals are combined:

  1. Uninstalled optional peer dependencies — automatically detected via peerDependenciesMeta
  2. Native modules (node-gyp) — automatically detected by scanning for binding.gyp files in the dependency tree
  3. Manual externals — specified via externals in sd.config.ts

During production build (sd-cli build), the following deployment files are generated in dist/:

| File | Description | |------|-------------| | package.json | Minimal package.json with externalized dependencies (version "*") for npm install on the deployment server | | mise.toml | Node.js version specification (read from root mise.toml) — only generated when packageManager: "mise" is set | | openssl.cnf | Legacy OpenSSL provider activation (required for MSSQL and other legacy TLS connections) | | pm2.config.cjs | PM2 process manager config (only generated when pm2 is configured) |

Note: Production deployment files are only generated during sd-cli build, not during sd-cli dev (watch mode).

publish

Publishes packages. For safety, proceeds in the following order:

  1. Pre-validation (npm authentication, Git uncommitted changes check)
  2. Version upgrade (increment prerelease if prerelease, otherwise patch)
  3. Build (Git rollback on failure)
  4. Git commit/tag/push (Git rollback on failure)
  5. npm/FTP/local deployment
  6. postPublish script execution
# Publish all packages with publish config
sd-cli publish

# Publish specific packages
sd-cli publish solid core-common

# Publish without build (dangerous)
sd-cli publish --no-build

# Simulate without actual deployment
sd-cli publish --dry-run

Options:

| Option | Description | Default | | ------------------------ | ---------------------------------------------------------- | ------- | | --build / --no-build | Whether to run build (skip with --no-build) | true | | --dry-run | Simulate without actual deployment | false | | --options, -o | Additional options to pass to sd.config.ts (multi-use) | [] | | --debug | Output debug logs | false |

init

Initializes a new Simplysm project in the current directory. The directory must be empty and the directory name must be a valid npm scope name (lowercase, numbers, hyphens only).

Creates a skeleton project with:

  • sd.config.ts, tsconfig.json, eslint.config.ts, pnpm-workspace.yaml
  • .gitignore, .prettierrc.yaml, .prettierignore, mise.toml

After rendering templates, runs pnpm install automatically.

# Create an empty directory and run init
mkdir my-project && cd my-project
sd-cli init

After initialization, use sd-cli add client and sd-cli add server to add packages.

Note: Claude Code skills/agents are automatically installed via @simplysm/sd-claude postinstall.

add client

Adds a client package to an existing project. Must be run from the project root (where sd.config.ts exists).

Runs an interactive prompt to collect:

  1. Client package name suffix (creates client-{suffix} package)
  2. Whether to use router

After collecting inputs, it:

  1. Renders client package from Handlebars templates into packages/client-{suffix}/
  2. Adds the package entry to sd.config.ts (via ts-morph AST editing)
  3. Adds tailwind CSS settings to eslint.config.ts (if first client)
  4. Runs pnpm install
sd-cli add client

add server

Adds a server package to an existing project. Must be run from the project root (where sd.config.ts exists).

Runs an interactive prompt to collect:

  1. Server name suffix (leave empty for just server, otherwise creates server-{suffix})
  2. Which existing client packages this server should serve (multi-select)

After collecting inputs, it:

  1. Renders server package from Handlebars templates into packages/{server-name}/
  2. Adds the server package entry to sd.config.ts
  3. Updates selected client packages' server field in sd.config.ts
  4. Runs pnpm install
sd-cli add server

replace-deps

Sets up local dependency replacement according to replaceDeps configuration in sd.config.ts. Useful for local development of dependent packages across separate repositories.

# Set up replacements (symlink or copy mode based on config)
sd-cli replace-deps

# With additional options
sd-cli replace-deps -o key=value

Options:

| Option | Description | Default | | ----------------- | ---------------------------------------------------------- | ------- | | --options, -o | Additional options to pass to sd.config.ts (multi-use) | [] | | --debug | Output debug logs | false |

device

Runs Capacitor app on Android device. Only available for client target packages with capacitor config in sd.config.ts.

# Specify package (required)
sd-cli device -p my-app

# Specify dev server URL directly
sd-cli device -p my-app -u http://192.168.0.10:3000

Options:

| Option | Description | Default | | ----------------- | ------------------------------------------------------------------------- | ------- | | --package, -p | Package name (required) | - | | --url, -u | Dev server URL (uses server port from sd.config.ts if not specified) | - | | --options, -o | Additional options to pass to sd.config.ts (multi-use) | [] | | --debug | Output debug logs | false |

Exported Types and Utilities

This package exports configuration types for sd.config.ts and Vite utilities. All are importable from @simplysm/sd-cli.

import type {
  SdConfigFn,
  SdConfigParams,
  SdConfig,
  SdPackageConfig,
  BuildTarget,
  SdBuildPackageConfig,
  SdClientPackageConfig,
  SdServerPackageConfig,
  SdScriptsPackageConfig,
  SdPublishConfig,
  SdLocalDirectoryPublishConfig,
  SdStoragePublishConfig,
  SdPostPublishScriptConfig,
  SdCapacitorConfig,
  SdCapacitorAndroidConfig,
  SdCapacitorSignConfig,
  SdCapacitorPermission,
  SdCapacitorIntentFilter,
  SdElectronConfig,
  ViteConfigOptions,
} from "@simplysm/sd-cli";
import { createViteConfig } from "@simplysm/sd-cli";

| Type | Description | |------|-------------| | SdConfigFn | Function type for sd.config.ts default export: (params: SdConfigParams) => SdConfig \| Promise<SdConfig> | | SdConfigParams | Parameters passed to the config function (cwd, dev, opt) | | SdConfig | Root configuration object (packages, replaceDeps?, postPublish?) | | SdPackageConfig | Union of all package config types | | BuildTarget | Library build target: "node" \| "browser" \| "neutral" | | SdBuildPackageConfig | Config for library packages (node/browser/neutral targets) | | SdClientPackageConfig | Config for client packages (client target) | | SdServerPackageConfig | Config for server packages (server target, with externals and pm2 options) | | SdScriptsPackageConfig | Config for scripts-only packages (scripts target) | | SdPublishConfig | Deployment config: "npm" \| SdLocalDirectoryPublishConfig \| SdStoragePublishConfig | | SdLocalDirectoryPublishConfig | Local directory deployment config (type: "local-directory", path) | | SdStoragePublishConfig | FTP/FTPS/SFTP deployment config (type, host, port?, path?, user?, pass?) | | SdPostPublishScriptConfig | Post-publish script config (type: "script", cmd, args) | | SdCapacitorConfig | Capacitor config for Android app builds | | SdCapacitorAndroidConfig | Android platform-specific Capacitor config | | SdCapacitorSignConfig | APK/AAB signing config (keystore, storePassword, alias, password, keystoreType?) | | SdCapacitorPermission | Android permission entry (name, maxSdkVersion?, ignore?) | | SdCapacitorIntentFilter | Android intent filter entry (action?, category?) | | SdElectronConfig | Electron desktop app build config | | ViteConfigOptions | Options passed to createViteConfig() — see fields below |

Vite Utilities

createViteConfig

Creates pre-configured Vite configuration for Simplysm client packages.

import { createViteConfig, type ViteConfigOptions } from "@simplysm/sd-cli";

const options: ViteConfigOptions = {
  pkgDir: "/path/to/package",
  name: "my-app",
  tsconfigPath: "/path/to/tsconfig.json",
  compilerOptions: {},
  mode: "build",
};

export default createViteConfig(options);

ViteConfigOptions fields:

| Field | Type | Required | Description | |-------|------|----------|-------------| | pkgDir | string | Yes | Absolute path to the package directory | | name | string | Yes | Package name used as Vite base path (/{name}/) | | tsconfigPath | string | Yes | Absolute path to tsconfig.json | | compilerOptions | Record<string, unknown> | Yes | TypeScript compiler options passed to esbuild | | env | Record<string, string> | No | Environment variables to substitute for process.env at build time | | mode | "build" \| "dev" | Yes | Build mode: "build" for production, "dev" for development server | | serverPort | number | No | Dev server port (0 for auto-assign). Only used in "dev" mode | | watchScopes | string[] | No | Scope package prefixes to watch for HMR (e.g., ["@simplysm"]) | | onScopeRebuild | () => void | No | Callback invoked when a watched scope package dist file changes |

The createViteConfig() function configures:

  • Development server configuration
  • Production build optimization
  • SolidJS + TailwindCSS plugin integration
  • PWA (service worker + web app manifest) generation
  • Environment variable substitution support
  • Scope package watch/HMR (automatically watches scope package dist files and triggers HMR on changes via replaceDeps)

Configuration (sd.config.ts)

Create an sd.config.ts file in the project root to define build targets and deployment settings per package. Used by typecheck, watch, dev, build, publish, and device commands.

The typecheck command treats all packages as neutral target if no config file exists. The watch, dev, build, and publish commands require this file.

Basic Example

import type { SdConfigFn } from "@simplysm/sd-cli";

const config: SdConfigFn = () => ({
  packages: {
    "core-common": { target: "neutral" },
    "core-node": { target: "node" },
    "core-browser": { target: "browser" },
    "solid": { target: "browser", publish: "npm" },
    "solid-demo": { target: "client", server: "solid-demo-server" },
    "solid-demo-server": { target: "server" },
    "my-scripts": { target: "scripts" },
  },
});

export default config;

Target Types

| Target | Description | Type-check | watch | dev | build | | --------- | ------------------------------------------------------------------ | ------------------ | ----- | --- | ------------ | | node | Node.js-only package. Removes DOM lib, includes @types/node | O (node) | O | X | O (JS + dts) | | browser | Browser-only package. Keeps DOM lib, excludes @types/node | O (browser) | O | X | O (JS + dts) | | neutral | Node/browser common. Keeps DOM lib, includes @types/node | O (node + browser) | O | X | O (JS + dts) | | client | Vite dev server-based client app | O (browser) | X | O | O (Vite) | | server | Fastify-based server app | X | X | O | O (JS) | | scripts | Excluded from typecheck/watch/build | X | X | X | X |

Function Parameters

The sd.config.ts function receives a SdConfigParams object as an argument:

import type { SdConfigFn, SdConfigParams } from "@simplysm/sd-cli";

const config: SdConfigFn = (params: SdConfigParams) => {
  // params.cwd  - Current working directory
  // params.dev  - Whether in dev mode (true for dev command, false for build/publish)
  // params.opt  - Additional options array passed via CLI's -o flag

  return {
    packages: {
      "my-app": {
        target: "client",
        server: params.dev ? 3000 : "my-server",
      },
    },
  };
};

export default config;

Package Configuration Types

Library Package (SdBuildPackageConfig)

{
  target: "node" | "browser" | "neutral";
  publish?: SdPublishConfig;  // Deployment config (optional)
  copySrc?: string[];         // Glob patterns for copying assets from src/ to dist/ (optional)
}

Asset Copying (copySrc)

The copySrc option allows copying non-TypeScript files (CSS, images, etc.) from src/ to dist/ during build and watch mode:

"my-lib": {
  target: "browser",
  publish: "npm",
  copySrc: ["**/*.css", "**/*.png"],  // Copy all CSS and PNG files
}

How it works:

  • Glob patterns are relative to src/ directory
  • File directory structure is preserved during copy (e.g., src/styles/theme.cssdist/styles/theme.css)
  • Applied during both production build (sd-cli build) and watch mode (sd-cli watch)
  • Useful for including CSS files with component libraries when consuming apps may not bundle them automatically

Client Package (SdClientPackageConfig)

{
  target: "client";
  server: string | number;      // Server package name or direct port number
  env?: Record<string, string>; // Environment variables to replace during build
  publish?: SdPublishConfig;    // Deployment config (optional)
  capacitor?: SdCapacitorConfig; // Capacitor config (optional)
  electron?: SdElectronConfig;  // Electron config (optional)
  configs?: Record<string, unknown>; // Runtime config (written to dist/.config.json during build)
}
Progressive Web App (PWA) Support

All client packages automatically generate PWA files during build. No configuration is required to enable PWA.

Generated Files:

  • sw.js - Service worker (handles offline caching and precache of all build assets)
  • manifest.webmanifest - Web app manifest (for app install/launch)
  • registerSW.js - Service worker registration script (injected automatically)

Key behaviors:

  • Build mode: Service worker is fully enabled with offline support and asset precaching via Workbox
  • Dev mode: Service worker registration is disabled by default for safe development (no stale cache issues)
  • Precache strategy: All build assets (*.js, *.css, *.html, *.ico, *.png, *.svg, *.woff2) are precached for instant loading
  • HTTPS requirement: Service workers require HTTPS at runtime (localhost dev mode is exempt)
  • Offline capability: Once cached, the app works offline with all precached resources available

Users can install the app on their home screen on supported browsers and devices. No additional code or dependencies are needed.

Server Package (SdServerPackageConfig)

{
  target: "server";
  env?: Record<string, string>;      // Environment variables to replace during build
  publish?: SdPublishConfig;         // Deployment config (optional)
  configs?: Record<string, unknown>; // Runtime config (written to dist/.config.json during build)
  externals?: string[];              // Additional modules to exclude from bundle (optional)
  packageManager?: "volta" | "mise"; // Package manager for Node.js version management (optional)
  pm2?: {                            // PM2 config — generates dist/pm2.config.cjs (optional)
    name?: string;                   // PM2 process name (defaults to package name)
    ignoreWatchPaths?: string[];     // Paths to ignore in PM2 watch
  };
}

Scripts Package (SdScriptsPackageConfig)

{
  target: "scripts";
}

Deployment Configuration (SdPublishConfig)

Three deployment methods are supported:

| Method | Config Value | Description | | ---------------- | ----------------------------------------------------------------------- | ------------------------------------- | | npm | "npm" | Deploy to npm registry | | Local directory | { type: "local-directory", path: "..." } | Copy dist to local path | | Storage | { type: "ftp" \| "ftps" \| "sftp", host, port?, path?, user?, pass? } | Upload to FTP/FTPS/SFTP server |

Environment variable substitution is supported in path for local directory and storage: %VER% (version), %PROJECT% (project path).

// npm deployment
"core-common": { target: "neutral", publish: "npm" },

// Local directory deployment
"my-app": {
  target: "client",
  server: 3000,
  publish: { type: "local-directory", path: "/deploy/%VER%/my-app" },
},

// SFTP upload
"my-server": {
  target: "server",
  publish: {
    type: "sftp",
    host: "deploy.example.com",
    port: 22,
    path: "/opt/app",
    user: "deploy",
    pass: "secret",
  },
},

Runtime Configuration (configs)

Define runtime configuration for server or client packages using the configs field. This configuration is automatically written to dist/.config.json during build and can be read at runtime via ctx.getConfig() in the service-server package.

import type { SdConfigFn } from "@simplysm/sd-cli";

const config: SdConfigFn = () => ({
  packages: {
    "my-server": {
      target: "server",
      configs: {
        // Runtime configuration sections
        orm: {
          default: {
            dialect: "mysql",
            host: process.env.DB_HOST || "localhost",
            port: 3306,
            database: "mydb",
            user: process.env.DB_USER || "root",
            password: process.env.DB_PASSWORD,
          },
        },
        smtp: {
          default: {
            host: "smtp.example.com",
            port: 587,
            secure: false,
            user: process.env.SMTP_USER,
            pass: process.env.SMTP_PASS,
          },
        },
      },
    },
    "my-app": {
      target: "client",
      server: "my-server",
      configs: {
        api: {
          baseUrl: process.env.API_URL || "http://localhost:3000",
          timeout: 30000,
        },
      },
    },
  },
});

export default config;

At runtime, services access configuration sections:

// In a service class
const ormConfig = await this.getConfig<Record<string, DbConfig>>("orm");
const dbConfig = ormConfig.default;  // Access specific DB config by name

Key points:

  • Configuration sections can be nested objects with any structure
  • Environment variable substitution can be used in config values
  • Generated dist/.config.json files are not included in version control (add to .gitignore)
  • Client and server both support configs, but typically only servers expose configuration via ctx.getConfig()

Dependency Replacement (replaceDeps)

Replace node_modules packages with local source directories via symlinks. Useful for local development of dependent packages across separate repositories.

The key is a glob pattern to match packages in node_modules, and the value is the local source directory path. The * wildcard in the key is substituted into the * in the value.

import type { SdConfigFn } from "@simplysm/sd-cli";

const config: SdConfigFn = () => ({
  packages: {
    "my-app": { target: "client", server: "my-server" },
  },
  replaceDeps: {
    // Replaces @simplysm/* packages in node_modules
    // with symlinks to ../simplysm/packages/*/dist
    "@simplysm/*": "../simplysm/packages/*",
  },
});

export default config;

postPublish Scripts

You can define scripts to run after deployment completes. Supports environment variable substitution (%VER%, %PROJECT%). On script failure, only a warning is printed and execution continues.

import type { SdConfigFn } from "@simplysm/sd-cli";

const config: SdConfigFn = () => ({
  packages: {
    /* ... */
  },
  postPublish: [
    {
      type: "script",
      cmd: "curl",
      args: ["-X", "POST", "https://hooks.example.com/deploy?version=%VER%"],
    },
  ],
});

export default config;

Capacitor Configuration (SdCapacitorConfig)

Capacitor configuration for Android app builds in client target packages.

"my-app": {
  target: "client",
  server: 3000,
  capacitor: {
    appId: "com.example.myapp",
    appName: "My App",
    icon: "resources/icon.png",          // App icon (relative to package directory)
    debug: true,                          // Whether debug build
    plugins: {                            // Capacitor plugins
      "@capacitor/camera": true,
      "@capacitor/storage": { group: "myGroup" },
    },
    platform: {
      android: {
        config: {                         // AndroidManifest.xml application attributes
          requestLegacyExternalStorage: "true",
        },
        bundle: true,                     // AAB bundle build (APK if false)
        sdkVersion: 33,                   // Android SDK version
        permissions: [                    // Additional permissions
          { name: "CAMERA" },
          { name: "WRITE_EXTERNAL_STORAGE", maxSdkVersion: 29 },
        ],
        intentFilters: [                  // Intent Filters
          { action: "android.intent.action.VIEW", category: "android.intent.category.DEFAULT" },
        ],
        sign: {                           // APK/AAB signing
          keystore: "keystore.jks",
          storePassword: "password",
          alias: "key0",
          password: "password",
          keystoreType: "jks",              // Keystore type (optional, defaults to "jks")
        },
      },
    },
  },
},

Electron Configuration (SdElectronConfig)

Electron configuration for Windows desktop app builds in client target packages. Requires src/electron-main.ts entry point in the package directory.

"my-app": {
  target: "client",
  server: 3000,
  electron: {
    appId: "com.example.myapp",           // Electron app ID (required)
    portable: false,                       // true: portable .exe, false: NSIS installer
    installerIcon: "resources/icon.ico",   // Installer icon (.ico, relative to package directory)
    reinstallDependencies: ["better-sqlite3"], // npm packages to include (native modules etc.)
    postInstallScript: "node scripts/setup.js", // npm postinstall script
    nsisOptions: {},                       // NSIS options (when portable is false)
    env: {                                 // Environment variables (accessible via process.env in electron-main.ts)
      API_URL: "https://api.example.com",
    },
  },
},

How it works:

  • Initialize: Creates .electron/src/package.json, runs npm install, rebuilds native modules with electron-rebuild
  • Build: Bundles electron-main.ts with esbuild, copies web assets, runs electron-builder for Windows
  • Dev mode: Bundles electron-main.ts, launches Electron pointing to Vite dev server URL

Server Externals & PM2 Configuration

Server packages can configure external modules, package manager selection, and PM2 deployment settings.

Externals

Native modules (with binding.gyp) are automatically detected and externalized. You can also manually specify additional modules to exclude from the bundle:

"my-server": {
  target: "server",
  externals: ["cpu-features", "ssh2"],  // Manually externalize these modules
},

Package Manager Selection

The packageManager field controls which Node.js version management tool is used in production deployment:

"my-server": {
  target: "server",
  packageManager: "volta",  // Use Volta for Node.js version management
},

Supported package managers:

| Value | Behavior | Generated Files | |-------|----------|-----------------| | "volta" | Uses Volta for Node.js version management. PM2 config will execute node directly (Volta manages version via package.json engines field). | package.json includes volta field with Node.js version | | "mise" | Uses mise for Node.js version management. PM2 config will resolve interpreter path via mise which node. | mise.toml is copied to dist/ with Node.js version from root mise.toml | | undefined | No version management tool. PM2 config will execute node directly from system PATH. | No additional version management files |

Examples:

// Using Volta
"my-server": {
  target: "server",
  packageManager: "volta",
  pm2: {
    name: "my-app-server",
  },
},

// Using mise
"my-server": {
  target: "server",
  packageManager: "mise",
  pm2: {
    name: "my-app-server",
  },
},

// No package manager (use system PATH node)
"my-server": {
  target: "server",
  pm2: {
    name: "my-app-server",
  },
},

PM2 Configuration

When pm2 is configured, dist/pm2.config.cjs is generated during production build for use with PM2 process manager:

"my-server": {
  target: "server",
  packageManager: "mise",  // Optional: specify package manager
  env: {
    CUSTOM_VAR: "value",
  },
  pm2: {
    name: "my-app-server",           // PM2 process name (optional)
    ignoreWatchPaths: ["uploads"],   // Additional paths to ignore in PM2 watch (optional)
  },
},

Generated pm2.config.cjs includes:

  • Process name (from pm2.name or derived from package name)
  • Watch mode enabled with configurable ignore paths (node_modules, www + custom paths)
  • Node.js interpreter path (resolved via mise which node if packageManager: "mise", otherwise node from PATH)
  • --openssl-config=openssl.cnf interpreter argument for legacy TLS support
  • Environment variables: NODE_ENV=production, TZ=Asia/Seoul, plus custom env values

Deployment workflow:

# 1. Build the server
sd-cli build my-server

# 2. Copy dist/ to deployment server

# 3. On the deployment server:
cd /path/to/my-server/dist

# If using mise, install mise and activate
mise install  # Only needed if packageManager: "mise"

# Install externalized dependencies
npm install

# Start with PM2
pm2 start pm2.config.cjs

Cache

| Command | Cache Path | Description | | ------------- | ---------------------------------------------------- | ------------------------------------------------------------------ | | lint | .cache/eslint.cache | ESLint cache | | lint | .cache/stylelint.cache | Stylelint cache | | typecheck | packages/{pkg}/.cache/typecheck-{env}.tsbuildinfo | Incremental type-check info ({env} is node or browser) | | watch (dts) | packages/{pkg}/.cache/dts.tsbuildinfo | Incremental .d.ts build info |

To reset cache, delete the .cache directory:

# Delete all caches
rm -rf .cache packages/*/.cache

Caveats

  • sd.config.ts is required for watch, dev, build, publish, and device commands. typecheck and lint work without a config file.
  • The publish command automatically increments version and performs Git commit/tag/push. Execution is rejected if there are uncommitted changes.
  • publish --no-build deploys already-built artifacts as-is, so use with caution.
  • Before using the device command, run sd-cli dev or sd-cli watch first to initialize the Capacitor project.
  • During build, VER (project version) and DEV ("true" or "false") environment variables are automatically set.

License

Apache-2.0