Skip to content

psam21/nrpc_workshop

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

25 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

NRPC Server - Nostr RPC-over-Events# Installation

A complete implementation of NRPC (Nostr Remote Procedure Call) server with support for reminders, direct messaging, scheduled posts, and ecash giveaways.```

npm install

πŸš€ Features```

  • NRPC Protocol - Implements kinds 22068 (request) and 22069 (response)Setup a sample .env:

  • Encrypted Communication - Supports NIP-17 gift wrapping and NIP-04 fallback```

  • Multiple Controllers - Modular design with specialized controllersexport NSEC=""

  • Scheduling System - Built-in scheduler for reminders and postsexport SERVICE_NAME="FORMSTR NRPC BACKEND"

  • Ecash Integration - Cashu wallet for token giveawaysexport SERVICE_ABOUT="Example NRPC backend by FORMSTR"

  • Method Introspection - Auto-discovery via getMethodsexport SERVICE_PICTURE=""

  • SQLite Persistence - Reliable data storageexport SERVICE_BANNER=""

  • Daemon Mode - Run as background service```

πŸ“‹ Table of Contents```

source .env

πŸ’Ώ Installation## Request Event (kind: 22068)

```bash- author: caller pubkey

Clone the repository- tags:

git clone https://github.com/psam21/nrpc_workshop.git - ["p", "<callee_pubkey>"]

cd nrpc_workshop - ["method", "<method_name>"]

  • ["param", "<key>", "<value>"] (repeatable)

Install dependencies

npm install## Response Event (kind: 22069)


- `author`: callee pubkey

## βš™οΈ Configuration- `tags`:

  - `["e", "<request_event_id>"]`

Create a `.env` file in the root directory:  - `["p", "<caller_pubkey>"]`

  - `["status", "<http_status_code>"]`

```bash  - On success:

# Required: Your Nostr private key    - `["result", "<key>", "<value>"]` (repeatable)

export NSEC="nsec1..."    - `["result_json", "<json_string>"]` (optional)

  - On error:

# Optional: Your public key (auto-derived if not provided)    - `["error", "<http_status_code>", "<message>"]`

export PUBKEY="your_hex_pubkey"

## Examples

# Service Information

export SERVICE_NAME="My NRPC Server"### Request

export SERVICE_ABOUT="Remote Procedure Call server over Nostr"

export SERVICE_PICTURE="https://example.com/logo.png"```json

export SERVICE_BANNER="https://example.com/banner.png"{

  "kind": 22068,

# Nostr Relays (comma-separated)  "author": "npub1caller...",

export RELAYS="wss://relay.damus.io,wss://relay.snort.social,wss://relay.primal.net,wss://relay.nostr.band"  "tags": [

    ["p", "npub1service..."],

# Optional: Ecash Giveaway (requires mint URL)    ["method", "createReminder"],

export MINT_URL="https://mint.minibits.cash/Bitcoin"    ["param", "time", "2025-09-17T09:00:00Z"],

    ["param", "text", "Doctor appointment"],

# Optional: Lightning & Social    ["param", "notify", "true"]

export LUD16="you@getalby.com"  ],

export WEBSITE="https://yourwebsite.com"  "content": ""

export NIP05="you@yourdomain.com"}



# Server Port (default: 3000)Success Response

export PORT="3000"

```{

  "kind": 22069,

### Setting Up Ecash Giveaway (Optional)  "author": "npub1service...",

  "tags": [

If you want to enable the giveaway feature:    ["e", "id_of_request_event"],

    ["p", "npub1caller..."],

1. **Set MINT_URL** in your `.env`    ["status", "200"],

2. **Get an ecash token** from a Cashu mint    ["result", "reminder_id", "rem123"],

3. **Add token to environment**:    ["result", "scheduled_at", "2025-09-17T09:00:00Z"]

   ```bash  ],

   export ECASH_TOKEN="cashuA..."  "content": ""

   ```}

4. **Seed the wallet**:

   ```bashError Response

   npm run seed

   ```{

  "kind": 22069,

## πŸƒ Running the Server  "author": "npub1service...",

  "tags": [

### Development Mode    ["e", "id_of_request_event"],

    ["p", "npub1caller..."],

```bash    ["status", "400"],

# Load environment variables    ["error", "400", "invalid time format"]

source .env  ],

  "content": ""

# Build TypeScript}

npm run build```


# Start server
npm start

Development with Auto-reload

npm run dev

Daemon Mode (Background)

npm start -- -d

This will:

  • Run the server in background
  • Create nrpc.pid with process ID
  • Log to output.log

To stop the daemon:

pkill -f "node dist/app.js"

πŸ”§ Available Methods

1. createReminder

Schedule a reminder to be sent via DM at a specific time.

Parameters:

  • Time (required): Time in format "HH:MM"
  • Text (required): Reminder message
  • Date (required): Date in format "YYYY-MM-DD"

Returns:

  • reminder_id: Unique identifier
  • scheduled_at: ISO timestamp
  • text: Reminder message
  • owner: Creator's pubkey

Errors:

  • 400: Invalid time/date format or missing parameters

2. sendDM

Send a direct message to the caller.

Parameters: None

Returns:

  • Empty object (success confirmation)

3. sendSecureDM

Send a secure direct message with humility check.

Parameters:

  • Are you humble? (required): Must be "Yes"

Returns:

  • message: "User is humble"

Errors:

  • 400: User is not humble (answered anything other than "Yes")

4. schedulePost

Schedule a Nostr event to be published at a future time.

Parameters:

  • When do you want it posed? (required): Unix timestamp
  • Say something! (required): Nostr event JSON

Returns:

  • post_id: Job identifier
  • scheduled_at: ISO timestamp
  • event_kind: Kind of scheduled event
  • event_id: Event ID

5. giveaway (if MINT_URL configured)

Claim a free ecash token (1 sat per pubkey, once only).

Parameters:

  • I want to receive ecash! (required): Nostr event JSON

Returns:

  • token: Cashu token string
  • pubkey: Claimer's pubkey
  • message: Success message (also sent via DM)

Errors:

  • 400: Already claimed
  • 400: Insufficient funds
  • 500: Internal error

6. alwaysError

Test endpoint that always throws an error.

Parameters:

  • message (optional): Custom error message

Errors:

  • 400: Always fails

7. getMethods

Returns introspection data for all available methods.

Parameters: None

Returns:

  • Array of method specifications with params, returns, and errors

πŸ“‘ NRPC Protocol

Request Event (kind: 22068)

{
  "kind": 22068,
  "pubkey": "caller_pubkey",
  "created_at": 1234567890,
  "tags": [
    ["p", "server_pubkey"],
    ["method", "createReminder"],
    ["param", "Time", "09:00"],
    ["param", "Text", "Doctor appointment"],
    ["param", "Date", "2025-11-01"]
  ],
  "content": "",
  "id": "...",
  "sig": "..."
}

Success Response (kind: 22069)

{
  "kind": 22069,
  "pubkey": "server_pubkey",
  "created_at": 1234567890,
  "tags": [
    ["e", "request_event_id"],
    ["p", "caller_pubkey"],
    ["status", "200"],
    ["result", "reminder_id", "abc123"],
    ["result", "scheduled_at", "2025-11-01T09:00:00Z"]
  ],
  "content": "",
  "id": "...",
  "sig": "..."
}

Error Response (kind: 22069)

{
  "kind": 22069,
  "pubkey": "server_pubkey",
  "created_at": 1234567890,
  "tags": [
    ["e", "request_event_id"],
    ["p", "caller_pubkey"],
    ["status", "400"],
    ["error", "400", "time and text required"]
  ],
  "content": "",
  "id": "...",
  "sig": "..."
}

Encrypted Requests (NIP-17 Gift Wrap)

The server also supports encrypted requests using:

  • kind: 21169 - Gift wrap
  • kind: 68 - Request rumor (encrypted)
  • kind: 69 - Response rumor (encrypted)

πŸ§ͺ Testing Tools

1. NRPC Dashboard (test-nrpc-client.html)

Interactive web dashboard to:

  • Discover NRPC servers on relays
  • Check available methods via getMethods
  • View server profiles and metadata

Usage:

xdg-open test-nrpc-client.html
# or on Mac: open test-nrpc-client.html

2. Ecash Claim Tool (claim-ecash.html)

Browser-based tool to claim ecash tokens from giveaway servers.

Features:

  • Pre-configured with known NRPC servers
  • Dynamic method signature detection
  • 30-second timeout
  • Clear error messages

Usage:

xdg-open claim-ecash.html

3. Server Status Checker (test-server-status.html)

Diagnostic tool to test if NRPC servers are online and responding.

Tests:

  • Profile metadata (kind 0)
  • getMethods response
  • 20-second timeout per server

πŸ“ Project Structure

nrpc_server/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app.ts                    # Main entry point
β”‚   β”œβ”€β”€ config.ts                 # Configuration loader
β”‚   β”œβ”€β”€ registry.ts               # Method registry
β”‚   β”œβ”€β”€ utils.ts                  # Utilities (signing, keys)
β”‚   β”œβ”€β”€ controllers/
β”‚   β”‚   β”œβ”€β”€ BaseController.ts     # Base class
β”‚   β”‚   β”œβ”€β”€ ReminderController.ts # Reminder methods
β”‚   β”‚   β”œβ”€β”€ DMController.ts       # Direct messaging
β”‚   β”‚   β”œβ”€β”€ SDMController.ts      # Secure DM with validation
β”‚   β”‚   β”œβ”€β”€ GiveAwayController.ts # Ecash giveaways
β”‚   β”‚   β”œβ”€β”€ SchedulePostController.ts
β”‚   β”‚   └── ErrorController.ts    # Test error handling
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   β”œβ”€β”€ nostr.ts             # Nostr relay management
β”‚   β”‚   β”œβ”€β”€ sendDM.ts            # NIP-17/NIP-04 DM sender
β”‚   β”‚   β”œβ”€β”€ ReminderService.ts   # Reminder logic
β”‚   β”‚   β”œβ”€β”€ SchedulerService.ts  # Generic job scheduler
β”‚   β”‚   β”œβ”€β”€ SchedulePostService.ts
β”‚   β”‚   β”œβ”€β”€ GiveAwayWalletService.ts # Cashu wallet
β”‚   β”‚   β”œβ”€β”€ proofStore.ts        # Ecash proof storage
β”‚   β”‚   └── claimStore.ts        # Giveaway claim tracking
β”‚   β”œβ”€β”€ db/
β”‚   β”‚   └── reminder.ts          # SQLite reminder DB
β”‚   └── scripts/
β”‚       └── seedWallet.ts        # Seed ecash wallet
β”œβ”€β”€ dist/                        # Compiled JavaScript
β”œβ”€β”€ package.json
β”œβ”€β”€ tsconfig.json
β”œβ”€β”€ .env                         # Environment configuration
β”œβ”€β”€ test-nrpc-client.html       # NRPC dashboard
β”œβ”€β”€ claim-ecash.html            # Ecash claim tool
β”œβ”€β”€ test-server-status.html     # Server status checker
β”œβ”€β”€ reminders.db                # SQLite database
β”œβ”€β”€ wallet.db                   # Ecash wallet database
└── README.md

πŸ› οΈ Development

Adding a New Controller

  1. Create controller file in src/controllers/:
import { NRPCParams, MethodRegistry } from "../registry.js";
import { BaseController } from "./BaseController.js";
import { Event } from "nostr-tools";

export class MyController extends BaseController {
  constructor(registry: MethodRegistry) {
    super(registry);

    registry.register("myMethod", this.myMethod.bind(this), {
      params: [
        { name: "param1", type: "string", required: true }
      ],
      returns: [
        { name: "result", type: "string" }
      ],
      errors: [
        { code: 400, message: "Error description" }
      ]
    });
  }

  async myMethod(params: NRPCParams, event: Event) {
    // Your logic here
    return { result: "success" };
  }
}
  1. Register in src/app.ts:
import { MyController } from "./controllers/MyController.js";

// In main() function:
new MyController(Registry);
  1. Rebuild and restart:
npm run build
npm start

Database Schema

Reminders (reminders.db):

CREATE TABLE reminders (
  id TEXT PRIMARY KEY,
  time TEXT NOT NULL,
  date TEXT NOT NULL,
  text TEXT NOT NULL,
  owner TEXT NOT NULL,
  scheduled_at INTEGER NOT NULL
);

Ecash Proofs (wallet.db):

CREATE TABLE proofs (
  id TEXT,
  mint TEXT NOT NULL,
  secret TEXT NOT NULL,
  amount INTEGER NOT NULL,
  C TEXT NOT NULL,
  created_at INTEGER DEFAULT (strftime('%s','now')),
  PRIMARY KEY (mint, secret, C)
);

CREATE TABLE claims (
  pubkey TEXT PRIMARY KEY,
  claimed_at INTEGER DEFAULT (strftime('%s','now'))
);

πŸ”’ Security Notes

  • Your NSEC is used to sign all server responses
  • Keep your .env file secure and never commit it
  • The ecash wallet database contains spendable tokens
  • Gift-wrapped messages use ephemeral keys for privacy

πŸ“š Dependencies

  • nostr-tools (v2.16.2) - Nostr protocol utilities
  • @cashu/cashu-ts - Ecash/Cashu integration
  • better-sqlite3 - SQLite database
  • ws - WebSocket for relay connections
  • dotenv - Environment configuration
  • uuid - Unique ID generation

🀝 Contributing

Contributions welcome! This is a workshop/learning project.

πŸ“„ License

MIT

πŸ”— Resources

About

nrpc_workshop

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •