# Oasis Server Setup

> Expert guide for integrating Oasis update server with Tauri apps for auto-updates, crash reporting, and feedback collection.

- Skill: `porkytheblack/oasis-server-setup` (Agent Skill)
- Install (CLI): `npx skillmds@latest add porkytheblack/oasis-server-setup`
- Raw SKILL.md: https://api.skillmd.com/api/skills/porkytheblack/oasis-server-setup/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: porkytheblack (https://skillmd.com/u/porkytheblack)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/porkytheblack/oasis-server-setup

---


# Oasis Server Setup — Development Guide

You are an expert on the Oasis update server. Use this knowledge when configuring auto-updates, crash reporting, or feedback collection for Tauri applications.

## What It Is

Oasis is a self-hosted release management and analytics server for Tauri applications. It provides update manifests, crash reporting, and feedback collection.

**Server repo**: https://github.com/porkytheblack/oasis
**Reusable workflow**: `porkytheblack/oasis/.github/workflows/tauri-release.yml@main`

## Architecture at a Glance

```
┌─────────────────────────────────────────────────────────────────┐
│                      Tauri Desktop App                           │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐  │
│  │ Auto-Update │  │ Crash SDK   │  │ Feedback SDK            │  │
│  └──────┬──────┘  └──────┬──────┘  └───────────┬─────────────┘  │
└─────────┼────────────────┼─────────────────────┼────────────────┘
          │                │                     │
          ▼                ▼                     ▼
┌─────────────────────────────────────────────────────────────────┐
│                        Oasis Server                              │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐  │
│  │ /update     │  │ /crashes    │  │ /feedback               │  │
│  │ manifests   │  │ collection  │  │ collection              │  │
│  └──────┬──────┘  └─────────────┘  └─────────────────────────┘  │
└─────────┼───────────────────────────────────────────────────────┘
          │
          ▼
┌─────────────────────────────────────────────────────────────────┐
│                    Cloudflare R2 (CDN)                           │
│         Artifact storage: .dmg, .exe, .AppImage                  │
└─────────────────────────────────────────────────────────────────┘
```

## Quick Start

### 1. Generate signing keys

```bash
npx @tauri-apps/cli signer generate -w ~/.tauri/keys/your-app.key
# Output: Public key + private key file
```

### 2. Configure tauri.conf.json

```json
{
  "plugins": {
    "updater": {
      "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6...",
      "endpoints": [
        "https://oasis.yourdomain.com/your-app/update/{{target}}-{{arch}}/{{current_version}}"
      ],
      "windows": {
        "installMode": "passive"
      }
    }
  }
}
```

### 3. Add updater capabilities

```json
// capabilities/default.json
{
  "permissions": [
    "updater:default",
    "updater:allow-check",
    "updater:allow-download-and-install",
    "process:default",
    "process:allow-restart"
  ]
}
```

### 4. Install Oasis SDK

```bash
pnpm add @oasis/sdk
```

### 5. Initialize SDK

```typescript
// lib/oasis.ts
import { initOasis } from '@oasis/sdk';

export const oasis = initOasis({
  apiKey: process.env.NEXT_PUBLIC_OASIS_API_KEY!,
  serverUrl: process.env.NEXT_PUBLIC_OASIS_SERVER_URL!,
  appVersion: '0.1.0',
  enableAutoCrashReporting: true,
});
```

### 6. Check for updates

```typescript
import { check } from '@tauri-apps/plugin-updater';
import { relaunch } from '@tauri-apps/plugin-process';

async function checkForUpdates() {
  const update = await check();
  if (update?.available) {
    await update.downloadAndInstall();
    await relaunch();
  }
}
```

## API Endpoints

| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/{app_slug}/update/{target}-{arch}/{version}` | GET | Update manifest |
| `/sdk/{app_slug}/feedback` | POST | Submit feedback |
| `/sdk/{app_slug}/crashes` | POST | Report crashes |
| `/api/releases/{app_slug}` | POST | Register release (CI only) |

## Update Manifest Response

```json
{
  "version": "0.2.0",
  "notes": "Bug fixes and improvements",
  "pub_date": "2024-01-15T10:00:00Z",
  "platforms": {
    "darwin-aarch64": {
      "signature": "dW50cnVzdGVkIGNvbW1lbnQ6...",
      "url": "https://cdn.example.com/app/v0.2.0/App_aarch64.app.tar.gz"
    },
    "darwin-x86_64": {
      "signature": "...",
      "url": "https://cdn.example.com/app/v0.2.0/App_x64.app.tar.gz"
    },
    "windows-x86_64": {
      "signature": "...",
      "url": "https://cdn.example.com/app/v0.2.0/App_x64-setup.nsis.zip"
    },
    "linux-x86_64": {
      "signature": "...",
      "url": "https://cdn.example.com/app/v0.2.0/App_amd64.AppImage.tar.gz"
    }
  }
}
```

No update available returns `HTTP 204 No Content`.

## Template Variables

| Variable | Description | Example |
|----------|-------------|---------|
| `{{target}}` | Operating system | `darwin`, `windows`, `linux` |
| `{{arch}}` | CPU architecture | `x86_64`, `aarch64` |
| `{{current_version}}` | App version | `0.1.0` |

## API Keys

| Key Type | Format | Purpose |
|----------|--------|---------|
| Public Key | `pk_{app-slug}_{random}` | SDK operations (client-side) |
| CI Key | `ci_{app-slug}_{random}` | Release registration (server-side) |

Example: `pk_coco_a1b2c3d4e5f6g7h8`

## SDK Usage Patterns

### Feedback Submission

```typescript
// Categorized feedback
await oasis.feedback.submit({
  category: 'bug',        // 'bug' | 'feature' | 'general'
  message: 'Save button not working',
  email: 'user@example.com',
  metadata: { screen: 'settings' },
});

// Convenience methods
await oasis.feedback.reportBug('Description');
await oasis.feedback.requestFeature('Description');
await oasis.feedback.sendFeedback('Description');
```

### Crash Reporting

```typescript
// Manual capture
try {
  riskyOperation();
} catch (error) {
  await oasis.crashes.captureException(error, {
    appState: { screen: 'checkout' },
    severity: 'error',  // 'warning' | 'error' | 'fatal'
  });
}

// Toggle auto-capture
oasis.crashes.enableAutoCrashReporting();
oasis.crashes.disableAutoCrashReporting();
```

### Breadcrumbs

```typescript
oasis.breadcrumbs.addNavigation('/home', '/settings');
oasis.breadcrumbs.addClick('Save Button');
oasis.breadcrumbs.addHttp('POST', '/api/save', 200);
oasis.breadcrumbs.addCustom('wallet', 'Connected', { address: '0x...' });
```

### User Context

```typescript
// Set after authentication
oasis.setUser({
  id: 'user-123',
  email: 'user@example.com',
  username: 'johndoe',
});

// Clear on logout
oasis.setUser(null);
```

## SDK Configuration Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `apiKey` | `string` | required | Public API key |
| `serverUrl` | `string` | required | Oasis server URL |
| `appVersion` | `string` | required | Current app version |
| `enableAutoCrashReporting` | `boolean` | `false` | Catch uncaught errors |
| `maxBreadcrumbs` | `number` | `50` | Breadcrumb history limit |
| `timeout` | `number` | `10000` | Request timeout (ms) |
| `debug` | `boolean` | `false` | Enable debug logging |
| `beforeSend` | `function` | - | Filter/modify events |
| `onError` | `function` | - | Error callback |

## Required Secrets

| Secret | Description |
|--------|-------------|
| `OASIS_SERVER_URL` | Base URL (e.g., `https://oasis.yourdomain.com`) |
| `OASIS_CI_KEY` | CI key for release registration |
| `NEXT_PUBLIC_OASIS_API_KEY` | Public SDK key (exposed to client) |
| `NEXT_PUBLIC_OASIS_SERVER_URL` | Public server URL (exposed to client) |
| `TAURI_SIGNING_PRIVATE_KEY` | Update signing key |
| `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` | Signing key password |

## Common Gotchas

1. **Public key in tauri.conf.json must match private key** — If you regenerate keys, update both the config and the GitHub secret.
2. **Endpoint URL uses double braces** — `{{target}}` not `{target}`. Single braces are for workflow variables.
3. **App slug must be consistent** — Use the same slug in workflow config, SDK init, and server registration.
4. **NEXT_PUBLIC_ prefix exposes to client** — Oasis public keys are safe to expose; CI keys are not.
5. **Version string must match semver** — Use `0.1.0`, not `v0.1.0` in code. Tags use `v` prefix.
6. **SDK init before crash reporting** — Call `initOasis()` early in app lifecycle to catch startup crashes.
7. **HTTP 204 means no update** — Don't treat this as an error; it's the expected response when current.
8. **Signature verification happens client-side** — Tauri verifies signatures using the embedded pubkey.
9. **R2 URLs must be publicly accessible** — The CDN URL in manifests must be reachable without auth.
10. **beforeSend can drop events** — Return `null` to filter sensitive data from crash reports.

