This commit is contained in:
@@ -1,91 +0,0 @@
|
||||
# Encryptable
|
||||
|
||||
The Encryptable module provides utilities for handling encrypted Nostr events, allowing you to merge plaintext updates into events and encrypt them before publishing.
|
||||
|
||||
## API
|
||||
|
||||
```typescript
|
||||
// Encryption function type
|
||||
export type Encrypt = (x: string) => Promise<string>;
|
||||
|
||||
// Partial event content for updates
|
||||
export type EncryptableUpdates = Partial<EventContent>;
|
||||
|
||||
// Event with attached plaintext data
|
||||
export type DecryptedEvent = TrustedEvent & {
|
||||
plaintext: EncryptableUpdates;
|
||||
};
|
||||
|
||||
// Creates a DecryptedEvent by attaching plaintext to an event
|
||||
export declare const asDecryptedEvent: (
|
||||
event: TrustedEvent,
|
||||
plaintext?: EncryptableUpdates
|
||||
) => DecryptedEvent;
|
||||
|
||||
// Encryptable class for handling encrypted events
|
||||
export declare class Encryptable<T extends EventTemplate> {
|
||||
constructor(
|
||||
event: Partial<T>,
|
||||
updates: EncryptableUpdates
|
||||
);
|
||||
|
||||
// Encrypts updates and merges them into the event
|
||||
reconcile(encrypt: Encrypt): Promise<T>;
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```typescript
|
||||
import { Encryptable } from '@welshman/util';
|
||||
|
||||
// Create encryptable with plaintext updates
|
||||
const encryptable = new Encryptable(
|
||||
{ kind: 10000 }, // Base event template
|
||||
{ content: "secret mute list data" } // Plaintext content to encrypt
|
||||
);
|
||||
|
||||
// Encrypt and get final event
|
||||
const encryptFn = async (text: string) => {
|
||||
// Your encryption logic here
|
||||
return await encrypt(text);
|
||||
};
|
||||
|
||||
const event = await encryptable.reconcile(encryptFn);
|
||||
// event.content is now encrypted
|
||||
```
|
||||
|
||||
### Encrypting Tags
|
||||
|
||||
```typescript
|
||||
import { Encryptable } from '@welshman/util';
|
||||
|
||||
// Encrypt both content and tag values
|
||||
const encryptable = new Encryptable(
|
||||
{ kind: 10000, tags: [] },
|
||||
{
|
||||
content: JSON.stringify(['pubkey1', 'pubkey2']),
|
||||
tags: [['p', 'sensitive-pubkey'], ['e', 'sensitive-event-id']]
|
||||
}
|
||||
);
|
||||
|
||||
// The reconcile method encrypts tag values at index 1
|
||||
const event = await encryptable.reconcile(encryptFn);
|
||||
// event.tags[0] = ['p', 'encrypted-pubkey']
|
||||
// event.tags[1] = ['e', 'encrypted-event-id']
|
||||
```
|
||||
|
||||
### Working with Decrypted Events
|
||||
|
||||
```typescript
|
||||
import { asDecryptedEvent } from '@welshman/util';
|
||||
|
||||
// Add plaintext data to an event for reference
|
||||
const event = { kind: 10000, content: "encrypted...", tags: [] };
|
||||
const plaintext = { content: "original content", tags: [['p', 'pubkey']] };
|
||||
|
||||
const decryptedEvent = asDecryptedEvent(event, plaintext);
|
||||
console.log(decryptedEvent.plaintext.content); // "original content"
|
||||
```
|
||||
@@ -1,134 +0,0 @@
|
||||
# Handlers (NIP-89)
|
||||
|
||||
The Handlers module provides functionality for working with handler recommendations and information (NIP-89).
|
||||
Handlers are events that describe which kinds a given application can display.
|
||||
|
||||
This module provides utilities for transforming these events into structured handler objects that applications can easily process.
|
||||
|
||||
|
||||
## Types
|
||||
|
||||
### Handler Definition
|
||||
|
||||
```typescript
|
||||
type Handler = {
|
||||
kind: number // Event kind this handler can process
|
||||
name: string // Display name of the handler
|
||||
about: string // Description
|
||||
image: string // Icon or image URL
|
||||
identifier: string // Unique identifier (d-tag)
|
||||
event: TrustedEvent // Original handler event
|
||||
website?: string // Optional website URL
|
||||
lud16?: string // Optional Lightning address
|
||||
nip05?: string // Optional NIP-05 identifier
|
||||
}
|
||||
```
|
||||
|
||||
## Core Functions
|
||||
|
||||
### Reading Handlers
|
||||
```typescript
|
||||
function readHandlers(event: TrustedEvent): Handler[]
|
||||
|
||||
// Example
|
||||
const handlers = readHandlers(handlerEvent)
|
||||
handlers.forEach(handler => {
|
||||
console.log(`Handler for kind ${handler.kind}: ${handler.name}`)
|
||||
})
|
||||
```
|
||||
|
||||
### Handler Identification
|
||||
```typescript
|
||||
function getHandlerKey(handler: Handler): string
|
||||
// Returns "kind:address" format
|
||||
|
||||
function getHandlerAddress(event: TrustedEvent): string | undefined
|
||||
// Gets handler address from event tags
|
||||
```
|
||||
|
||||
### Display Formatting
|
||||
```typescript
|
||||
function displayHandler(
|
||||
handler?: Handler,
|
||||
fallback = ""
|
||||
): string
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Reading Handler Information
|
||||
```typescript
|
||||
const event = {
|
||||
kind: 31990, // Handler Information kind
|
||||
content: JSON.stringify({
|
||||
name: "Note Viewer",
|
||||
about: "Displays text notes with formatting",
|
||||
image: "https://example.com/icon.png"
|
||||
}),
|
||||
tags: [
|
||||
['k', '1'], // Handles kind 1 (text notes)
|
||||
['d', 'note-viewer']
|
||||
]
|
||||
}
|
||||
|
||||
const handlers = readHandlers(event)
|
||||
// Returns array of handlers defined in the event
|
||||
```
|
||||
|
||||
### Working with Handlers
|
||||
```typescript
|
||||
// Get unique handler identifier
|
||||
const key = getHandlerKey(handler)
|
||||
// => "1:31990:pubkey:identifier" (handler-kind:address)
|
||||
// where address is the "kind:pubkey:identifier" of the handler event
|
||||
|
||||
// Display handler name
|
||||
const name = displayHandler(handler, "Unknown Handler")
|
||||
// => "Note Viewer" or fallback if handler undefined
|
||||
|
||||
// Get handler address
|
||||
const address = getHandlerAddress(event)
|
||||
// Returns address from tags with 'web' marker or first address
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
```typescript
|
||||
// Process handler information event
|
||||
function processHandlerEvent(event: TrustedEvent) {
|
||||
// Read all handlers from event
|
||||
const handlers = readHandlers(event)
|
||||
|
||||
// Process each handler
|
||||
handlers.forEach(handler => {
|
||||
// Generate unique key
|
||||
const key = getHandlerKey(handler)
|
||||
|
||||
// Store handler information
|
||||
handlerRegistry.set(key, {
|
||||
name: handler.name,
|
||||
kind: handler.kind,
|
||||
about: handler.about,
|
||||
image: handler.image,
|
||||
website: handler.website,
|
||||
address: getHandlerAddress(handler.event)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Find handler for event kind
|
||||
function findHandler(kind: number): Handler | undefined {
|
||||
return Array.from(handlerRegistry.values())
|
||||
.find(h => h.kind === kind)
|
||||
}
|
||||
|
||||
// Display handler information
|
||||
function renderHandler(handler: Handler) {
|
||||
return {
|
||||
title: displayHandler(handler, "Unknown"),
|
||||
description: handler.about,
|
||||
icon: handler.image,
|
||||
website: handler.website || null
|
||||
}
|
||||
}
|
||||
```
|
||||
+3
-3
@@ -2,20 +2,20 @@
|
||||
|
||||
[](https://npmjs.com/package/@welshman/util)
|
||||
|
||||
A utility package for Nostr application development, providing essential tools and types for working with Nostr events, addresses, profiles, and more.
|
||||
A utility package for Nostr application development, providing essential tools and types for working with Nostr events, addresses, filters, tags, and more.
|
||||
|
||||
## What's Included
|
||||
|
||||
- **Event Management**: Create, validate, and process Nostr events
|
||||
- **Repository**: In-memory event storage with querying and indexing
|
||||
- **Filters**: Advanced event filtering and subscription management
|
||||
- **Profiles**: User profile handling and formatting
|
||||
- **Lists**: Public and private list management
|
||||
- **Zaps**: Lightning Network payment integration
|
||||
- **Tags**: Comprehensive tag parsing and manipulation
|
||||
- **Addresses**: NIP-19 address handling
|
||||
- **Relays**: Relay URL handling, event dispatching and in-memory storage
|
||||
|
||||
> Note: profiles, lists, handlers, rooms, and event Reader/Builder helpers now live in [@welshman/domain](/domain/).
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
# Lists
|
||||
|
||||
The Lists module provides utilities for working with Nostr lists, including both public and private lists (like bookmarks, mute lists, etc.). It handles list creation, encryption, and manipulation.
|
||||
|
||||
## Core Types
|
||||
|
||||
### List Parameters
|
||||
```typescript
|
||||
interface ListParams {
|
||||
kind: number // List kind (e.g., 10000 for mutes)
|
||||
}
|
||||
```
|
||||
|
||||
### List Structure
|
||||
```typescript
|
||||
interface List extends ListParams {
|
||||
publicTags: string[][] // Publicly visible tags
|
||||
privateTags: string[][] // Encrypted tags
|
||||
event?: DecryptedEvent // Original event if list exists
|
||||
}
|
||||
```
|
||||
|
||||
### Published List
|
||||
```typescript
|
||||
interface PublishedList extends List {
|
||||
event: DecryptedEvent // Required event for published lists
|
||||
}
|
||||
```
|
||||
|
||||
## List Creation
|
||||
|
||||
### Create New List
|
||||
```typescript
|
||||
function makeList(list: ListParams & Partial<List>): List
|
||||
|
||||
// Example
|
||||
const muteList = makeList({
|
||||
kind: 10000,
|
||||
publicTags: [['d', 'mutes']],
|
||||
privateTags: [['p', 'pubkey1'], ['p', 'pubkey2']]
|
||||
})
|
||||
```
|
||||
|
||||
### Read Existing List
|
||||
```typescript
|
||||
function readList(event: DecryptedEvent): PublishedList
|
||||
|
||||
// Example
|
||||
const list = readList(decryptedEvent)
|
||||
```
|
||||
|
||||
## List Operations
|
||||
|
||||
### Get All Tags
|
||||
```typescript
|
||||
function getListTags(list: List | undefined): string[][]
|
||||
|
||||
// Example
|
||||
const allTags = getListTags(list) // Combines public and private tags
|
||||
```
|
||||
|
||||
### Remove Items
|
||||
```typescript
|
||||
// Remove by predicate
|
||||
function removeFromListByPredicate(
|
||||
list: List,
|
||||
pred: (t: string[]) => boolean
|
||||
): Encryptable
|
||||
|
||||
// Remove by value
|
||||
function removeFromList(
|
||||
list: List,
|
||||
value: string
|
||||
): Encryptable
|
||||
```
|
||||
|
||||
### Add Items
|
||||
```typescript
|
||||
// Add public items
|
||||
function addToListPublicly(
|
||||
list: List,
|
||||
...tags: string[][]
|
||||
): Encryptable
|
||||
|
||||
// Add private items
|
||||
function addToListPrivately(
|
||||
list: List,
|
||||
...tags: string[][]
|
||||
): Encryptable
|
||||
|
||||
// Update list with new tags
|
||||
function updateList(
|
||||
list: List,
|
||||
options: {publicTags?: string[][], privateTags?: string[][]}
|
||||
): Encryptable
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Creating a Private List
|
||||
```typescript
|
||||
// Create new mute list
|
||||
const muteList = makeList({
|
||||
kind: 10000,
|
||||
publicTags: [
|
||||
['d', 'mutes'],
|
||||
['name', 'My Mute List']
|
||||
]
|
||||
})
|
||||
|
||||
// Add items privately
|
||||
const updated = addToListPrivately(
|
||||
muteList,
|
||||
['p', 'pubkey1'],
|
||||
['p', 'pubkey2']
|
||||
)
|
||||
|
||||
// Add new items publicly
|
||||
const addItems = addToListPublicly(
|
||||
list,
|
||||
['p', 'pubkey3'],
|
||||
['p', 'pubkey4']
|
||||
)
|
||||
|
||||
// Encrypt and publish
|
||||
const encrypted = await updated.reconcile(encrypt)
|
||||
```
|
||||
|
||||
### Reading and Updating Lists
|
||||
```typescript
|
||||
// Read existing list
|
||||
const list = readList(decryptedEvent)
|
||||
|
||||
// Remove item
|
||||
const removeItem = removeFromList(list, 'pubkey1')
|
||||
|
||||
// Remove by predicate
|
||||
const noMentions = removeFromListByPredicate(
|
||||
list,
|
||||
tag => tag[0] === 'p'
|
||||
)
|
||||
```
|
||||
|
||||
### Working with Tags
|
||||
```typescript
|
||||
// Get all list tags
|
||||
const tags = getListTags(list)
|
||||
```
|
||||
@@ -1,115 +0,0 @@
|
||||
# Profile
|
||||
|
||||
The Profile module provides utilities for handling Nostr user profiles (kind 0 events), including profile creation, reading, and display formatting.
|
||||
|
||||
## Core Types
|
||||
|
||||
### Profile Structure
|
||||
```typescript
|
||||
interface Profile {
|
||||
name?: string // Display name
|
||||
nip05?: string // NIP-05 verification
|
||||
lud06?: string // Legacy Lightning address
|
||||
lud16?: string // Lightning address
|
||||
lnurl?: string // Lightning URL
|
||||
about?: string // Bio/description
|
||||
banner?: string // Banner image URL
|
||||
picture?: string // Profile picture URL
|
||||
website?: string // Website URL
|
||||
display_name?: string // Alternative display name
|
||||
event?: TrustedEvent // Original profile event
|
||||
}
|
||||
```
|
||||
|
||||
### Published Profile
|
||||
```typescript
|
||||
interface PublishedProfile extends Omit<Profile, "event"> {
|
||||
event: TrustedEvent // Required event for published profiles
|
||||
}
|
||||
```
|
||||
|
||||
## Core Functions
|
||||
|
||||
### Profile Creation & Reading
|
||||
```typescript
|
||||
// Create new profile
|
||||
function makeProfile(profile: Partial<Profile>): Profile
|
||||
|
||||
// Read profile from event
|
||||
function readProfile(event: TrustedEvent): PublishedProfile
|
||||
|
||||
// Create profile event
|
||||
function createProfile(profile: Profile): EventTemplate
|
||||
|
||||
// Edit existing profile
|
||||
function editProfile(profile: PublishedProfile): EventTemplate
|
||||
```
|
||||
|
||||
### Display Formatting
|
||||
```typescript
|
||||
// Format pubkey for display
|
||||
function displayPubkey(pubkey: string): string
|
||||
|
||||
// Format profile name for display
|
||||
function displayProfile(
|
||||
profile?: Profile,
|
||||
fallback = ""
|
||||
): string
|
||||
|
||||
// Check if profile has name
|
||||
function profileHasName(profile?: Profile): boolean
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Creating New Profile
|
||||
```typescript
|
||||
// Create basic profile
|
||||
const profile = makeProfile({
|
||||
name: "Alice",
|
||||
about: "Nostr user",
|
||||
picture: "https://example.com/avatar.jpg",
|
||||
lud16: "alice@getalby.com"
|
||||
})
|
||||
|
||||
// Create profile event
|
||||
const profileEvent = createProfile(profile)
|
||||
```
|
||||
|
||||
### Reading Profile
|
||||
```typescript
|
||||
// Read profile from event
|
||||
const profile = readProfile(profileEvent)
|
||||
|
||||
// Access profile data
|
||||
console.log(profile.name)
|
||||
console.log(profile.about)
|
||||
console.log(profile.lnurl) // Auto-generated from lud16/lud06
|
||||
```
|
||||
|
||||
### Displaying Profile
|
||||
```typescript
|
||||
// Display profile name
|
||||
const name = displayProfile(profile, "Anonymous")
|
||||
|
||||
// Display pubkey
|
||||
const shortPubkey = displayPubkey(profile.event.pubkey)
|
||||
// => "npub1abc...xyz"
|
||||
|
||||
// Check for name
|
||||
if (profileHasName(profile)) {
|
||||
showName(profile)
|
||||
} else {
|
||||
showPubkey(profile)
|
||||
}
|
||||
```
|
||||
|
||||
### Updating Profile
|
||||
```typescript
|
||||
// Edit existing profile
|
||||
const profileEvent = editProfile({
|
||||
...existingProfile,
|
||||
name: "New Name",
|
||||
about: "Updated bio"
|
||||
})
|
||||
```
|
||||
Reference in New Issue
Block a user