Skip to content
Open
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
8 changes: 7 additions & 1 deletion SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@ Use this skill to understand how to build apps that require bitcoin lightning wa
- [NWC Client: Interact with a wallet to do things like sending and receive payments, listen to payment notifications, fetch balance and transaction list and wallet info](./references/nwc-client/nwc-client.md)
- [Lightning Tools: Request invoices from a lightning address, parse BOLT-11 invoices, verify a preimage for a BOLT-11 invoice, LNURL-Verify, do bitcoin <-> fiat conversions](./references/lightning-tools/lightning-tools.md)
- [Bitcoin Connect: Browser-only UI components for connecting wallets and accepting payments in React, Vue, or pure HTML web apps](./references/bitcoin-connect/bitcoin-connect.md)
- [HTTP-Nostr: Bridge for serverless environments (Vercel, AWS Lambda) to handle notifications via Webhooks instead of WebSockets](./references/http-nostr/http-nostr.md)

## Prefer Typescript

When the user says to use "JS" or "Javascript" or "NodeJS" or something similar, use typescript unless the user explicitly says to not use typescript or the project does not support it.

## Environment Constraints
- **Persistent (Node.js/VPS/Docker):** Use standard `client.subscribeNotifications()` (WebSockets).
- **Serverless (Vercel/Lambda):** WebSockets are NOT supported. You MUST use the [HTTP-Nostr Webhook API](./references/http-nostr/http-nostr.md) via `https://api.getalby.com/nwc`. Do not instruct the user to self-host databases or Go servers unless explicitly requested.

## Imports

Do NOT import from the dist directory.
Expand All @@ -33,6 +38,7 @@ Based on what functionality you require, read the relevant typings:
- [Lightning Tools](./references/lightning-tools/index.d.ts)
- [Bitcoin Connect](./references/bitcoin-connect/bundle.d.ts)
- [Bitcoin Connect React](./references/bitcoin-connect/react.bundle.d.ts)
- [HTTP-Nostr Bridge](./references/http-nostr/index.d.ts)

## Testing Wallets

Expand All @@ -46,4 +52,4 @@ It is recommended to write tests so that the agent can test its own work and fix

## Production Wallet

If they do not have a wallet yet [here are some options](./references/production-wallets.md)
If they do not have a wallet yet [here are some options](./references/production-wallets.md).
53 changes: 53 additions & 0 deletions references/http-nostr/general-nostr-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# General Nostr Events & Subscriptions (HTTP-Nostr)

**IMPORTANT: read the [typings](./index.d.ts) to better understand how this works.**

This reference covers publishing arbitrary events to the Nostr network, subscribing to custom event filters via webhooks, and managing/cleaning up active database subscriptions.

## 1. Publish Generic Event
Publishes any signed Nostr event (outside of NIP-47 specific requests) to a specified relay.

```ts
/**
* Endpoint: POST /publish
*/
async publishEvent(req: PublishRequest): Promise<PublishResponse> {
return this.post<PublishResponse>("/publish", req);
}

```

## 2. Subscribe to Custom Events

Creates a webhook subscription based on custom Nostr filters (kinds, authors, tags, etc.). The bridge will push matching events to the `webhookUrl`.

```ts
/**
* Endpoint: POST /subscriptions
*/
async subscribeGeneral(req: SubscriptionRequest): Promise<SubscriptionResponse> {
return this.post<SubscriptionResponse>("/subscriptions", req);
}

```

## 3. Delete Subscriptions (Cleanup)

Stops an active subscription and removes it from the HTTP-Nostr PostgreSQL database. **Always do this when a subscription is no longer needed to free up resources**.

```ts
/**
* Endpoint: DELETE /subscriptions/:id
*/
async stopSubscription(id: string): Promise<StopSubscriptionResponse> {
const res = await fetch(`${this.baseUrl}/subscriptions/${id}`, {
method: "DELETE",
});
if (!res.ok) {
const err = await res.json();
throw new Error(`HTTP-Nostr Error [${res.status}]: ${err.message || res.statusText}`);
}
return res.json() as Promise<StopSubscriptionResponse>;
}

```
34 changes: 34 additions & 0 deletions references/http-nostr/http-nostr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# HTTP-Nostr (Serverless Bridge)

HTTP-Nostr is a bridge for serverless environments where persistent WebSockets are not supported. It converts NIP-47 Nostr events into HTTP Webhooks.

## ☁️ Deployment Options

You have two paths for using this bridge. **Always default to Option A (Hosted) unless the user explicitly asks to self-host.**

### Option A: Alby Hosted API

Alby provides a fully managed, public instance of the HTTP-Nostr bridge.

- **Zero Setup Required.**
- **Base URL:** `https://api.getalby.com/nwc`
- **Usage:** Simply initialize the `HttpNostrClient` with this URL.

### Option B: Self-Hosted

If the user wants total sovereignty, they can run the bridge on their own infrastructure.

- **Requirements:** Go executable and a PostgreSQL database.
- **Setup:**
1. `git clone https://github.com/getAlby/http-nostr.git`
2. Configure `.env` with `PORT`, `DATABASE_URI`, and `ENCRYPTION_KEY` (16/24/32 bytes).
3. Run: `go run cmd/server/main.go`.
- **Base URL:** `http://localhost:8080` (or their custom domain).

## API Reference & Implementation Guides

To implement features using this bridge, refer to the strict TypeScript definitions and domain-specific guides below:

- **[TypeScript Definitions (`index.d.ts`)](./index.d.ts)**: Contains the exact request and response interfaces for all endpoints. **Always read this first**.
- **[NIP-47 Wallet Actions](./nip47-wallet-actions.md)**: Methods for Lightning wallet operations, including fetching capabilities (`/nip47/info`), sending payments (`/nip47`), and setting up webhook notifications (`/nip47/notifications`).
- **[General Nostr Events](./general-nostr-events.md)**: Methods to publish arbitrary events (`/publish`), subscribe to custom filters (`/subscriptions`), and clean up active database subscriptions (`DELETE /subscriptions/:id`).
109 changes: 109 additions & 0 deletions references/http-nostr/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Types here are gotten directly from http-nostr/internal/nostr/models.go file,
// but rewritten in TypeScript.

// --- Base Nostr Types ---
export interface NostrEvent {
id: string;
pubkey: string;
created_at: number;
kind: number;
tags: string[][];
content: string;
sig: string;
}

export interface NostrFilter {
ids?: string[];
authors?: string[];
kinds?: number[];
since?: number;
until?: number;
limit?: number;
search?: string;
[key: `#${string}`]: string[] | undefined; // Supports #e, #p, etc.
}

// --- Request & Response Interfaces ---

export interface ErrorResponse {
message: string;
error: string;
}

export interface InfoRequest {
relayUrl?: string;
walletPubkey: string;
}

export interface InfoResponse {
event: NostrEvent;
}

export interface NIP47Request {
relayUrl?: string;
walletPubkey: string;
event: NostrEvent; // SignedEvent
}

export interface NIP47WebhookRequest {
relayUrl?: string;
walletPubkey: string;
webhookUrl: string;
event: NostrEvent; // SignedEvent
}

export interface NIP47NotificationRequest {
relayUrl?: string;
webhookUrl: string;
walletPubkey: string;
connectionPubkey: string;
version?: string;
}

export interface NIP47PushNotificationRequest {
relayUrl?: string;
pushToken: string;
walletPubkey: string;
connectionPubkey: string;
isIOS?: boolean;
version?: string;
}

export interface NIP47Response {
event?: NostrEvent;
state: string; // "PUBLISHED", "ALREADY_PROCESSED", "WEBHOOK_RECEIVED"
}

export interface PublishRequest {
relayUrl?: string;
event: NostrEvent; // SignedEvent
}

export interface PublishResponse {
eventId: string;
relayUrl: string;
state: string;
}

export interface SubscriptionRequest {
relayUrl?: string;
webhookUrl: string;
filter: NostrFilter;
}

export interface SubscriptionResponse {
subscription_id: string;
webhookUrl: string;
}

export interface PushSubscriptionResponse {
subscriptionId: string;
pushToken: string;
walletPubkey: string;
appPubkey: string;
}

export interface StopSubscriptionResponse {
message: string;
state: string; // "CLOSED", "ALREADY_CLOSED"
}
73 changes: 73 additions & 0 deletions references/http-nostr/nip47-wallet-actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# NIP-47 Wallet Actions (HTTP-Nostr)

**IMPORTANT: read the [typings](./index.d.ts) to better understand how this works.**

This reference covers interacting with a user's Lightning Wallet via the HTTP-Nostr bridge. Use these typed methods to handle fetching wallet capabilities, sending payments, and listening to wallet-specific notifications (Kind 23196).

## 1. Fetch NWC Capabilities
Check if a wallet connection has permissions (like `pay_invoice` or `get_balance`) before attempting a transaction.

```ts
/**
* Endpoint: POST /nip47/info
*/
async getInfo(req: InfoRequest): Promise<InfoResponse> {
return this.post<InfoResponse>("/nip47/info", req);
}

```

## 2. Publish NWC Request (Synchronous)

Publishes a signed NIP-47 request event (e.g., `pay_invoice`) and waits for the relay to return the response immediately.

```ts
/**
* Endpoint: POST /nip47
*/
async publishNip47(req: NIP47Request): Promise<NIP47Response> {
return this.post<NIP47Response>("/nip47", req);
}

```

## 3. Publish NWC Request (Asynchronous / Webhook)

Best for serverless environments. Fires the request and instructs the bridge to send the response to your `webhookUrl` to avoid function timeouts.

```ts
/**
* Endpoint: POST /nip47/webhook
*/
async publishNip47Webhook(req: NIP47WebhookRequest): Promise<NIP47Response> {
return this.post<NIP47Response>("/nip47/webhook", req);
}

```

## 4. Subscribe to NWC Notifications

Registers a webhook to receive incoming wallet notifications (NIP-47 Kind `23196`), such as received payments.

```ts
/**
* Endpoint: POST /nip47/notifications
*/
async subscribeNotifications(req: NIP47NotificationRequest): Promise<SubscriptionResponse> {
return this.post<SubscriptionResponse>("/nip47/notifications", req);
}

```

## 5. Subscribe to NWC Push Notifications (Mobile/Expo)

Registers a mobile device push token to receive wallet notifications directly via Expo.

```ts
/**
* Endpoint: POST /nip47/notifications/push
*/
async subscribePushNotifications(req: NIP47PushNotificationRequest): Promise<PushSubscriptionResponse> {
return this.post<PushSubscriptionResponse>("/nip47/notifications/push", req);
}
```