Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.skyvexsoftware.com/llms.txt

Use this file to discover all available pages before exploring further.

Plugins are built with Vite using a shared config factory from the SDK. The output is zipped and uploaded to the Skyvex website for distribution.

Vite Configuration

Use createPluginConfig() from the SDK:
// vite.config.ts
import { createPluginConfig } from "@skyvexsoftware/stratos-sdk/vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";

export default createPluginConfig({
  ui: { entry: "src/ui/index.tsx" },
  background: { entry: "src/background/index.ts" }, // optional
  vite: {
    plugins: [tailwindcss(), react()],
  },
});
The vite option accepts any Vite config to merge in — plugins, resolve aliases, CSS config, etc.
@vitejs/plugin-react is required, not optional. The SDK injects a React Fast Refresh preamble into your entry file that imports from /@react-refresh — an endpoint only served when react() is registered. Without it, pnpm dev against a running Stratos will fail to load the plugin UI with a cross-origin module error.
If you only have a UI module, omit the background field.

Build Scripts

With background module:
{
  "scripts": {
    "dev": "vite",
    "build": "vite build && cross-env BUILD_TARGET=background vite build",
    "build:ui": "vite build",
    "build:bg": "cross-env BUILD_TARGET=background vite build",
    "bundle": "pnpm build && stratos-deploy"
  }
}
UI-only plugin:
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "bundle": "pnpm build && stratos-deploy"
  }
}
Use cross-env for Windows compatibility with the BUILD_TARGET environment variable.

How the Build Works

UI build (default): Compiles your React code into a single ESM bundle. Shared dependencies are externalised and resolved from the shell at runtime via window.__stratos_modules__. Background build (BUILD_TARGET=background): Compiles your Node.js module into an ESM bundle. Electron, Node.js builtins, and the SDK are externalised.

CSS and Static Assets

Plugins are loaded at runtime via import(), so CSS and assets must be embedded in the JS bundle — separate files won’t be loaded. CSS injection is handled automatically. Any CSS you import (including Tailwind output from @tailwindcss/vite) is injected into the DOM as a <style> tag when your plugin module loads. The shell wraps all plugin CSS in @layer plugin to prevent your styles from overriding the shell’s UI — you don’t need to do anything special for this. Your plugin’s styles.css should include Tailwind and a @source directive so Tailwind can find your component files:
src/ui/styles.css
@import "tailwindcss";
@source "./**/*.{ts,tsx}";
Import it in your plugin’s entry file:
import "./styles.css";
import "./hero-banner.css";  // any additional custom CSS
Static assets (images, SVGs, fonts) under 10 MB are inlined as data URIs automatically. Import them as usual and use the result as a src:
import logo from "./assets/logo.svg";
import badge from "../assets/badge-icon.svg";

<img src={logo} alt="Logo" />
<img src={badge} alt="Badge" className="h-5 w-5" />
This works for any file type Vite can handle (.svg, .png, .jpg, .webp, .woff2, etc.).

What Gets Externalized

You do not need to bundle these — the shell provides them at runtime: UI externals:
  • react, react-dom
  • @tanstack/react-query, @tanstack/react-router
  • @skyvexsoftware/stratos-sdk
  • sonner, socket.io-client
  • maplibre-gl, react-map-gl/maplibre
Background externals:
  • electron
  • @skyvexsoftware/stratos-sdk (except /helpers, which is bundled into your plugin)
  • socket.io-client
  • All Node.js built-in modules
Anything else you import (e.g. lucide-react, your own utilities) will be bundled into your plugin.

Build Output

After pnpm build, the dist/ directory contains:
dist/
├── plugin.json                ← copied from root
├── assets/                    ← icons (for sidebar display)
│   ├── icon-light.svg
│   └── icon-dark.svg
├── ui/
│   └── index.js               ← bundled UI module (ESM, CSS + assets inlined)
└── background/                 ← only if background module exists
    └── index.js               ← bundled background module (ESM)
CSS and imported static assets are embedded directly in ui/index.js — there are no separate .css files in the output.

Development Workflow

Live Reload Development

The recommended development workflow uses the Stratos app’s dev mode:
  1. Open Stratos with the --dev flag
  2. Log in and select your airline
  3. In your plugin directory:
pnpm dev
Your plugin’s Vite dev server auto-connects to Stratos via Socket.io. The plugin appears in the sidebar immediately. Code changes auto-reload in about a second.
✓ Vite dev server running at http://localhost:5174
✓ Connected to Stratos (localhost:2066)
✓ Plugin "my-plugin" mounted
ChangeBehavior
UI component code (src/ui/**)Auto-reloads on save
CSS / Tailwind classesAuto-reloads on save
Background module (src/background/**)Auto-rebuilds and hot-reloads
plugin.jsonRestart pnpm dev
New dependenciesRun pnpm install then restart pnpm dev

Manual Testing (No Dev Server)

If you prefer to test with a production build:
  1. Run pnpm build
  2. Copy the dist/ contents to Stratos’s plugins directory:
PlatformPath
macOS~/Library/Application Support/Stratos/plugins/my-plugin/
Windows%APPDATA%\Stratos\plugins\my-plugin\
Linux~/.config/Stratos/plugins/my-plugin/
  1. Restart Stratos — it discovers plugins by finding plugin.json in each subdirectory.
Tip: Symlink your dist/ directory to skip the copy step:
# macOS
ln -s "$(pwd)/dist" ~/Library/Application\ Support/Stratos/plugins/my-plugin

Deploying

Quick Deploy

The SDK includes a stratos-deploy CLI that bundles and uploads your plugin in one step:
pnpm bundle
This runs pnpm build, zips dist/ into bundle.zip, and uploads it to the Skyvex API. Your package.json should have:
{
  "scripts": {
    "bundle": "pnpm build && stratos-deploy"
  }
}
If you scaffolded your plugin with create-stratos-plugin, this script is already included.

Authentication

Generate an API key from your account settings at skyvexsoftware.com, then set it as an environment variable:
SKYVEX_API_TOKEN=your-token pnpm bundle
The plugin ID and version are read from plugin.json automatically. On success, the Skyvex server validates, signs, and publishes your plugin to the CDN.

Manual Upload

If you don’t have an API token or prefer to upload through the website:
pnpm bundle
Without SKYVEX_API_TOKEN, the command still builds and creates bundle.zip — it just skips the upload and tells you where to upload manually at skyvexsoftware.com.

CI/CD

For automated deployments, set SKYVEX_API_TOKEN as a secret in your CI environment:
# GitHub Actions example
- name: Deploy plugin
  run: pnpm bundle
  env:
    SKYVEX_API_TOKEN: ${{ secrets.SKYVEX_API_TOKEN }}

What Happens After Upload

  1. The Skyvex API validates your plugin.json manifest
  2. An .integrity file is generated with SHA256 hashes for every file in your bundle
  3. The bundle is signed with Ed25519 and republished to the CDN
  4. latest.json is updated so Stratos clients detect the new version
  5. Users receive the update automatically

Troubleshooting

ErrorCauseFix
”No built plugin found”dist/ doesn’t existRun pnpm build first, or use pnpm bundle which builds automatically
”Version X already exists”This version is already publishedBump the version in plugin.json
”Authentication failed”Invalid or expired tokenGenerate a new token at skyvexsoftware.com
”Permission denied”Token doesn’t own this pluginCheck you’re using the correct account’s token
”Build output incomplete”dist/ui/index.js is missingCheck your Vite config and build output

Airline Plugin Sync

When a plugin has "type": "airline", the VA platform manages distribution. Stratos automatically syncs the plugin set on authentication:
  1. Pilot logs in to their VA
  2. Shell fetches the airline’s public plugin list (every plugin the VA has installed for everyone, plus core plugins)
  3. After relay-token authentication, the shell fetches the pilot-scoped list — this returns the airline-wide plugins plus any extras the VA admin has assigned to that specific pilot
  4. Missing plugins are downloaded and installed automatically; removed plugins are cleaned up
  5. Updates are applied automatically when new versions are published
VA admins choose, per plugin, whether to install it for all pilots or only for selected pilots from the airline management panel. Pilot-specific assignments only appear in the post-login (relay-authenticated) plugin list, never in the public airline list. For "user" type plugins, pilots install them manually.

CDN Layout

Plugin artifacts are stored at:
cdn.skyvexsoftware.com/stratos/plugins/
  {author.id}/
    {plugin.id}/
      latest.json                    ← current version metadata
      {version}/
        bundle.zip                   ← plugin bundle for this version

latest.json Format

{
  "version": "1.1.0",
  "sha256": "abc123...",
  "minShellVersion": "1.20.0",
  "updatedAt": "2026-02-25T10:00:00Z"
}
The shell’s plugin updater reads latest.json to detect available updates, verifies integrity via SHA256, and checks shell version compatibility before installing.