Update util docs

This commit is contained in:
Jon Staab
2025-06-04 17:52:25 -07:00
parent 95eae509cc
commit 59db0eda9d
10 changed files with 780 additions and 837 deletions
+156 -136
View File
@@ -1,185 +1,205 @@
# Nostr Events
The Events module provides comprehensive type definitions and utilities for working with Nostr events, including helper functions for event creation, validation, and manipulation.
The Events module provides type definitions and utilities for working with Nostr events, including creation, validation, and manipulation functions.
## Event Types Hierarchy
## API
### Event Types
```typescript
// Base event with content and tags
interface EventContent {
tags: string[][]
content: string
}
// Base event content structure
export type EventContent = {
tags: string[][];
content: string;
};
// Base event with kind
interface EventTemplate extends EventContent {
kind: number
}
// Event template with kind
export type EventTemplate = EventContent & {
kind: number;
};
// Event with timestamp
interface StampedEvent extends EventTemplate {
created_at: number
}
export type StampedEvent = EventTemplate & {
created_at: number;
};
// Event with author
interface OwnedEvent extends StampedEvent {
pubkey: string
}
export type OwnedEvent = StampedEvent & {
pubkey: string;
};
// Event with ID
interface HashedEvent extends OwnedEvent {
id: string
}
export type HashedEvent = OwnedEvent & {
id: string;
};
// Event with signature
interface SignedEvent extends HashedEvent {
sig: string
[verifiedSymbol]?: boolean
}
// Signed event
export type SignedEvent = HashedEvent & {
sig: string;
};
// Event with wrapped content
interface UnwrappedEvent extends HashedEvent {
wrap: SignedEvent
}
// Wrapped event (NIP-59)
export type UnwrappedEvent = HashedEvent & {
wrap: SignedEvent;
};
// Event that can be either signed or wrapped
type TrustedEvent = HashedEvent & {
sig?: string
wrap?: SignedEvent
[verifiedSymbol]?: boolean
}
export type TrustedEvent = HashedEvent & {
sig?: string;
wrap?: SignedEvent;
};
```
## Event Creation
### Create Basic Event
```typescript
import { createEvent } from '@welshman/util'
const event = createEvent(
1, // kind
{
content: "Hello Nostr!",
tags: [["t", "nostr"]],
created_at: now() // Optional, defaults to current time
}
)
```
## Type Guards
### Event Creation
```typescript
// Check event types
isEventTemplate(event): boolean
isStampedEvent(event): boolean
isOwnedEvent(event): boolean
isHashedEvent(event): boolean
isSignedEvent(event): boolean
isUnwrappedEvent(event): boolean
isTrustedEvent(event): boolean
// Options for creating events
export type MakeEventOpts = {
content?: string;
tags?: string[][];
created_at?: number;
};
// Creates a stamped event template
export declare const makeEvent: (kind: number, opts?: MakeEventOpts) => StampedEvent;
```
## Event Type Conversion
### Type Guards
```typescript
// Convert to specific event types
asEventTemplate(event): EventTemplate
asStampedEvent(event): StampedEvent
asOwnedEvent(event): OwnedEvent
asHashedEvent(event): HashedEvent
asSignedEvent(event): SignedEvent
asUnwrappedEvent(event): UnwrappedEvent
asTrustedEvent(event): TrustedEvent
export declare const isEventTemplate: (e: EventTemplate) => e is EventTemplate;
export declare const isStampedEvent: (e: StampedEvent) => e is StampedEvent;
export declare const isOwnedEvent: (e: OwnedEvent) => e is OwnedEvent;
export declare const isHashedEvent: (e: HashedEvent) => e is HashedEvent;
export declare const isSignedEvent: (e: TrustedEvent) => e is SignedEvent;
export declare const isUnwrappedEvent: (e: TrustedEvent) => e is UnwrappedEvent;
export declare const isTrustedEvent: (e: TrustedEvent) => e is TrustedEvent;
```
## Event Utilities
### Event Utilities
### Event Validation
```typescript
// Check if event has valid signature
hasValidSignature(event: SignedEvent): boolean
// Event validation and signatures
export declare const verifyEvent: (event: TrustedEvent) => boolean;
// Get event identifier (d tag)
getIdentifier(event: EventTemplate): string | undefined
// Event properties
export declare const getIdentifier: (e: EventTemplate) => string | undefined;
export declare const getIdOrAddress: (e: HashedEvent) => string;
export declare const getIdAndAddress: (e: HashedEvent) => string[];
// Event type checking
export declare const isEphemeral: (e: EventTemplate) => boolean;
export declare const isReplaceable: (e: EventTemplate) => boolean;
export declare const isPlainReplaceable: (e: EventTemplate) => boolean;
export declare const isParameterizedReplaceable: (e: EventTemplate) => boolean;
// Thread and reply handling
// Note: getAncestors handles comments (kind 1111) differently from regular notes
export declare const getAncestors: (event: EventTemplate) => { roots: string[]; replies: string[] };
export declare const getParentIdsAndAddrs: (event: EventTemplate) => string[];
export declare const getParentIdOrAddr: (event: EventTemplate) => string | undefined;
export declare const getParentId: (event: EventTemplate) => string | undefined;
export declare const getParentAddr: (event: EventTemplate) => string | undefined;
export declare const isChildOf: (child: EventTemplate, parent: HashedEvent) => boolean;
```
### Event References
```typescript
// Get event ID or address
getIdOrAddress(event: HashedEvent): string
## Threading Protocols
// Get both ID and address (if replaceable)
getIdAndAddress(event: HashedEvent): string[]
```
The `getAncestors` function handles two different threading protocols:
### Event Type Checking
```typescript
// Check event properties
isEphemeral(event: EventTemplate): boolean
isReplaceable(event: EventTemplate): boolean
isPlainReplaceable(event: EventTemplate): boolean
isParameterizedReplaceable(event: EventTemplate): boolean
```
### Regular Notes (NIP-10)
For regular notes and most event kinds, threading follows [NIP-10](https://github.com/nostr-protocol/nips/blob/master/10.md):
- Uses `e` and `a` tags with optional markers (`root`, `reply`, `mention`)
- Positional rules apply when markers are absent:
- First `e`/`a` tag = root
- Last `e`/`a` tag = reply target
- Middle tags = mentions
### Thread & Reply Handling
```typescript
// Get thread information
getAncestors(event: EventTemplate): { roots: string[], replies: string[] }
### Comments (NIP-22)
For comments (kind 1111), threading follows [NIP-22](https://github.com/nostr-protocol/nips/blob/master/22.md):
- Uses uppercase tags (`E`, `A`, `P`, `K`) for root references
- Uses lowercase tags (`e`, `a`, `p`, `k`) for reply references
- No positional rules - explicit tag types determine relationship
// Get parent references
getParentIdsAndAddrs(event: EventTemplate): string[]
getParentIdOrAddr(event: EventTemplate): string | undefined
getParentId(event: EventTemplate): string | undefined
getParentAddr(event: EventTemplate): string | undefined
// Check reply relationship
isChildOf(child: EventTemplate, parent: HashedEvent): boolean
```
All `getParent*` functions and `isChildOf` include this logic, automatically handling both protocols based on event kind.
## Examples
### Creating and Processing Events
### Creating Events
```typescript
// Create new event
const event = createEvent(1, {
content: "Hello world!",
tags: [["t", "greeting"]]
})
import { makeEvent, NOTE, LONG_FORM } from '@welshman/util';
// Process based on type
if (isSignedEvent(event)) {
// Handle signed event
if (hasValidSignature(event)) {
processValidEvent(event)
}
} else if (isUnwrappedEvent(event)) {
// Handle wrapped event
processWrappedEvent(event)
}
// Create a basic note
const note = makeEvent(NOTE, {
content: "Hello Nostr!",
tags: [["t", "nostr"]]
});
// Create a long-form article with custom timestamp
const article = makeEvent(LONG_FORM, {
content: "# My Article\n\nThis is my article content...",
tags: [["d", "my-article"], ["title", "My Article"]],
created_at: 1234567890
});
```
### Event Properties
```typescript
import { getIdentifier, getIdOrAddress, LONG_FORM } from '@welshman/util';
const article = makeEvent(LONG_FORM, {
content: "Article content...",
tags: [["d", "my-unique-id"]]
});
// Get the identifier (d tag value)
const identifier = getIdentifier(article); // "my-unique-id"
// For a hashed event, get ID or address
const reference = getIdOrAddress(hashedArticle);
// Returns address for replaceable events, ID for others
```
### Working with Threads
```typescript
// Get thread context
const ancestors = getAncestors(event)
const rootId = ancestors.roots[0]
const replyTo = ancestors.replies[0]
import { getAncestors, isChildOf, NOTE, COMMENT } from '@welshman/util';
// Check threading
if (isChildOf(event, parentEvent)) {
// Handle reply
// Regular note reply (NIP-10)
const noteReply = makeEvent(NOTE, {
content: "This is a reply to a note",
tags: [
["e", "root-event-id", "", "root"],
["e", "parent-event-id", "", "reply"]
]
});
// Comment reply (NIP-22)
const commentReply = makeEvent(COMMENT, {
content: "This is a reply comment",
tags: [
["E", "root-event-id"], // uppercase = root reference
["e", "parent-event-id"] // lowercase = reply reference
]
});
// Both work the same way
const noteAncestors = getAncestors(noteReply);
const commentAncestors = getAncestors(commentReply);
console.log('Note roots:', noteAncestors.roots); // ["root-event-id"]
console.log('Note replies:', noteAncestors.replies); // ["parent-event-id"]
console.log('Comment roots:', commentAncestors.roots); // ["root-event-id"]
console.log('Comment replies:', commentAncestors.replies); // ["parent-event-id"]
// Parent checking works for both protocols
if (isChildOf(noteReply, parentEvent)) {
console.log('Note is a reply');
}
if (isChildOf(commentReply, parentEvent)) {
console.log('Comment is a reply');
}
```
### Type Conversion
```typescript
// Convert to needed type
const template = asEventTemplate(event)
const stamped = asStampedEvent(event)
const owned = asOwnedEvent(event)
const hashed = asHashedEvent(event)
const signed = asSignedEvent(event)
```