# How to Create Custom Plugins Using the TREK Plugin SDK: Permissions and Development Guide

> Learn to create custom plugins with the TREK plugin SDK. Understand the strict permission model for building secure, isolated Node.js plugins.

- Repository: [Maurice/TREK](https://github.com/mauriceboe/TREK)
- Tags: how-to-guide
- Published: 2026-07-11

---

**The TREK plugin SDK provides a Node.js toolchain for building isolated plugins that run in child processes, enforcing a strict permission model declared in [`trek-plugin.json`](https://github.com/mauriceboe/TREK/blob/main/trek-plugin.json) where any unauthorized access throws `PERMISSION_DENIED`.**

The TREK plugin SDK (`trek-plugin-sdk`) is the official development toolchain for extending TREK instances with custom functionality. By scaffolding a Node.js package that exports a definition via `definePlugin`, developers can create widgets, page extensions, and third-party integrations that interact with TREK data through a strictly permissioned context object. This guide covers the complete workflow from initial scaffolding to production publishing, with specific attention to the runtime permissions model that governs every interaction.

## Scaffolding a New Plugin with the TREK Plugin SDK

The SDK provides an interactive wizard to bootstrap plugin projects. Running `npx trek-plugin-sdk create` launches a CLI that prompts for:

- **ID and location** – the plugin’s directory path
- **Type** – `widget`, `page`, `integration`, or `trip-page`
- **Permissions** – initial TREK capabilities the plugin requires

As documented in [`plugin-sdk/README.md`](https://github.com/mauriceboe/TREK/blob/main/plugin-sdk/README.md) lines 5-13, the wizard optionally initializes a Git repository and installs development dependencies, producing a ready-to-develop folder structure.

```bash

# Interactive wizard

npx trek-plugin-sdk create

# Non-interactive with flags

npx trek-plugin-sdk create my-plugin --type widget
cd my-plugin

```

## Live-Reload Development Environment

The `dev` command starts a local development server on **port 4317** that mirrors production constraints while enabling rapid iteration. According to [`plugin-sdk/README.md`](https://github.com/mauriceboe/TREK/blob/main/plugin-sdk/README.md) lines 21-24, the server:

- **Injects a `ctx` object** restricted to the permissions declared in your manifest
- Provides a SQLite database (`db:own`) for private plugin data
- Hot-reloads code changes without restarting

Access `http://localhost:4317/preview` to view your widget rendered inside an isolated iframe with the host’s theme applied.

```bash
npx trek-plugin-sdk dev

```

## Writing Plugin Code

### The definePlugin Export

Every plugin must export a definition created by `definePlugin`, as implemented in [`plugin-sdk/src/index.ts`](https://github.com/mauriceboe/TREK/blob/main/plugin-sdk/src/index.ts). The function accepts a configuration object containing lifecycle hooks and route definitions.

```javascript
// my-plugin/index.js
const { definePlugin } = require('trek-plugin-sdk')

module.exports = definePlugin({
  async onLoad(ctx) {
    // Initialize private database tables
    await ctx.db.migrate('001', 'CREATE TABLE cache (k TEXT PRIMARY KEY, v TEXT)')
  },

  routes: [
    {
      method: 'GET',
      path: '/status',
      auth: true,
      async handler(req, ctx) {
        return {
          status: 200,
          headers: { 'content-type': 'application/json' },
          body: '{"ok":true}'
        }
      }
    },
  ],
})

```

### The Permissioned Context Object

All interactions with TREK flow through the `ctx` object injected at runtime. The available methods—`ctx.db`, `ctx.invoke`, `ctx.notify`, and others—are filtered by the permission grants listed in your manifest. If your code attempts to call `ctx.db.write()` without the corresponding grant, the SDK immediately throws `PERMISSION_DENIED`.

## Understanding the TREK Plugin Permissions Model

Permissions are declared in [`trek-plugin.json`](https://github.com/mauriceboe/TREK/blob/main/trek-plugin.json) under the `grants` key. The manifest schema is defined in [`plugin-sdk/src/manifest.ts`](https://github.com/mauriceboe/TREK/blob/main/plugin-sdk/src/manifest.ts), while human-readable descriptions reside in [`shared/src/i18n/zh/admin.ts`](https://github.com/mauriceboe/TREK/blob/main/shared/src/i18n/zh/admin.ts) lines 220-239.

```json
{
  "id": "my-plugin",
  "apiVersion": 1,
  "grants": [
    "db:own",
    "db:read:trips",
    "ws:broadcast:trip"
  ]
}

```

**Core permission categories include:**

- **`db:*`** – Access to database capabilities. `db:own` grants a private SQLite sandbox, while `db:read:*` and `db:write:*` control access to specific TREK entities.
- **`ws:broadcast:*`** – Permission to send real-time WebSocket messages to trips or individual users.
- **`http:outbound`** – Allows the plugin to make external HTTP requests to approved hosts.
- **`hook:*`** – Registers the plugin as an extension provider for features like photo sources or calendar integrations.

At runtime, the loader in [`server/src/nest/plugins/runtime/plugin-sdk.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/nest/plugins/runtime/plugin-sdk.ts) validates every `ctx` method call against the manifest’s `grants` array. Unauthorized calls throw `PERMISSION_DENIED`, which your plugin can catch to implement graceful degradation.

## Testing Without a Running Instance

The SDK ships with a testing harness that enforces the exact same permission model as production. Import `createMockHost` from `trek-plugin-sdk/testing` to instantiate a mock context for unit testing, as shown in [`plugin-sdk/README.md`](https://github.com/mauriceboe/TREK/blob/main/plugin-sdk/README.md) lines 82-90.

```javascript
import { createMockHost } from 'trek-plugin-sdk/testing'

const { ctx, broadcasts } = createMockHost({
  grants: ['db:read:trips', 'ws:broadcast:trip'],
  trips: { 1: { members: [42], data: { id: 1, name: 'Japan' } } },
})

// Exercise your plugin logic against the restricted ctx

```

## Packaging and Publishing

When development is complete, the SDK provides commands to prepare your plugin for distribution:

1. **`pack`** – Creates a signed `.trekplugin` archive from your build output
2. **`publish`** – Uploads to a GitHub release and opens a PR against the TREK plugin registry

```bash

# Create distributable archive

npx trek-plugin-sdk pack .

# Publish to registry (requires GitHub authentication)

npx trek-plugin-sdk publish --repo you/repo --tag v1.0.0

```

Optional signing via `keygen` and `sign` commands provides cryptographic verification for trust-on-first-use scenarios.

## Summary

- **Scaffold** new plugins using `npx trek-plugin-sdk create`, selecting the appropriate type and initial permissions.
- **Develop** against a live-reload server on port 4317 where the `ctx` object reflects your declared permissions.
- **Declare** all required capabilities in [`trek-plugin.json`](https://github.com/mauriceboe/TREK/blob/main/trek-plugin.json) under the `grants` key; the runtime enforces these strictly via `PERMISSION_DENIED` errors.
- **Test** logic offline using `createMockHost` from the testing submodule to verify behavior under different permission configurations.
- **Distribute** by packing into `.trekplugin` archives and publishing to the registry via the SDK CLI.

## Frequently Asked Questions

### What permissions do I need to access the database in a TREK plugin?

You must declare `db:own` in your [`trek-plugin.json`](https://github.com/mauriceboe/TREK/blob/main/trek-plugin.json) grants to receive a private SQLite sandbox, or specific `db:read:*` and `db:write:*` grants to access TREK entity data. Any call to `ctx.db` without the appropriate permission throws `PERMISSION_DENIED` instead of executing.

### How does the TREK plugin SDK isolate plugins from the host system?

The SDK executes each plugin in a separate child process and injects the `trek-plugin-sdk` module at runtime. All access to TREK services flows through the `ctx` object, which is filtered by the permission list in your manifest. This architecture prevents plugins from accessing system resources or data outside their declared grants.

### Can I test my plugin without running a full TREK server?

Yes. The SDK provides `createMockHost` in the `trek-plugin-sdk/testing` submodule. This function creates a mock `ctx` object that enforces the same permission model as the production runtime, allowing you to write unit tests that verify behavior when specific grants are missing or present.

### What file declares the permissions for a TREK plugin?

The [`trek-plugin.json`](https://github.com/mauriceboe/TREK/blob/main/trek-plugin.json) file in your plugin root declares permissions under the `grants` key. This manifest is validated against the schema defined in [`plugin-sdk/src/manifest.ts`](https://github.com/mauriceboe/TREK/blob/main/plugin-sdk/src/manifest.ts) and enforced at runtime by the loader in [`server/src/nest/plugins/runtime/plugin-sdk.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/nest/plugins/runtime/plugin-sdk.ts).