Youwee LogoYouwee

Plugin SDK Reference

Complete documentation for youwee-sdk (v2.2.0), the JavaScript/TypeScript authoring toolchain for building, signing, and distributing Youwee plugins.

1. Getting Started

SDK Overview

Youwee plugins are written in JavaScript/TypeScript and execute in a capability-based Deno sandbox. The SDK provides local development commands (using Bun), typescript typings, and access to app-mediated APIs for writing notification hooks, storage uploading, or post-processing tools. Note that Youwee executes packaged .ywp files, not raw workspaces.

Key Concepts

Workspace

Plugin Workspace: The source directory containing your configurations, locales, and code. This is where you write and test code.

Packaged (.ywp)

Packaged Plugin (.ywp): A signed archive produced from the workspace. Contains bundled code, checksums, and signature files. Only signed .ywp packages can be imported by users.

Distribution Rule

Important Rule: Workspaces are strictly for development. End-user distribution must use the signed .ywp format.

Development Lifecycle

1

Create a workspace folder containing plugin.json, package.json, and src/plugin.ts.

2

Install dependencies (bun install) with "youwee-sdk": "^2.2.0" in your package.json.

3

Configure your plugin metadata and triggers in plugin.json.

4

Write your hook functions in src/plugin.ts using the definePlugin(...) contract.

5

Add localized resources in locales/ (e.g. en.json, vi.json).

6

Run local typecheck (bun run typecheck) and runtime tests (bun run test:deno).

7

Build the bundled code: bunx youwee-sdk build (creates dist/plugin.cjs).

8

Generate signing keypair: bunx youwee-sdk keygen ./plugin.youwee-plugin-key.json.

9

Pack and sign: bunx youwee-sdk pack --private-key ./plugin.youwee-plugin-key.json (creates release/<slug>.ywp).

10

Import the signed .ywp file into Youwee settings or attach the workspace for live debugging.

Recommended Workspace Layout

workspace-structure.txt
my-plugin/
  plugin.json              # Plugin identity, permissions & settings config
  package.json             # NPM package properties & SDK dependency range
  tsconfig.json            # Editor and compiler configurations
  README.md                # Default documentation shown inside Youwee UI
  README.vi.md             # Localized Vietnamese documentation
  CHANGELOG.md             # Version history
  src/
    plugin.ts              # Entrypoint where definePlugin() hooks reside
  locales/
    en.json                # English translation keys
    vi.json                # Vietnamese translation keys
  dist/
    plugin.cjs             # Generated production runtime bundle
  release/
    my-plugin.ywp          # Signed packaged output imported into Youwee

GitHub Actions in Workspace

Workspace scaffolds generated by Youwee include preconfigured GitHub actions:

CI Workflow (.github/workflows/ci.yml)

ci.yml: Runs type checking, code bundling, and contract tests against the Deno sandbox model.

.github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v1
      - run: bun install
      - run: bun run typecheck
      - run: bun run build
      - run: bun run test:deno

Release Workflow (.github/workflows/release.yml)

release.yml: Automates release packing, generates sha256 checksums, signs with the YOUWEE_PLUGIN_SIGNING_KEY repository secret, and uploads the final .ywp package to GitHub releases.

Requires GitHub Repository Secret: YOUWEE_PLUGIN_SIGNING_KEY
.github/workflows/release.yml
name: Release Package
on:
  push:
    tags:
      - 'v*'
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v1
      - run: bun install
      - run: bun run build
      - run: echo "${{ secrets.YOUWEE_PLUGIN_SIGNING_KEY }}" > ./plugin-key.json
      - run: bunx youwee-sdk pack --private-key ./plugin-key.json

2. Manifest & Permissions

Every plugin must declare a plugin.json file. It defines identity, compatibility ranges, permissions, triggers, and configuration UI schemas.

plugin.json
{
  "id": "local.gg-drive",
  "slug": "gg-drive",
  "name": "GG Drive",
  "version": "0.1.0",
  "runtime": {
    "language": "javascript",
    "supportedProviders": ["deno"],
    "preferredProvider": "deno",
    "entrypoint": "src/plugin.ts"
  },
  "compatibility": {
    "appVersion": ">=0.15.0 <0.16.0",
    "sdkVersion": ">=2.2.0 <3.0.0"
  },
  "triggers": [
    "download.completed"
  ],
  "permissions": {
    "network": true,
    "fs": [
      "fs.payload-file.read",
      "fs.user-selected.write"
    ],
    "tools": [
      "tool.ffmpeg.run"
    ]
  },
  "configFields": [
    {
      "key": "driveFolderId",
      "inputType": "text",
      "label": "Folder ID",
      "required": true
    }
  ],
  "i18n": {
    "defaultLocale": "en",
    "supportedLocales": ["en", "vi"],
    "directory": "locales"
  }
}

Identity Fields

id (immutable reverse-DNS name), slug (URL-safe string for paths), name (UI display name), and version.

Runtime Settings

language must be "javascript", supportedProviders must contain "deno", and entrypoint points to the workspace source code.

Lifecycle Triggers

List of triggers in plugin.json must use raw runtime strings (do not use triggers.downloadCompleted properties):

  • download.queued: Fired when download is added to the download queue.
  • download.beforeStart: Fired just before the downloader initializes connection.
  • download.completed: Fired when the download succeeds and outputs a file.
  • download.failed: Fired when the download job terminates with an error.
Do not declare trigger mappings using Javascript variables inside plugin.json. Always use raw strings.

Capability Permissions

Youwee plugins run in a secure sandbox. Direct Deno filesystem and process spawning APIs are disabled. Instead, you declare capability permission scopes in plugin.json:

Network Access

network: true - Grants outbound network fetch requests and YouTube API searches.

Filesystem Access

fs: Granular filesystem capabilities like fs.payload-file.read (access downloaded file), fs.payload-directory.read/write (neighboring files), fs.temp.read/write (scratchspace), and fs.user-selected.read/write (user config inputs).

Tool Execution

tools: tool.ffmpeg.run and tool.ytdlp.run - Grants permission to run application-bundled yt-dlp and FFmpeg binaries.

YouTube Keyword Search API

When network: true is approved, plugins can request Youwee to perform keyword searches on YouTube using the app's managed connection. Excellent for finding matching videos, captions, or checking metadata:

youtube-search.ts
const results = await ctx.youwee.youtube.searchVideos({
  query: "hd drone flight 4k",
  limit: 10,
  filters: {
    uploadDate: "thisWeek",     // today, thisWeek, thisMonth, thisYear
    duration: "short",         // short (<4m), medium (4-20m), long (>20m)
    sort: "viewCount",         // relevance, viewCount
    features: ["hd", "creativeCommons"] // live, fourK, hd, subtitles, creativeCommons, etc.
  }
});

// Loading next page using continuation tokens
if (results.continuation) {
  const nextPage = await ctx.youwee.youtube.searchVideos({
    query: "hd drone flight 4k",
    continuation: results.continuation,
    limit: 10
  });
}

Configuration Fields (configFields)

Declare custom fields in configFields to let Youwee auto-render settings inputs. Supported input types: text, textarea, password (securely masked), number, boolean, file, directory, select, and multi-select. Saved variables are injected into runtime context.

3. Coding & Execution Context

Plugin Module Contract

The plugin module entrypoint must export a default object defined with definePlugin(...) that conforms to PluginDefinition.

src/plugin.ts
import { definePlugin, triggers, type PluginDefinition } from "youwee-sdk";

const plugin = definePlugin({
  meta: {
    name: "My Post Processor",
    version: "1.0.0",
    description: "Converts output audio or triggers hooks after download."
  },
  hooks: {
    [triggers.downloadCompleted]: async (ctx) => {
      ctx.log.info(ctx.i18n.t("process.start", { file: ctx.file.name }));
      
      // Perform app bridge mediated filesystem and tool tasks
      const text = await ctx.youwee.fs.readText(ctx.file.path);
      ctx.log.info("Read file contents successfully");

      return ctx.ok("Job done successfully", { processedLines: text.split("\n").length });
    }
  }
} satisfies PluginDefinition);

export default plugin;

Execution Context (ctx)

Each hook function receives a ctx argument containing payload metadata, configuration helpers, and secure app bridges.

ctx.trigger

The string identifier of the event triggering this execution.

ctx.download

Metadata about the job (e.g. jobId, kind).

ctx.file

Information about the file (e.g. path, name, size).

ctx.media

Information about the source media (e.g. url, title).

ctx.config

Access settings (get(key), require(key), has(key), all()).

ctx.log

Safe logging methods (info, warn, error). Logs are shown in Youwee UI.

ctx.i18n

Localized translation helper (t(key, params), has(key), raw(key)).

ctx.youwee

Meditated bridge APIs for filesystem, tools, and YouTube searches.

App Bridge APIs (ctx.youwee)

The ctx.youwee namespace exposes capability-based APIs that act as safe proxies to read/write files, call CLI tools, or perform keyword queries using the main application process's active sessions.

Filesystem Access (ctx.youwee.fs)

Read and write strings, binary data, or base64 files, manage directories, and create temporary files within sandboxed boundaries.

filesystem-operations.ts
// UTF-8 Text read/write
const text = await ctx.youwee.fs.readText(ctx.file.path);
await ctx.youwee.fs.writeText(outputPath, text);

// Binary read/write (e.g. metadata, cover images)
const bytes = await ctx.youwee.fs.readBytes(ctx.file.path);
await ctx.youwee.fs.writeBytes(outputPath, bytes);

// Base64-encoded binary helper
const base64 = await ctx.youwee.fs.readBase64(ctx.file.path);
await ctx.youwee.fs.writeBase64(outputPath, base64);

// Directory & Temp operations
const files = await ctx.youwee.fs.readDir(approvedDirPath);
await ctx.youwee.fs.ensureDir(newDirPath);
const tempPath = await ctx.youwee.fs.tempDir("plugin-task-");

// Secure Cleanup
await ctx.youwee.fs.removeFile(tempPath + "/file.tmp");

CLI Tools Runner (ctx.youwee.tools)

Spawn bundled instances of FFmpeg or yt-dlp to perform post-processing tasks, such as audio conversion, metadata embedding, or custom extraction.

tools-execution.ts
// Run app-bundled FFmpeg command
const ffmpegResult = await ctx.youwee.tools.ffmpeg.run([
  "-i", ctx.file.path,
  "-vn",
  "-acodec", "libmp3lame",
  outputPath
]);

// Run app-bundled yt-dlp command
const ytdlpResult = await ctx.youwee.tools.ytdlp.run([
  "--version"
]);

// Both return: { success: boolean, code: number, stdout: string, stderr: string }

YouTube Keyword Search (ctx.youwee.youtube)

Run search queries on YouTube to retrieve video arrays and metadata without making raw external network requests.

youtube-search-api.ts
const results = await ctx.youwee.youtube.searchVideos({
  query: "lofi study beats",
  limit: 15
});

SDK Runtime Compatibility (ctx.youwee.sdk)

Inspect the active youwee-sdk runtime versions and assert if the host Youwee app version satisfies target compatibility ranges.

compatibility-checks.ts
// Read SDK runtime version
const sdkVersion = ctx.youwee.sdk.version;

// Check compatibility range returns boolean
const isCompatible = ctx.youwee.sdk.checkAppVersion(">=0.15.0");

// Assert range throws a compatible error on failure
ctx.youwee.sdk.assertAppVersion(">=0.15.0");

Results & Pipeline Mutations

Plugins return ctx.ok(message?, metadata?) for success, and ctx.fail(message?, metadata?) for failure. The return object can include mutations to pass file paths or metadata changes to subsequent plugins in the chain:

mutations.ts
return {
  success: true,
  message: "Conversion complete",
  mutations: {
    activeFilepath: "/users/downloads/converted.mp3",
    activeFilename: "converted.mp3",
    extraFiles: ["/users/downloads/converted.vtt"]
  }
};
activeFilepath: Overwrites the target file path in the workflow pipeline.
activeFilename: Overwrites the display filename.
extraFiles: Appends companion file paths (e.g. subtitles, thumbnails) to the pipeline state.
metadataPatch: Patches metadata parameters for downstream steps.

Internationalization (i18n)

To localize messages, declare i18n properties (defaultLocale, supportedLocales, directory) in plugin.json. Place JSON translation files in the locales folder (e.g. locales/en.json, locales/vi.json). Key translations are resolved dynamically from current app language.

Fallback Chain Order

  1. 1. Current active Youwee application locale
  2. 2. Application default fallback locale
  3. 3. Plugin's defaultLocale declared in manifest
  4. 4. Raw translation key string
locales/en.json
locales/en.json
{
  "process.start": "Starting conversion of {{file}}"
}
src/plugin.ts
src/plugin.ts
ctx.i18n.t("process.start", { file: ctx.file.name })

4. Toolchain & Debugging

Build & Pack Commands

Use the Bun authoring toolchain to build and sign your plugin workspace:

bunx youwee-sdk build

Builds and bundles TypeScript files into a single bundle: dist/plugin.cjs.

bunx youwee-sdk keygen [path]

Generates a secure Ed25519 signing keypair file.

bunx youwee-sdk pack --private-key [path]

Validates files, generates checksums and signatures, and outputs a signed .ywp package into release/.

Packaged Archive Structure

The packed .ywp file is a standard ZIP archive containing the following strict layout. Youwee inspects and verifies these files at import time:

packaged-structure.txt
manifest.json        # Compiled static runtime manifest
build.json           # SDK compiler & format metadata
checksums.json       # SHA-256 integrity map for all files
signature.json       # Ed25519 payload signature
dist/
  plugin.cjs         # Main compiled Javascript runtime
locales/
  en.json            # English translations
  vi.json            # Vietnamese translations
README.md            # Default read documentation
  • manifest.json: Packed production manifest.
  • build.json: SDK version metadata and build package formats.
  • checksums.json: SHA-256 hashes of all bundled assets and files.
  • signature.json: Ed25519 signatures validating the integrity of checksums.json.
  • dist/plugin.cjs: Bundled JavaScript production runtime.
  • locales/: Bundled localization files.
  • README.md / CHANGELOG.md: Documentation rendered in Youwee UI.

Debugging & Live Workspaces

For quick iteration without building .ywp packages continually, use Youwee's Attach Workspace development flow:

  1. In Youwee, go to Settings > Plugins.
  2. Choose Attach Workspace and select your plugin workspace folder.
  3. Enable the attached plugin and assign it to a test workflow.
  4. Edit your src/plugin.ts or plugin.json files. Youwee reload is instant — trigger the workflow again to see updates.
Note: Direct Deno write/run permissions are still blocked in live workspaces. Meditated ctx.youwee APIs must be used.

Troubleshooting FAQ

Q:Deno throws permission errors (--allow-write or --allow-run)

A:Direct OS filesystem APIs and Deno command calls are blocked. Re-write your logic to use ctx.youwee.fs.* methods and ctx.youwee.tools.* methods instead.

Q:Plugin imports successfully but does not trigger

A:Verify the plugin is enabled in Settings > Plugins, appropriate triggers are requested in plugin.json, and the plugin has been assigned to active workflows.

Q:The manifest says my triggers are invalid

A:Ensure you are using raw trigger strings (e.g. "download.completed") instead of code properties (e.g. "triggers.downloadCompleted") in plugin.json.

Q:Environment variable fields are empty

A:Configuring user settings via permissions.env is obsolete. Use configFields in plugin.json to auto-render fields in the settings UI.