Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .github/file-size-budget.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,10 @@ free/geocoding/internal/handlers.go 1087
free/geocoding/internal/provider/provider.go 406
free/github-runner/third_party/sdk/devkit/cmd/new-plugin/main.go 510
free/github-runner/third_party/sdk/identity.go 338
free/github/actions/sync.sh 422
free/idme/internal/handlers.go 536
free/invitations/third_party/sdk/devkit/cmd/new-plugin/main.go 510
free/invitations/third_party/sdk/identity.go 338
free/job-queue/go/api/handlers.go 356
free/jobs/actions/schedule.sh 310
free/link-preview/third_party/sdk/devkit/cmd/new-plugin/main.go 510
free/link-preview/third_party/sdk/identity.go 338
free/linkedin/internal/handlers.go 346
Expand All @@ -75,7 +73,6 @@ free/media-processing/ts/src/watcher.ts 320
free/meetings/internal/handlers.go 925
free/mlflow/third_party/sdk/devkit/cmd/new-plugin/main.go 510
free/mlflow/third_party/sdk/identity.go 338
free/notifications/actions/stats.sh 308
free/notifications/sdk/devkit/cmd/new-plugin/main.go 510
free/notifications/sdk/identity.go 338
free/notify/third_party/sdk/devkit/cmd/new-plugin/main.go 510
Expand Down Expand Up @@ -103,11 +100,9 @@ free/retro-gaming/internal/handlers.go 996
free/rom-discovery/internal/handlers.go 526
free/search/sdk/devkit/cmd/new-plugin/main.go 510
free/search/sdk/identity.go 338
free/shopify/actions/sync.sh 376
free/shopify/third_party/sdk/devkit/cmd/new-plugin/main.go 510
free/shopify/third_party/sdk/identity.go 338
free/sports/internal/handlers.go 876
free/stripe/actions/sync.sh 381
free/stripe/internal/db_schema.go 761
free/subtitle-manager/third_party/sdk/devkit/cmd/new-plugin/main.go 510
free/subtitle-manager/third_party/sdk/identity.go 338
Expand All @@ -130,8 +125,6 @@ free/webhooks/sdk/identity.go 338
free/workflows/internal/handlers.go 721
sdk/devkit/cmd/new-plugin/main.go 510
sdk/identity.go 338
shared/generate-plugin.sh 2069
shared/plugin-utils.sh 719
shared/src/database.ts 306
shared/src/webhook.ts 323
shared/validate-registry.sh 1020
3 changes: 1 addition & 2 deletions .github/wiki/Contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ Plugins live in `free/`, `community/`, and `monitoring/` directories. Each plugi
```
free/<plugin-name>/
plugin.json # Plugin manifest
install.sh # Installation script
README.md # Plugin-specific docs
docker-compose.yml # If adding a service
ts/src/ # TypeScript source
Expand Down Expand Up @@ -150,7 +149,7 @@ All checks must pass or your PR will fail automated validation.

1. Fork the repository
2. Create a feature branch from `main`
3. New plugins need a `plugin.json`, `install.sh`, and README
3. New plugins need a `plugin.json`, a Go `cmd/` entry point, and a README
4. Make your changes, following existing plugin patterns
5. Test with a local nSelf stack
6. Submit a PR with a clear description of what changed and why
Expand Down
253 changes: 11 additions & 242 deletions .github/wiki/Development.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,25 @@ Every plugin follows this structure:
```
plugins/<name>/
├── plugin.json # Plugin metadata (required)
├── install.sh # Installation script (required)
├── uninstall.sh # Uninstallation script (required)
├── cmd/ # Go service or CLI entry point (required)
├── migrations/ # Embedded SQL migrations, applied at boot (required for plugins with tables)
├── schema/
│ ├── tables.sql # Database schema (required)
│ └── migrations/ # Schema migrations (optional)
├── webhooks/
│ ├── handler.sh # Webhook dispatcher (optional)
│ └── events/ # Event handlers (optional)
├── actions/
│ └── *.sh # CLI actions (optional)
└── templates/
└── *.template # Config templates (optional)
│ └── tables.sql # Database schema reference
├── Dockerfile
└── docker-compose.plugin.yml
```

A plugin ships a binary. The CLI never runs per-plugin `install.sh`, `uninstall.sh`, `actions/*.sh` or
`webhooks/**/*.sh` scripts, and the repository carries none. Install, upgrade and removal go through
`nself plugin install|upgrade|remove`; migrations run when the service starts. Start from
`nself plugin new` and follow [Plugin Development](Plugin-Development.md).

## Creating a Plugin

### 1. Create Plugin Directory

```bash
mkdir -p plugins/my-service/{schema,webhooks/events,actions,templates}
mkdir -p plugins/my-service/{cmd,migrations,schema}
```

### 2. Create plugin.json
Expand Down Expand Up @@ -145,236 +144,6 @@ CREATE INDEX IF NOT EXISTS idx_np_myservice_webhooks_account
- Use UUID for primary keys (recommended)
- Include `created_at` and `synced_at` timestamps

### 4. Create Install Script

Create `install.sh`:

```bash
#!/bin/bash
set -euo pipefail

PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SHARED_DIR="$(dirname "$PLUGIN_DIR")/../shared"

source "${SHARED_DIR}/plugin-utils.sh"
source "${SHARED_DIR}/schema-sync.sh"

install_plugin() {
plugin_info "Installing my-service plugin..."

# Check environment
if ! plugin_check_env "myservice" "MYSERVICE_API_KEY"; then
plugin_warn "MYSERVICE_API_KEY not set"
fi

# Apply schema
plugin_db_exec_file "${PLUGIN_DIR}/schema/tables.sql"

plugin_success "Plugin installed!"
}

install_plugin
```

### 5. Create Uninstall Script

Create `uninstall.sh`:

```bash
#!/bin/bash
set -euo pipefail

PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SHARED_DIR="$(dirname "$PLUGIN_DIR")/../shared"

source "${SHARED_DIR}/plugin-utils.sh"

uninstall_plugin() {
local keep_data="${1:-false}"

plugin_info "Uninstalling my-service plugin..."

if [[ "$keep_data" != "true" ]]; then
plugin_db_query "DROP TABLE IF EXISTS myservice_webhooks CASCADE;"
plugin_db_query "DROP TABLE IF EXISTS myservice_items CASCADE;"
fi

plugin_success "Plugin uninstalled!"
}

uninstall_plugin "${1:-false}"
```

## Adding Actions

Actions are CLI commands users can run.

### Create an Action

Create `actions/sync.sh`:

```bash
#!/bin/bash
set -euo pipefail

PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SHARED_DIR="$(dirname "$PLUGIN_DIR")/../shared"

source "${SHARED_DIR}/plugin-utils.sh"

MYSERVICE_API_KEY="${MYSERVICE_API_KEY:-}"
MYSERVICE_API_BASE="https://api.myservice.com/v1"

api_request() {
local endpoint="$1"
curl -s \
-H "Authorization: Bearer ${MYSERVICE_API_KEY}" \
"${MYSERVICE_API_BASE}/${endpoint}"
}

sync_items() {
plugin_info "Syncing items..."

local response
response=$(api_request "items")

# Process and insert items
# ...

plugin_success "Sync complete!"
}

case "${1:-sync}" in
sync) sync_items ;;
-h|--help) echo "Usage: nself plugin my-service sync" ;;
*) echo "Unknown command: $1" ;;
esac
```

## Adding Webhook Support

### 1. Create Webhook Handler

Create `webhooks/handler.sh`:

```bash
#!/bin/bash
set -euo pipefail

PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SHARED_DIR="$(dirname "$PLUGIN_DIR")/../shared"

source "${SHARED_DIR}/plugin-utils.sh"

process_webhook() {
local payload="$1"

# Extract event type
local event_type
event_type=$(plugin_json_get "$payload" "type")

plugin_info "Received: $event_type"

# Record event
local event_id
event_id=$(plugin_json_get "$payload" "id")

plugin_db_query "
INSERT INTO myservice_webhooks (id, type, data)
VALUES ('$event_id', '$event_type', '$payload'::jsonb);
"

# Dispatch to event handler
local handler="${PLUGIN_DIR}/webhooks/events/${event_type}.sh"
if [[ -f "$handler" ]]; then
bash "$handler" "$payload"
fi
}

process_webhook "$1"
```

### 2. Create Event Handlers

Create `webhooks/events/item_created.sh`:

```bash
#!/bin/bash
set -euo pipefail

PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SHARED_DIR="$(dirname "$PLUGIN_DIR")/../shared"

source "${SHARED_DIR}/plugin-utils.sh"

handle_item_created() {
local payload="$1"

local item_id name
item_id=$(plugin_json_get "$payload" "item_id")
name=$(plugin_json_get "$payload" "name")

plugin_db_query "
INSERT INTO myservice_items (id, name, synced_at)
VALUES ('$item_id', '$name', NOW())
ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, synced_at = NOW();
"

plugin_success "Created item: $item_id"
}

handle_item_created "$@"
```

## Shared Utilities

Use the shared utilities for common operations:

### Database Operations

```bash
# Execute query
plugin_db_query "SELECT * FROM table;"

# Execute SQL file
plugin_db_exec_file "/path/to/file.sql"

# Check if table exists
if plugin_table_exists "myservice_items"; then
echo "Table exists"
fi
```

### HTTP Requests

```bash
plugin_http_get "https://api.example.com/endpoint"
plugin_http_post "https://api.example.com/endpoint" '{"data":"value"}'
```

### Logging

```bash
plugin_debug "Debug message"
plugin_info "Info message"
plugin_warn "Warning message"
plugin_error "Error message"
plugin_success "Success message"
```

### Caching

```bash
# Get cached value (TTL in seconds)
value=$(plugin_cache_get "my-plugin" "key" 3600)

# Set cached value
plugin_cache_set "my-plugin" "key" "value"

# Clear cache
plugin_cache_clear "my-plugin"
```

## Testing Your Plugin

### 1. Install Locally
Expand Down
4 changes: 2 additions & 2 deletions .github/wiki/architecture/Plugin-System.md
Original file line number Diff line number Diff line change
Expand Up @@ -1104,8 +1104,8 @@ import { StripeClient } from './client.ts';
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 6. Run post-install hook (if defined) │
│ bash plugins/stripe/install.sh │
│ 6. Post-install │
│ (no script runs; migrations apply when the service boots)│
└─────────────────────────────────────────────────────────────┘
│
▼
Expand Down
5 changes: 2 additions & 3 deletions .github/wiki/plugins/File-Processing.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,8 @@ The File Processing plugin provides background processing for uploaded files wit
## Quick Start

```bash
# Install dependencies
cd plugins/file-processing
./install.sh
# Install the plugin
nself plugin install file-processing

# Configure environment
echo "FILE_STORAGE_PROVIDER=minio" >> .env
Expand Down
12 changes: 2 additions & 10 deletions .github/wiki/plugins/IDme.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ The ID.me plugin provides a complete OAuth 2.0 integration with ID.me for govern
# 1. Register your application at developers.id.me

# 2. Install the plugin
cd plugins/idme
./install.sh
nself plugin install idme

# 3. Configure environment
cp .env.example .env
Expand Down Expand Up @@ -2892,14 +2891,7 @@ Error: Client authentication failed
Error: relation "np_idme_verifications" does not exist
```

**Solution:** Run the installer to create tables.

```bash
cd plugins/idme
./install.sh
```

Or initialize via CLI:
**Solution:** The plugin applies its migrations when it starts. Initialize via CLI:

```bash
nself plugin idme init
Expand Down
3 changes: 1 addition & 2 deletions .github/wiki/plugins/Notifications.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ The Notifications plugin provides a complete multi-channel notification system s

```bash
# Install the plugin
cd ~/Sites/nself-plugins/plugins/notifications
bash install.sh
nself plugin install notifications

# Install TypeScript dependencies
cd ts
Expand Down
Loading
Loading