Update docs
This commit is contained in:
@@ -52,8 +52,8 @@ pin(tag: string[]): Promise<Thunk>
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
type SendWrappedOptions = Omit<ThunkOptions, "event" | "relays"> & {
|
type SendWrappedOptions = Omit<ThunkOptions, "event" | "relays"> & {
|
||||||
template: EventTemplate
|
event: EventTemplate
|
||||||
pubkeys: string[]
|
recipients: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
sendWrapped(options: SendWrappedOptions): Promise<MergedThunk>
|
sendWrapped(options: SendWrappedOptions): Promise<MergedThunk>
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ const thunk = publishThunk({
|
|||||||
thunk.controller.abort()
|
thunk.controller.abort()
|
||||||
|
|
||||||
// Some commands are included
|
// Some commands are included
|
||||||
const thunk = follow('97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322')
|
const thunk = follow(['p', '97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322'])
|
||||||
|
|
||||||
// Load events as a promise
|
// Load events as a promise
|
||||||
const events = await load({
|
const events = await load({
|
||||||
|
|||||||
@@ -61,14 +61,14 @@ Several common collections are built-in and ready for use:
|
|||||||
profiles → profilesByPubkey → deriveProfile → loadProfile
|
profiles → profilesByPubkey → deriveProfile → loadProfile
|
||||||
|
|
||||||
// Lists
|
// Lists
|
||||||
follows → followsByPubkey → deriveFollows → loadFollows
|
followLists → followListsByPubkey → deriveFollowList → loadFollowList
|
||||||
mutes → mutesByPubkey → deriveMutes → loadMutes
|
muteLists → muteListsByPubkey → deriveMuteList → loadMuteList
|
||||||
pins → pinsByPubkey → derivePins → loadPins
|
pinLists → pinListsByPubkey → derivePinList → loadPinList
|
||||||
|
|
||||||
// Relays
|
// Relays
|
||||||
relays → relaysByUrl → deriveRelay → loadRelay
|
relays → relaysByUrl → deriveRelay → loadRelay
|
||||||
relayLists → relayListsByPubkey → deriveRelayLists → loadRelayLists
|
relayLists → relayListsByPubkey → deriveRelayList → loadRelayList
|
||||||
messagingRelayLists → messagingRelayListsByPubkey → deriveMessagingRelayLists → loadMessagingRelayLists
|
messagingRelayLists → messagingRelayListsByPubkey → deriveMessagingRelayList → loadMessagingRelayList
|
||||||
|
|
||||||
// Identity
|
// Identity
|
||||||
handles → handlesByNip05 → deriveHandle → loadHandle
|
handles → handlesByNip05 → deriveHandle → loadHandle
|
||||||
@@ -97,24 +97,20 @@ const name = deriveProfileDisplay(pubkey)
|
|||||||
Several modules provide user-specific derived stores that automatically load data for the currently signed-in user:
|
Several modules provide user-specific derived stores that automatically load data for the currently signed-in user:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { userProfile, userFollows, userMutes, userPins } from '@welshman/app'
|
import { userProfile, userFollowList, userMuteList, userPinList } from '@welshman/app'
|
||||||
|
|
||||||
userProfile.subscribe(profile => {
|
userProfile.subscribe(profile => {
|
||||||
// Current user's profile data
|
// Current user's profile data
|
||||||
})
|
})
|
||||||
|
|
||||||
userFollows.subscribe(follows => {
|
userFollowList.subscribe(follows => {
|
||||||
// Current user's follow list
|
// Current user's follow list
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
### Repository Integration
|
### Repository Integration
|
||||||
|
|
||||||
All events from subscriptions are automatically:
|
Events from subscriptions are automatically tracked to their source relay and saved to the repository, unless they are DVM-kind or ephemeral events (which are discarded). WRAP (kind 1059) events are handled separately and only processed when `shouldUnwrap` is set to `true`.
|
||||||
|
|
||||||
- Saved to the repository
|
|
||||||
- Tracked to their source relay
|
|
||||||
- Checked against deletion status
|
|
||||||
|
|
||||||
The repository serves as an intelligent cache layer, making subsequent queries for the same data faster.
|
The repository serves as an intelligent cache layer, making subsequent queries for the same data faster.
|
||||||
|
|
||||||
|
|||||||
@@ -63,10 +63,11 @@ Several thunk factories are provided for common or more complicated scenarios li
|
|||||||
- `unfollow(value: string)`
|
- `unfollow(value: string)`
|
||||||
- `follow(tag: string[])`
|
- `follow(tag: string[])`
|
||||||
- `unmute(value: string)`
|
- `unmute(value: string)`
|
||||||
- `mute(tag: string[])`
|
- `mutePublicly(tag: string[])`
|
||||||
|
- `mutePrivately(tag: string[])`
|
||||||
- `unpin(value: string)`
|
- `unpin(value: string)`
|
||||||
- `pin(tag: string[])`
|
- `pin(tag: string[])`
|
||||||
- `sendWrapped({template, pubkeys, ...options}: SendWrappedOptions)`
|
- `sendWrapped({event, recipients, ...options}: SendWrappedOptions)`
|
||||||
- `manageRelay(url: string, request: ManagementRequest)`
|
- `manageRelay(url: string, request: ManagementRequest)`
|
||||||
- `createRoom(url: string, room: RoomMeta)`
|
- `createRoom(url: string, room: RoomMeta)`
|
||||||
- `deleteRoom(url: string, room: RoomMeta)`
|
- `deleteRoom(url: string, room: RoomMeta)`
|
||||||
|
|||||||
+1
-1
@@ -174,7 +174,7 @@ getNip55().then(signerApps => {
|
|||||||
A fun feature of nostr is that you can log in as other people, and see what nostr is like from their perspective (minus encrypted data or course).
|
A fun feature of nostr is that you can log in as other people, and see what nostr is like from their perspective (minus encrypted data or course).
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import {loginWithPubkey} from "@welshman/signer"
|
import {loginWithPubkey} from "@welshman/app"
|
||||||
|
|
||||||
// Log in as hodlbod
|
// Log in as hodlbod
|
||||||
loginWithPubkey("97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322")
|
loginWithPubkey("97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322")
|
||||||
|
|||||||
+31
-38
@@ -2,25 +2,6 @@
|
|||||||
|
|
||||||
The User Data module provides utilities for loading and managing user-specific data like profiles, follows, mutes, pins, and relay selections. It includes both reactive stores and manual loading functions.
|
The User Data module provides utilities for loading and managing user-specific data like profiles, follows, mutes, pins, and relay selections. It includes both reactive stores and manual loading functions.
|
||||||
|
|
||||||
## Types
|
|
||||||
|
|
||||||
### UserDataLoader
|
|
||||||
```typescript
|
|
||||||
type UserDataLoader = (pubkey: string, relays?: string[], force?: boolean) => unknown
|
|
||||||
```
|
|
||||||
|
|
||||||
Function type for loading user data with optional relay specification and force refresh.
|
|
||||||
|
|
||||||
### MakeUserDataOptions
|
|
||||||
```typescript
|
|
||||||
type MakeUserDataOptions<T> = {
|
|
||||||
mapStore: Readable<Map<string, T>>
|
|
||||||
loadItem: UserDataLoader
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Configuration for creating user data stores.
|
|
||||||
|
|
||||||
## User Data Stores
|
## User Data Stores
|
||||||
|
|
||||||
These reactive stores automatically load and cache user data:
|
These reactive stores automatically load and cache user data:
|
||||||
@@ -30,56 +11,68 @@ These reactive stores automatically load and cache user data:
|
|||||||
export const userProfile: Store<Profile | undefined>
|
export const userProfile: Store<Profile | undefined>
|
||||||
|
|
||||||
// User follows list
|
// User follows list
|
||||||
export const userFollows: Store<List | undefined>
|
export const userFollowList: Store<List | undefined>
|
||||||
|
|
||||||
// User mutes list
|
// User mutes list
|
||||||
export const userMutes: Store<List | undefined>
|
export const userMuteList: Store<List | undefined>
|
||||||
|
|
||||||
// User pins list
|
// User pins list
|
||||||
export const userPins: Store<List | undefined>
|
export const userPinList: Store<List | undefined>
|
||||||
|
|
||||||
// User relay selections
|
// User relay selections
|
||||||
export const userRelayLists: Store<List | undefined>
|
export const userRelayList: Store<List | undefined>
|
||||||
|
|
||||||
// User messaging relay selections
|
// User messaging relay selections
|
||||||
export const userMessagingRelayLists: Store<List | undefined>
|
export const userMessagingRelayList: Store<List | undefined>
|
||||||
|
|
||||||
// User blossom servers
|
// User blossom servers
|
||||||
export const userBlossomServers: Store<List | undefined>
|
export const userBlossomServerList: Store<List | undefined>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Manual Loading Functions
|
## Manual Loading Functions
|
||||||
|
|
||||||
These functions allow manual loading of user data with optional relay specification and force refresh:
|
These functions load user data for the currently signed-in user with optional relay hints:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Load user profile
|
// Load user profile
|
||||||
function loadUserProfile(relays?: string[], force?: boolean): Promise<void>
|
function loadUserProfile(relays?: string[]): Promise<void>
|
||||||
|
|
||||||
// Load user follows
|
// Load user follows
|
||||||
function loadUserFollows(relays?: string[], force?: boolean): Promise<void>
|
function loadUserFollowList(relays?: string[]): Promise<void>
|
||||||
|
|
||||||
// Load user mutes
|
// Load user mutes
|
||||||
function loadUserMutes(relays?: string[], force?: boolean): Promise<void>
|
function loadUserMuteList(relays?: string[]): Promise<void>
|
||||||
|
|
||||||
// Load user pins
|
// Load user pins
|
||||||
function loadUserPins(relays?: string[], force?: boolean): Promise<void>
|
function loadUserPinList(relays?: string[]): Promise<void>
|
||||||
|
|
||||||
// Load user relay selections
|
// Load user relay selections
|
||||||
function loadUserRelayLists(relays?: string[], force?: boolean): Promise<void>
|
function loadUserRelayList(relays?: string[]): Promise<void>
|
||||||
|
|
||||||
// Load user messaging relay selections
|
// Load user messaging relay selections
|
||||||
function loadUserMessagingRelayLists(relays?: string[], force?: boolean): Promise<void>
|
function loadUserMessagingRelayList(relays?: string[]): Promise<void>
|
||||||
|
|
||||||
// Load user blossom servers
|
// Load user blossom servers
|
||||||
function loadUserBlossomServers(relays?: string[], force?: boolean): Promise<void>
|
function loadUserBlossomServerList(relays?: string[]): Promise<void>
|
||||||
|
```
|
||||||
|
|
||||||
|
Force-reload variants bypass the cache and always fetch fresh data:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function forceLoadUserProfile(relays?: string[]): Promise<void>
|
||||||
|
function forceLoadUserFollowList(relays?: string[]): Promise<void>
|
||||||
|
function forceLoadUserMuteList(relays?: string[]): Promise<void>
|
||||||
|
function forceLoadUserPinList(relays?: string[]): Promise<void>
|
||||||
|
function forceLoadUserRelayList(relays?: string[]): Promise<void>
|
||||||
|
function forceLoadUserMessagingRelayList(relays?: string[]): Promise<void>
|
||||||
|
function forceLoadUserBlossomServerList(relays?: string[]): Promise<void>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|
||||||
### Using Reactive Stores
|
### Using Reactive Stores
|
||||||
```typescript
|
```typescript
|
||||||
import { userProfile, userFollows } from '@welshman/app'
|
import { userProfile, userFollowList } from '@welshman/app'
|
||||||
|
|
||||||
// Subscribe to user profile changes
|
// Subscribe to user profile changes
|
||||||
userProfile.subscribe(profile => {
|
userProfile.subscribe(profile => {
|
||||||
@@ -89,18 +82,18 @@ userProfile.subscribe(profile => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Get current follows list
|
// Get current follows list
|
||||||
const follows = userFollows.get()
|
const follows = userFollowList.get()
|
||||||
```
|
```
|
||||||
|
|
||||||
### Manual Loading
|
### Manual Loading
|
||||||
```typescript
|
```typescript
|
||||||
import { loadUserMutes, loadUserRelayLists } from '@welshman/app'
|
import { loadUserMuteList, forceLoadUserRelayList } from '@welshman/app'
|
||||||
|
|
||||||
// Load user mutes from specific relays
|
// Load user mutes from specific relays
|
||||||
await loadUserMutes(['wss://relay1.com', 'wss://relay2.com'])
|
await loadUserMuteList(['wss://relay1.com', 'wss://relay2.com'])
|
||||||
|
|
||||||
// Force refresh user relay selections
|
// Force refresh user relay selections
|
||||||
await loadUserRelayLists([], true)
|
await forceLoadUserRelayList([])
|
||||||
|
|
||||||
// Load from default relays
|
// Load from default relays
|
||||||
await loadUserProfile()
|
await loadUserProfile()
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ followersByPubkey: Readable<Map<string, Set<string>>>
|
|||||||
mutersByPubkey: Readable<Map<string, Set<string>>>
|
mutersByPubkey: Readable<Map<string, Set<string>>>
|
||||||
|
|
||||||
// The full WOT graph with scores (pubkey → score)
|
// The full WOT graph with scores (pubkey → score)
|
||||||
wotGraph: Readable<Map<string, number>>
|
wotGraph: Writable<Map<string, number>>
|
||||||
|
|
||||||
// The maximum WOT score in the graph
|
// The maximum WOT score in the graph
|
||||||
maxWot: Readable<number>
|
maxWot: Readable<number>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Defines all supported content types:
|
|||||||
- `Cashu` - Cashu token strings
|
- `Cashu` - Cashu token strings
|
||||||
- `Code` - Code blocks and inline code
|
- `Code` - Code blocks and inline code
|
||||||
- `Ellipsis` - Truncation indicators
|
- `Ellipsis` - Truncation indicators
|
||||||
|
- `Email` - Email addresses
|
||||||
- `Emoji` - Custom emoji references
|
- `Emoji` - Custom emoji references
|
||||||
- `Event` - Event references (note/nevent)
|
- `Event` - Event references (note/nevent)
|
||||||
- `Invoice` - Lightning invoices
|
- `Invoice` - Lightning invoices
|
||||||
@@ -57,13 +58,12 @@ reduceLinks(content: Parsed[]) => Parsed[]
|
|||||||
## Type Guards
|
## Type Guards
|
||||||
|
|
||||||
Utility functions to check parsed element types:
|
Utility functions to check parsed element types:
|
||||||
- `isAddress(parsed)`, `isCashu(parsed)`, `isCode(parsed)`, etc.
|
- `isAddress(parsed)`, `isCashu(parsed)`, `isCode(parsed)`, `isEmail(parsed)`, etc.
|
||||||
- `isImage(parsed)` - special check for image links
|
- `isImage(parsed)` - special check for image links
|
||||||
|
|
||||||
## Utilities
|
## Utilities
|
||||||
|
|
||||||
- `urlIsMedia(url)` - Checks if URL points to media file
|
- `urlIsMedia(url)` - Checks if URL points to media file
|
||||||
- `fromNostrURI(s)` - Removes nostr: protocol prefix
|
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ type RenderOptions = {
|
|||||||
|
|
||||||
## Built-in Renderers
|
## Built-in Renderers
|
||||||
|
|
||||||
- `makeTextRenderer` - renders an array of `Parsed` elements as text
|
- `makeTextRenderer` - creates a `Renderer` configured for plain-text output
|
||||||
- `makeHtmlRenderer` - renders an array of `Parsed` elements as HTML
|
- `makeHtmlRenderer` - creates a `Renderer` configured for HTML output
|
||||||
|
|
||||||
## Main Functions
|
## Main Functions
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ const html = renderAsHtml(parsed, {
|
|||||||
}).toString()
|
}).toString()
|
||||||
|
|
||||||
// Result:
|
// Result:
|
||||||
// Check out this cool #nostr client!<br>
|
// Check out this cool #nostr client!
|
||||||
// Visit <a href="https://njump.me/nprofile1...">npub1jlrs53p...</a> for more info<br>
|
// Visit <a href="https://njump.me/nprofile1...">npub1jlrs53p...</a> for more info
|
||||||
// <a href="https://github.com/coracle-social/welshman" class="custom-link">github.com/coracle-social/welshman</a>
|
// <a href="https://github.com/coracle-social/welshman" class="custom-link">github.com/coracle-social/welshman</a>
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ export class FeedController {
|
|||||||
load(limit: number): Promise<void>
|
load(limit: number): Promise<void>
|
||||||
|
|
||||||
// Get listener function (memoized)
|
// Get listener function (memoized)
|
||||||
getListener(): Promise<() => Promise<void>>
|
getListener(): Promise<() => () => void>
|
||||||
|
|
||||||
// Listen for new events in the feed
|
// Listen for new events in the feed; returns an unsubscribe function
|
||||||
listen(): Promise<void>
|
listen(): () => Promise<void>
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+9
-11
@@ -18,31 +18,29 @@ Read the spec on [the NIPs repository](https://github.com/nostr-protocol/nips/bl
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Define a feed using set operations
|
// Define a feed using set operations
|
||||||
const feed = intersectionFeed(
|
const feed = makeIntersectionFeed(
|
||||||
unionFeed(
|
makeUnionFeed(
|
||||||
dvmFeed({
|
makeDVMFeed({
|
||||||
kind: 5300,
|
kind: 5300,
|
||||||
pubkey: '19b78ccfa7c5e31e6bacbb3f2a1703f64b62017702e584440bf29a7e16263e8c',
|
pubkey: '19b78ccfa7c5e31e6bacbb3f2a1703f64b62017702e584440bf29a7e16263e8c',
|
||||||
}),
|
}),
|
||||||
listFeed("10003:19ba654f26afd4930fd3d51baf4e26f1413b7aeec7190cd6c0cdf4d2f14cec6b:"),
|
makeListFeed("10003:19ba654f26afd4930fd3d51baf4e26f1413b7aeec7190cd6c0cdf4d2f14cec6b:"),
|
||||||
)
|
),
|
||||||
wotFeed({min: 0.1}),
|
makeWOTFeed({min: 0.1}),
|
||||||
scopeFeed("global"),
|
makeGlobalFeed(),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create a controller, providing required context via FeedOptions
|
// Create a controller, providing required context via FeedOptions
|
||||||
const controller = new FeedController({
|
const controller = new FeedController({
|
||||||
feed,
|
feed,
|
||||||
request,
|
|
||||||
requestDVM,
|
|
||||||
getPubkeysForScope,
|
getPubkeysForScope,
|
||||||
getPubkeysForWOTRange,
|
getPubkeysForWOTRange,
|
||||||
onEvent: event => console.log("Event", event),
|
onEvent: event => console.log("Event", event),
|
||||||
onExhausted: () => console.log("Exhausted"),
|
onExhausted: () => console.log("Exhausted"),
|
||||||
})
|
})
|
||||||
|
|
||||||
// Load notes using the feed
|
// Load notes using the feed — events are delivered via the onEvent callback above
|
||||||
const events = await controller.load(10)
|
await controller.load(10)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|||||||
+1
-1
@@ -32,6 +32,6 @@ emitter.on('*', (eventType, ...args) => {
|
|||||||
// Emit an event - triggers both listeners
|
// Emit an event - triggers both listeners
|
||||||
emitter.emit('message', 'Hello world');
|
emitter.emit('message', 'Hello world');
|
||||||
// Output:
|
// Output:
|
||||||
// Event: message ['Hello world']
|
|
||||||
// Message: Hello world
|
// Message: Hello world
|
||||||
|
// Event: message ['Hello world']
|
||||||
```
|
```
|
||||||
+3
-3
@@ -40,9 +40,9 @@ cache.set('c', 3);
|
|||||||
|
|
||||||
console.log(cache.get('a')); // 1
|
console.log(cache.get('a')); // 1
|
||||||
|
|
||||||
// Adding 'd' will evict 'b' (least recently used)
|
// Adding 'd' will evict 'a' (its stale key entry is at the front of the tracking queue)
|
||||||
cache.set('d', 4);
|
cache.set('d', 4);
|
||||||
|
|
||||||
console.log(cache.has('b')); // false
|
console.log(cache.has('b')); // true
|
||||||
console.log(cache.has('a')); // true (recently accessed)
|
console.log(cache.has('a')); // false
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ The `TaskQueue` class provides a simple queue processing system with batched ope
|
|||||||
// Task queue options
|
// Task queue options
|
||||||
export type TaskQueueOptions<Item> = {
|
export type TaskQueueOptions<Item> = {
|
||||||
batchSize: number;
|
batchSize: number;
|
||||||
|
batchDelay: number;
|
||||||
processItem: (item: Item) => unknown;
|
processItem: (item: Item) => unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ export declare class TaskQueue<Item> {
|
|||||||
push(item: Item): void;
|
push(item: Item): void;
|
||||||
remove(item: Item): void;
|
remove(item: Item): void;
|
||||||
subscribe(subscriber: (item: Item) => void): () => void;
|
subscribe(subscriber: (item: Item) => void): () => void;
|
||||||
process(): Promise<void>;
|
process(): void;
|
||||||
stop(): void;
|
stop(): void;
|
||||||
start(): void;
|
start(): void;
|
||||||
clear(): void;
|
clear(): void;
|
||||||
@@ -32,6 +33,7 @@ import { TaskQueue } from '@welshman/lib';
|
|||||||
// Create a task queue that processes 3 items at a time
|
// Create a task queue that processes 3 items at a time
|
||||||
const queue = new TaskQueue({
|
const queue = new TaskQueue({
|
||||||
batchSize: 3,
|
batchSize: 3,
|
||||||
|
batchDelay: 0,
|
||||||
processItem: async (message: string) => {
|
processItem: async (message: string) => {
|
||||||
console.log('Processing:', message);
|
console.log('Processing:', message);
|
||||||
// Simulate async work
|
// Simulate async work
|
||||||
|
|||||||
+15
-14
@@ -35,17 +35,17 @@ type PartialUser = MakeOptional<User, 'email' | 'age'>;
|
|||||||
## Basic functional programming utilities
|
## Basic functional programming utilities
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Null or undefined
|
// Undefined or T
|
||||||
export type Nil = null | undefined;
|
export type Maybe<T> = T | undefined;
|
||||||
|
|
||||||
// Check whether something is null or undefined
|
// Check whether something is not undefined
|
||||||
export declare const isNil: <T>(x: T, ...args: unknown[]) => boolean;
|
export declare const isDefined: <T>(x: T, ...args: unknown[]) => boolean;
|
||||||
|
|
||||||
// Check whether something is not null or undefined
|
// Check whether something is undefined
|
||||||
export declare const isNotNil: <T>(x: T, ...args: unknown[]) => x is (T & null) | (T & {}) | (T & undefined);
|
export declare const isUndefined: <T>(x: T, ...args: unknown[]) => boolean;
|
||||||
|
|
||||||
// Assert that a nullable type is not null or undefined
|
// Assert that a value is not undefined
|
||||||
export declare const assertNotNil: <T>(x: T, ...args: unknown[]) => NonNullable<T>;
|
export declare const assertDefined: <T>(x: T, ...args: unknown[]) => NonNullable<T>;
|
||||||
|
|
||||||
// Function that does nothing and returns undefined
|
// Function that does nothing and returns undefined
|
||||||
export declare const noop: (...args: unknown[]) => undefined;
|
export declare const noop: (...args: unknown[]) => undefined;
|
||||||
@@ -215,7 +215,7 @@ export declare const drop: <T>(n: number, xs: Iterable<T>) => T[];
|
|||||||
// Returns first n elements of array
|
// Returns first n elements of array
|
||||||
export declare const take: <T>(n: number, xs: Iterable<T>) => T[];
|
export declare const take: <T>(n: number, xs: Iterable<T>) => T[];
|
||||||
|
|
||||||
// Concatenates multiple arrays, filtering out null/undefined
|
// Concatenates multiple arrays, skipping undefined array arguments
|
||||||
export declare const concat: <T>(...xs: T[][]) => T[];
|
export declare const concat: <T>(...xs: T[][]) => T[];
|
||||||
|
|
||||||
// Prepends element to array
|
// Prepends element to array
|
||||||
@@ -417,7 +417,7 @@ export declare const yieldThread: () => any;
|
|||||||
// Poll options for condition checking
|
// Poll options for condition checking
|
||||||
type PollOptions = {
|
type PollOptions = {
|
||||||
signal: AbortSignal;
|
signal: AbortSignal;
|
||||||
condition: () => boolean;
|
condition: () => unknown;
|
||||||
interval?: number;
|
interval?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -468,6 +468,7 @@ export declare const setJson: (k: string, v: any) => void;
|
|||||||
// Options for fetch requests
|
// Options for fetch requests
|
||||||
type FetchOpts = {
|
type FetchOpts = {
|
||||||
method?: string;
|
method?: string;
|
||||||
|
signal?: AbortSignal;
|
||||||
headers?: Record<string, string | boolean>;
|
headers?: Record<string, string | boolean>;
|
||||||
body?: string | FormData;
|
body?: string | FormData;
|
||||||
};
|
};
|
||||||
@@ -497,8 +498,8 @@ export declare const ellipsize: (s: string, l: number, suffix?: string) => strin
|
|||||||
// Displays a list of items with oxford commas and a chosen conjunction
|
// Displays a list of items with oxford commas and a chosen conjunction
|
||||||
export declare const displayList: <T>(xs: T[], conj?: string, n?: number) => string;
|
export declare const displayList: <T>(xs: T[], conj?: string, n?: number) => string;
|
||||||
|
|
||||||
// Generates a hash string from input string
|
// Generates a hash number from input string
|
||||||
export declare const hash: (s: string) => string;
|
export declare const hash: (s: string) => number;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Curried utilities for working with collections
|
## Curried utilities for working with collections
|
||||||
@@ -564,8 +565,8 @@ export declare const hexToBech32: (prefix: string, hex: string) => `${Lowercase<
|
|||||||
// Converts bech32 string to hex format
|
// Converts bech32 string to hex format
|
||||||
export declare const bech32ToHex: (b32: string) => string;
|
export declare const bech32ToHex: (b32: string) => string;
|
||||||
|
|
||||||
// Converts an array buffer to hex format
|
// Converts an array buffer or Uint8Array to hex format
|
||||||
export declare const bytesToHex: (buffer: ArrayBuffer) => string;
|
export declare const bytesToHex: (buffer: ArrayBuffer | Uint8Array) => string;
|
||||||
|
|
||||||
// Converts a hex string to a Uint8Array buffer
|
// Converts a hex string to a Uint8Array buffer
|
||||||
export declare const hexToBytes: (hex: string) => Uint8Array;
|
export declare const hexToBytes: (hex: string) => Uint8Array;
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ The `netContext` global provides sensible defaults:
|
|||||||
import {netContext} from '@welshman/net'
|
import {netContext} from '@welshman/net'
|
||||||
|
|
||||||
// Override event validation
|
// Override event validation
|
||||||
netContext.isEventValid: (event, url) => {
|
netContext.isEventValid = (event, url) => {
|
||||||
return event.kind < 30000 && verifyEvent(event)
|
return event.kind < 30000 && verifyEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -5,6 +5,7 @@ Type definitions and utilities for Nostr protocol messages.
|
|||||||
## Relay Message Types
|
## Relay Message Types
|
||||||
|
|
||||||
**Enums:**
|
**Enums:**
|
||||||
|
- `RelayMessageType.Notice` - Human-readable notice from relay
|
||||||
- `RelayMessageType.Auth` - Authentication challenge
|
- `RelayMessageType.Auth` - Authentication challenge
|
||||||
- `RelayMessageType.Closed` - Subscription closed
|
- `RelayMessageType.Closed` - Subscription closed
|
||||||
- `RelayMessageType.Eose` - End of stored events
|
- `RelayMessageType.Eose` - End of stored events
|
||||||
@@ -15,11 +16,11 @@ Type definitions and utilities for Nostr protocol messages.
|
|||||||
|
|
||||||
**Type Definitions:**
|
**Type Definitions:**
|
||||||
- `RelayMessage` - Base relay message type
|
- `RelayMessage` - Base relay message type
|
||||||
- `RelayAuth`, `RelayClosed`, `RelayEose`, `RelayEvent`, `RelayNegErr`, `RelayNegMsg`, `RelayOk` - Specific message types
|
- `RelayNotice`, `RelayAuth`, `RelayClosed`, `RelayEose`, `RelayEvent`, `RelayNegErr`, `RelayNegMsg`, `RelayOk` - Specific message types
|
||||||
- `RelayAuthPayload`, `RelayClosedPayload`, etc. - Payload types for each message
|
- `RelayNoticePayload`, `RelayAuthPayload`, `RelayClosedPayload`, etc. - Payload types for each message
|
||||||
|
|
||||||
**Type Guards:**
|
**Type Guards:**
|
||||||
- `isRelayAuth()`, `isRelayClosed()`, `isRelayEose()`, `isRelayEvent()`, `isRelayNegErr()`, `isRelayNegMsg()`, `isRelayOk()`
|
- `isRelayNotice()`, `isRelayAuth()`, `isRelayClosed()`, `isRelayEose()`, `isRelayEvent()`, `isRelayNegErr()`, `isRelayNegMsg()`, `isRelayOk()`
|
||||||
|
|
||||||
## Client Message Types
|
## Client Message Types
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ The contract for socket policies. Takes a Socket object and returns a cleanup fu
|
|||||||
|
|
||||||
## Built-in Policies
|
## Built-in Policies
|
||||||
|
|
||||||
|
### `socketPolicyPing`
|
||||||
|
|
||||||
|
Sends a PING message every 30 seconds when the socket is open and has been idle (no send or receive activity in the last 30 seconds). Keeps connections alive through NAT/firewall idle timeouts.
|
||||||
|
|
||||||
### `socketPolicyAuthBuffer`
|
### `socketPolicyAuthBuffer`
|
||||||
|
|
||||||
Buffers messages during authentication flow and replays them after successful auth.
|
Buffers messages during authentication flow and replays them after successful auth.
|
||||||
|
|||||||
+1
-6
@@ -12,16 +12,11 @@ A connection pool that creates and manages Socket instances for different relay
|
|||||||
- `static get()` - Returns the singleton pool instance
|
- `static get()` - Returns the singleton pool instance
|
||||||
- `has(url)` - Checks if a socket exists for the given URL
|
- `has(url)` - Checks if a socket exists for the given URL
|
||||||
- `get(url)` - Gets or creates a socket for the given URL
|
- `get(url)` - Gets or creates a socket for the given URL
|
||||||
|
- `makeSocket(url)` - Creates a Socket for the given URL, using `PoolOptions.makeSocket` if provided, otherwise applies `defaultSocketPolicies`
|
||||||
- `subscribe(callback)` - Subscribes to new socket creation events
|
- `subscribe(callback)` - Subscribes to new socket creation events
|
||||||
- `remove(url)` - Removes and cleans up a socket
|
- `remove(url)` - Removes and cleans up a socket
|
||||||
- `clear()` - Removes all sockets from the pool
|
- `clear()` - Removes all sockets from the pool
|
||||||
|
|
||||||
## Functions
|
|
||||||
|
|
||||||
### makeSocket(url, policies)
|
|
||||||
|
|
||||||
Creates a new Socket instance with the given URL and applies default policies.
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
|||||||
+5
-3
@@ -16,7 +16,9 @@ Requests events from a single relay using the given filters. Returns a promise t
|
|||||||
- `context?` - Adapter context
|
- `context?` - Adapter context
|
||||||
- `autoClose?` - Auto-close subscription after EOSE
|
- `autoClose?` - Auto-close subscription after EOSE
|
||||||
- Validation functions: `isEventValid`, `isEventDeleted`
|
- Validation functions: `isEventValid`, `isEventDeleted`
|
||||||
- Callback functions: `onEvent`, `onDeleted`, `onInvalid`, `onFiltered`, `onDuplicate`, `onDisconnect`, `onEose`, `onClose`
|
- Callback functions: `onEvent`, `onDeleted`, `onInvalid`, `onFiltered`, `onDuplicate`, `onDisconnect`, `onEose`, `onClosed`, `onClose`
|
||||||
|
- `onClosed?: (message: string, url: string) => void` - Called when the relay sends a CLOSED message, receiving the close reason and relay URL
|
||||||
|
- `onClose?: () => void` - Called when the subscription is fully closed
|
||||||
|
|
||||||
### request(options)
|
### request(options)
|
||||||
|
|
||||||
@@ -38,9 +40,9 @@ Creates a batched loader function that delays and combines requests for efficien
|
|||||||
- `threshold?` - Relay completion threshold
|
- `threshold?` - Relay completion threshold
|
||||||
- Validation functions and context options
|
- Validation functions and context options
|
||||||
|
|
||||||
### load(filters, relays, options)
|
### load(options)
|
||||||
|
|
||||||
Pre-configured loader with 200ms delay, 3s timeout, and 0.5 threshold.
|
Pre-configured loader with 200ms delay, 3s timeout, and 0.5 threshold. Takes a `LoadOptions` object containing `relays`, `filters`, and optional callback fields (`onEvent`, `onDisconnect`, `onEose`, `onClose`) and an optional `signal`.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const router = Router.get()
|
|||||||
// Get relays for reading events from specific pubkeys
|
// Get relays for reading events from specific pubkeys
|
||||||
const readRelays = router.FromPubkeys(['pubkey1', 'pubkey2']).getUrls()
|
const readRelays = router.FromPubkeys(['pubkey1', 'pubkey2']).getUrls()
|
||||||
|
|
||||||
// Get relays for publishing an event (author's outbox + mentions' messaginges)
|
// Get relays for publishing (author's outbox + mentions' inbox/read relays)
|
||||||
const publishRelays = router.PublishEvent(event).getUrls()
|
const publishRelays = router.PublishEvent(event).getUrls()
|
||||||
|
|
||||||
// Try hard to find a quoted note with maximal fallbacks
|
// Try hard to find a quoted note with maximal fallbacks
|
||||||
@@ -74,8 +74,8 @@ The main class for relay selection. Configure it once with your relay discovery
|
|||||||
|
|
||||||
**Scenario Methods:**
|
**Scenario Methods:**
|
||||||
- `FromRelays(relays)` - Use specific relays
|
- `FromRelays(relays)` - Use specific relays
|
||||||
- `ForUser()` / `FromUser()` / `UserMessaging()` - User's read/write/messaging relays
|
- `ForUser()` / `FromUser()` / `MessagesForUser()` - User's read/write/messaging relays
|
||||||
- `ForPubkey(pubkey)` / `FromPubkey(pubkey)` / `PubkeyMessaging(pubkey)` - Pubkey's relays
|
- `ForPubkey(pubkey)` / `FromPubkey(pubkey)` / `MessagesForPubkey(pubkey)` - Pubkey's relays
|
||||||
- `ForPubkeys(pubkeys)` / `FromPubkeys(pubkeys)` - Multiple pubkeys' relays
|
- `ForPubkeys(pubkeys)` / `FromPubkeys(pubkeys)` - Multiple pubkeys' relays
|
||||||
- `Event(event)` - Relays for an event's author
|
- `Event(event)` - Relays for an event's author
|
||||||
- `PublishEvent(event)` - Relays for publishing (author + mentions)
|
- `PublishEvent(event)` - Relays for publishing (author + mentions)
|
||||||
@@ -106,8 +106,8 @@ Functions that determine how many fallback relays to add:
|
|||||||
`getFilterSelections(filters)` automatically chooses appropriate relays based on filter content:
|
`getFilterSelections(filters)` automatically chooses appropriate relays based on filter content:
|
||||||
- Search filters → search relays
|
- Search filters → search relays
|
||||||
- Wrap events → user's messaging
|
- Wrap events → user's messaging
|
||||||
- Profile/relay kinds → indexer relays
|
- Profile/relay/follow/messaging-relay kinds → indexer relays
|
||||||
- Author filters → authors' relays
|
- Author filters → authors' relays
|
||||||
- Everything else → user's relays (low weight)
|
- All filters → user's read relays (low-weight baseline, always fires)
|
||||||
|
|
||||||
Returns `RelaysAndFilters[]` with optimized relay-filter combinations.
|
Returns `RelaysAndFilters[]` with optimized relay-filter combinations.
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ interface ISigner {
|
|||||||
// Core signing functionality
|
// Core signing functionality
|
||||||
sign: SignWithOptions
|
sign: SignWithOptions
|
||||||
getPubkey: () => Promise<string>
|
getPubkey: () => Promise<string>
|
||||||
|
cleanup?: () => Promise<void>
|
||||||
|
|
||||||
// Encryption capabilities
|
// Encryption capabilities
|
||||||
nip04: {
|
nip04: {
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ The NIP-01 implementation extends the base interface with two static utility met
|
|||||||
### Usage Example
|
### Usage Example
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { ISigner } from './interfaces'
|
import { ISigner, Nip01Signer } from '@welshman/signer'
|
||||||
import { Nip01Signer } from './signers/nip01'
|
|
||||||
|
|
||||||
// Using the standard interface
|
// Using the standard interface
|
||||||
const signer: ISigner = new Nip01Signer(mySecret)
|
const signer: ISigner = new Nip01Signer(mySecret)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const signer = new Nip07Signer()
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Nip07Signer, getNip07 } from '@welshman/signer'
|
import { Nip07Signer, getNip07 } from '@welshman/signer'
|
||||||
import { createEvent, NOTE } from '@welshman/util'
|
import { makeEvent, NOTE } from '@welshman/util'
|
||||||
|
|
||||||
async function example() {
|
async function example() {
|
||||||
// Check for NIP-07 provider
|
// Check for NIP-07 provider
|
||||||
@@ -47,7 +47,7 @@ async function example() {
|
|||||||
console.log('Public key:', pubkey)
|
console.log('Public key:', pubkey)
|
||||||
|
|
||||||
// Create and sign an event (will prompt user)
|
// Create and sign an event (will prompt user)
|
||||||
const event = createEvent(NOTE, {
|
const event = makeEvent(NOTE, {
|
||||||
content: "Hello via browser extension!",
|
content: "Hello via browser extension!",
|
||||||
tags: [["t", "test"]]
|
tags: [["t", "test"]]
|
||||||
})
|
})
|
||||||
|
|||||||
+11
-10
@@ -16,13 +16,13 @@ import {
|
|||||||
Nip46Broker,
|
Nip46Broker,
|
||||||
Nip46Signer
|
Nip46Signer
|
||||||
} from '@welshman/signer'
|
} from '@welshman/signer'
|
||||||
import { createEvent, NOTE } from '@welshman/util'
|
import { makeEvent, NOTE } from '@welshman/util'
|
||||||
|
|
||||||
async function connectToRemoteSigner() {
|
async function connectToRemoteSigner() {
|
||||||
// Initial setup
|
// Initial setup
|
||||||
const clientSecret = makeSecret()
|
const clientSecret = makeSecret()
|
||||||
const relays = ['wss://relay.example.com']
|
const relays = ['wss://relay.example.com']
|
||||||
const broker = Nip46Broker.get({ relays, clientSecret })
|
const broker = new Nip46Broker({ relays, clientSecret })
|
||||||
const signer = new Nip46Signer(broker)
|
const signer = new Nip46Signer(broker)
|
||||||
|
|
||||||
// Generate connection URL
|
// Generate connection URL
|
||||||
@@ -36,9 +36,10 @@ async function connectToRemoteSigner() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Wait for connection
|
// Wait for connection
|
||||||
|
const abortController = new AbortController()
|
||||||
const response = await broker.waitForNostrconnect(
|
const response = await broker.waitForNostrconnect(
|
||||||
ncUrl,
|
ncUrl,
|
||||||
new AbortController()
|
abortController.signal
|
||||||
)
|
)
|
||||||
|
|
||||||
// Store signer info for later
|
// Store signer info for later
|
||||||
@@ -46,7 +47,7 @@ async function connectToRemoteSigner() {
|
|||||||
localStorage.setItem('bunkerUrl', bunkerUrl)
|
localStorage.setItem('bunkerUrl', bunkerUrl)
|
||||||
|
|
||||||
// Use the signer
|
// Use the signer
|
||||||
const event = createEvent(NOTE, {
|
const event = makeEvent(NOTE, {
|
||||||
content: "Signed with remote signer!",
|
content: "Signed with remote signer!",
|
||||||
tags: [["t", "test"]]
|
tags: [["t", "test"]]
|
||||||
})
|
})
|
||||||
@@ -72,7 +73,7 @@ async function reconnect() {
|
|||||||
relays
|
relays
|
||||||
} = Nip46Broker.parseBunkerUrl(bunkerUrl)
|
} = Nip46Broker.parseBunkerUrl(bunkerUrl)
|
||||||
|
|
||||||
const broker = Nip46Broker.get({
|
const broker = new Nip46Broker({
|
||||||
relays,
|
relays,
|
||||||
clientSecret: makeSecret(),
|
clientSecret: makeSecret(),
|
||||||
signerPubkey,
|
signerPubkey,
|
||||||
@@ -88,8 +89,8 @@ async function reconnect() {
|
|||||||
### Constructor and Factory
|
### Constructor and Factory
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Recommended: use the singleton factory
|
// Direct instantiation
|
||||||
const broker = Nip46Broker.get({
|
new Nip46Broker({
|
||||||
relays: string[],
|
relays: string[],
|
||||||
clientSecret: string,
|
clientSecret: string,
|
||||||
connectSecret?: string,
|
connectSecret?: string,
|
||||||
@@ -97,8 +98,8 @@ const broker = Nip46Broker.get({
|
|||||||
algorithm?: "nip04" | "nip44"
|
algorithm?: "nip04" | "nip44"
|
||||||
})
|
})
|
||||||
|
|
||||||
// Direct instantiation (not recommended)
|
// Static factory: create a broker from a bunker:// URL
|
||||||
new Nip46Broker(params)
|
Nip46Broker.fromBunkerUrl(url: string): Nip46Broker
|
||||||
```
|
```
|
||||||
|
|
||||||
### Connection Methods
|
### Connection Methods
|
||||||
@@ -110,7 +111,7 @@ broker.makeNostrconnectUrl(metadata: Record<string, string>): Promise<string>
|
|||||||
// Wait for connection approval
|
// Wait for connection approval
|
||||||
broker.waitForNostrconnect(
|
broker.waitForNostrconnect(
|
||||||
url: string,
|
url: string,
|
||||||
abort?: AbortController
|
signal: AbortSignal
|
||||||
): Promise<Nip46ResponseWithResult>
|
): Promise<Nip46ResponseWithResult>
|
||||||
|
|
||||||
// Get bunker URL for later reconnection
|
// Get bunker URL for later reconnection
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ Creates a new signer instance that will communicate with the specified native ap
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Nip55Signer, getNip55 } from '@welshman/signer'
|
import { Nip55Signer, getNip55 } from '@welshman/signer'
|
||||||
import { createEvent, NOTE } from '@welshman/util'
|
import { makeEvent, NOTE } from '@welshman/util'
|
||||||
|
|
||||||
async function example() {
|
async function example() {
|
||||||
try {
|
try {
|
||||||
@@ -69,7 +69,7 @@ async function example() {
|
|||||||
console.log('Public key:', pubkey)
|
console.log('Public key:', pubkey)
|
||||||
|
|
||||||
// Sign an event
|
// Sign an event
|
||||||
const event = createEvent(NOTE, {
|
const event = makeEvent(NOTE, {
|
||||||
content: "Hello from native app!",
|
content: "Hello from native app!",
|
||||||
tags: [["t", "test"]]
|
tags: [["t", "test"]]
|
||||||
})
|
})
|
||||||
|
|||||||
+15
-21
@@ -14,23 +14,20 @@ The `Nip59` class provides utilities for implementing the Gift Wrap protocol (NI
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Nip59 } from '@welshman/signer'
|
import { Nip59 } from '@welshman/signer'
|
||||||
import { createEvent, DIRECT_MESSAGE } from '@welshman/util'
|
import { makeEvent, DIRECT_MESSAGE } from '@welshman/util'
|
||||||
|
|
||||||
// Create a NIP-59 instance from any signer
|
// Create a NIP-59 instance from any signer
|
||||||
const nip59 = Nip59.fromSigner(mySigner)
|
const nip59 = Nip59.fromSigner(mySigner)
|
||||||
|
|
||||||
// Wrap an event
|
// Wrap an event — returns the gift-wrap SignedEvent to publish
|
||||||
const rumor = await nip59.wrap(
|
const wrappedEvent = await nip59.wrap(
|
||||||
recipientPubkey,
|
recipientPubkey,
|
||||||
createEvent(DIRECT_MESSAGE, {
|
makeEvent(DIRECT_MESSAGE, {
|
||||||
content: "Secret message",
|
content: "Secret message",
|
||||||
tags: [["p", recipientPubkey]]
|
tags: [["p", recipientPubkey]]
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
// The wrapped event to publish
|
|
||||||
const wrappedEvent = rumor.wrap
|
|
||||||
|
|
||||||
// Unwrap a received event
|
// Unwrap a received event
|
||||||
const unwrapped = await nip59.unwrap(receivedWrappedEvent)
|
const unwrapped = await nip59.unwrap(receivedWrappedEvent)
|
||||||
```
|
```
|
||||||
@@ -51,11 +48,12 @@ export const wrap = async (
|
|||||||
template: StampedEvent,
|
template: StampedEvent,
|
||||||
tags: string[][] = []
|
tags: string[][] = []
|
||||||
) => {
|
) => {
|
||||||
const rumor = await getRumor(signer, template)
|
const author = await signer.getPubkey()
|
||||||
|
const rumor = await prep(template, author)
|
||||||
const seal = await getSeal(signer, pubkey, rumor)
|
const seal = await getSeal(signer, pubkey, rumor)
|
||||||
const wrap = await getWrap(wrapper, pubkey, seal, tags)
|
const wrap = await getWrap(wrapper, pubkey, seal, tags)
|
||||||
|
|
||||||
return Object.assign(rumor, {wrap})
|
return wrap
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -79,20 +77,20 @@ class Nip59 {
|
|||||||
* @param pubkey Recipient's public key
|
* @param pubkey Recipient's public key
|
||||||
* @param template The event to wrap
|
* @param template The event to wrap
|
||||||
* @param tags Additional tags for the wrap event (optional)
|
* @param tags Additional tags for the wrap event (optional)
|
||||||
* @returns Promise<UnwrappedEvent> Original event and its wrapped version
|
* @returns Promise<SignedEvent> The gift-wrap event to publish
|
||||||
*/
|
*/
|
||||||
wrap(
|
wrap(
|
||||||
pubkey: string,
|
pubkey: string,
|
||||||
template: StampedEvent,
|
template: StampedEvent,
|
||||||
tags?: string[][]
|
tags?: string[][]
|
||||||
): Promise<UnwrappedEvent>
|
): Promise<SignedEvent>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unwraps a received wrapped event
|
* Unwraps a received wrapped event
|
||||||
* @param event The wrapped event to decrypt
|
* @param event The wrapped event to decrypt
|
||||||
* @returns Promise<UnwrappedEvent> The original unwrapped event
|
* @returns Promise<HashedEvent> The original unwrapped event
|
||||||
*/
|
*/
|
||||||
unwrap(event: SignedEvent): Promise<UnwrappedEvent>
|
unwrap(event: SignedEvent): Promise<HashedEvent>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance with a specific wrapper signer
|
* Creates a new instance with a specific wrapper signer
|
||||||
@@ -109,24 +107,20 @@ class Nip59 {
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Nip59, Nip01Signer } from '@welshman/signer'
|
import { Nip59, Nip01Signer } from '@welshman/signer'
|
||||||
import { createEvent, DIRECT_MESSAGE } from '@welshman/util'
|
import { makeEvent, DIRECT_MESSAGE } from '@welshman/util'
|
||||||
|
|
||||||
async function example() {
|
async function example() {
|
||||||
// Create NIP-59 instance
|
// Create NIP-59 instance
|
||||||
const signer = new Nip01Signer(mySecret)
|
const signer = new Nip01Signer(mySecret)
|
||||||
const nip59 = Nip59.fromSigner(signer)
|
const nip59 = Nip59.fromSigner(signer)
|
||||||
|
|
||||||
// Create and wrap an event
|
// Create and wrap an event — returns the gift-wrap SignedEvent to publish
|
||||||
const event = createEvent(DIRECT_MESSAGE, {
|
const event = makeEvent(DIRECT_MESSAGE, {
|
||||||
content: "Secret message",
|
content: "Secret message",
|
||||||
tags: [["p", recipientPubkey]]
|
tags: [["p", recipientPubkey]]
|
||||||
})
|
})
|
||||||
|
|
||||||
const rumor = await nip59.wrap(recipientPubkey, event)
|
const wrappedEvent = await nip59.wrap(recipientPubkey, event)
|
||||||
|
|
||||||
// rumor contains:
|
|
||||||
// - The original event (rumor)
|
|
||||||
// - The wrapped version to publish (rumor.wrap)
|
|
||||||
|
|
||||||
// Later, unwrap a received event
|
// Later, unwrap a received event
|
||||||
const unwrapped = await nip59.unwrap(receivedEvent)
|
const unwrapped = await nip59.unwrap(receivedEvent)
|
||||||
|
|||||||
+2
-1
@@ -15,7 +15,8 @@ A utility package providing welshman-specific svelte store functionality and uti
|
|||||||
## Quick Example
|
## Quick Example
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import {Repository, NAMED_PEOPLE, TrustedEvent, PublishedList, readList} from '@welshman/util'
|
import {Repository} from '@welshman/net'
|
||||||
|
import {NAMED_PEOPLE, TrustedEvent, PublishedList, readList} from '@welshman/util'
|
||||||
import {deriveItemsByKey} from '@welshman/store'
|
import {deriveItemsByKey} from '@welshman/store'
|
||||||
|
|
||||||
const repository = new Repository()
|
const repository = new Repository()
|
||||||
|
|||||||
@@ -13,16 +13,16 @@ deriveEventsById(options: {
|
|||||||
}): Readable<Map<string, TrustedEvent>>
|
}): Readable<Map<string, TrustedEvent>>
|
||||||
|
|
||||||
// Convert events by ID to array
|
// Convert events by ID to array
|
||||||
deriveEvents(eventsByIdStore: Readable<Map<string, TrustedEvent>>): Readable<TrustedEvent[]>
|
deriveEvents(options: { repository: Repository, filters: Filter[], includeDeleted?: boolean }): Readable<TrustedEvent[]>
|
||||||
|
|
||||||
// Sort events ascending by created_at
|
// Sort events ascending by created_at
|
||||||
deriveEventsAsc(eventsStore: Readable<TrustedEvent[]>): Readable<TrustedEvent[]>
|
deriveEventsAsc(eventsByIdStore: Readable<Map<string, TrustedEvent>>): Readable<TrustedEvent[]>
|
||||||
|
|
||||||
// Sort events descending by created_at
|
// Sort events descending by created_at
|
||||||
deriveEventsDesc(eventsStore: Readable<TrustedEvent[]>): Readable<TrustedEvent[]>
|
deriveEventsDesc(eventsByIdStore: Readable<Map<string, TrustedEvent>>): Readable<TrustedEvent[]>
|
||||||
|
|
||||||
// Derive single event by ID or address
|
// Derive single event by ID or address
|
||||||
deriveEvent(repository: Repository, idOrAddress: string): Readable<TrustedEvent | undefined>
|
makeDeriveEvent(options: { repository: Repository, includeDeleted?: boolean, onDerive?: (filters: Filter[], ...args: any[]) => void }): (idOrAddress: string, ...args: any[]) => Readable<TrustedEvent | undefined>
|
||||||
|
|
||||||
// Track if event is deleted
|
// Track if event is deleted
|
||||||
deriveIsDeleted(repository: Repository, event: TrustedEvent): Readable<boolean>
|
deriveIsDeleted(repository: Repository, event: TrustedEvent): Readable<boolean>
|
||||||
@@ -52,14 +52,14 @@ makeDeriveItem<T>(
|
|||||||
// Create cached loader with staleness checking and exponential backoff
|
// Create cached loader with staleness checking and exponential backoff
|
||||||
makeLoadItem<T>(
|
makeLoadItem<T>(
|
||||||
loadItem: (key: string, ...args: any[]) => Promise<unknown>,
|
loadItem: (key: string, ...args: any[]) => Promise<unknown>,
|
||||||
getItem: (key: string) => T | undefined,
|
getItem: (key: string, ...args: any[]) => T | undefined,
|
||||||
options?: {getFetched?, setFetched?, timeout?}
|
options?: {getFetched?, setFetched?, timeout?}
|
||||||
): (key: string, ...args: any[]) => Promise<T | undefined>
|
): (key: string, ...args: any[]) => Promise<T | undefined>
|
||||||
|
|
||||||
// Create loader that always fetches fresh data
|
// Create loader that always fetches fresh data
|
||||||
makeForceLoadItem<T>(
|
makeForceLoadItem<T>(
|
||||||
loadItem: (key: string, ...args: any[]) => Promise<unknown>,
|
loadItem: (key: string, ...args: any[]) => Promise<unknown>,
|
||||||
getItem: (key: string) => T | undefined
|
getItem: (key: string, ...args: any[]) => T | undefined
|
||||||
): (key: string, ...args: any[]) => Promise<T | undefined>
|
): (key: string, ...args: any[]) => Promise<T | undefined>
|
||||||
|
|
||||||
// Optimized getter that switches to subscription when hot
|
// Optimized getter that switches to subscription when hot
|
||||||
@@ -70,17 +70,13 @@ getter<T>(store: Readable<T>, options?: {threshold?: number}): () => T
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import {Repository} from "@welshman/net"
|
import {Repository} from "@welshman/net"
|
||||||
import {deriveEventsById, deriveEvents, deriveItemsByKey, deriveItems} from "@welshman/store"
|
import {deriveEvents, deriveItemsByKey, deriveItems} from "@welshman/store"
|
||||||
import {readProfile, PROFILE} from "@welshman/util"
|
import {readProfile, PROFILE} from "@welshman/util"
|
||||||
|
|
||||||
const repository = new Repository()
|
const repository = new Repository()
|
||||||
|
|
||||||
// Reactive store of text notes
|
// Reactive store of text notes
|
||||||
const noteEventsById = deriveEventsById({
|
const notes = deriveEvents({ repository, filters: [{kinds: [1], limit: 100}] })
|
||||||
repository,
|
|
||||||
filters: [{kinds: [1], limit: 100}]
|
|
||||||
})
|
|
||||||
const notes = deriveEvents(noteEventsById)
|
|
||||||
|
|
||||||
// Reactive store of profiles indexed by pubkey
|
// Reactive store of profiles indexed by pubkey
|
||||||
const profilesByPubkey = deriveItemsByKey({
|
const profilesByPubkey = deriveItemsByKey({
|
||||||
|
|||||||
+2
-10
@@ -38,15 +38,9 @@ export type SignedEvent = HashedEvent & {
|
|||||||
sig: string;
|
sig: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wrapped event (NIP-59)
|
// Event that may or may not be signed
|
||||||
export type UnwrappedEvent = HashedEvent & {
|
|
||||||
wrap: SignedEvent;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Event that can be either signed or wrapped
|
|
||||||
export type TrustedEvent = HashedEvent & {
|
export type TrustedEvent = HashedEvent & {
|
||||||
sig?: string;
|
sig?: string;
|
||||||
wrap?: SignedEvent;
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -72,8 +66,6 @@ export declare const isStampedEvent: (e: StampedEvent) => e is StampedEvent;
|
|||||||
export declare const isOwnedEvent: (e: OwnedEvent) => e is OwnedEvent;
|
export declare const isOwnedEvent: (e: OwnedEvent) => e is OwnedEvent;
|
||||||
export declare const isHashedEvent: (e: HashedEvent) => e is HashedEvent;
|
export declare const isHashedEvent: (e: HashedEvent) => e is HashedEvent;
|
||||||
export declare const isSignedEvent: (e: TrustedEvent) => e is SignedEvent;
|
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
|
||||||
@@ -88,7 +80,7 @@ export declare const getIdOrAddress: (e: HashedEvent) => string;
|
|||||||
export declare const getIdAndAddress: (e: HashedEvent) => string[];
|
export declare const getIdAndAddress: (e: HashedEvent) => string[];
|
||||||
|
|
||||||
// Event deduplication by id or address
|
// Event deduplication by id or address
|
||||||
export declare const deduplicateEvents: (e: TrustedEvent) => TrustedEvent[];
|
export declare const deduplicateEvents: (events: TrustedEvent[]) => TrustedEvent[];
|
||||||
|
|
||||||
// Event type checking
|
// Event type checking
|
||||||
export declare const isEphemeral: (e: EventTemplate) => boolean;
|
export declare const isEphemeral: (e: EventTemplate) => boolean;
|
||||||
|
|||||||
@@ -79,7 +79,8 @@ const handlers = readHandlers(event)
|
|||||||
```typescript
|
```typescript
|
||||||
// Get unique handler identifier
|
// Get unique handler identifier
|
||||||
const key = getHandlerKey(handler)
|
const key = getHandlerKey(handler)
|
||||||
// => "1:30023:note-viewer" (kind:pubkey:identifier)
|
// => "1:31990:pubkey:identifier" (handler-kind:address)
|
||||||
|
// where address is the "kind:pubkey:identifier" of the handler event
|
||||||
|
|
||||||
// Display handler name
|
// Display handler name
|
||||||
const name = displayHandler(handler, "Unknown Handler")
|
const name = displayHandler(handler, "Unknown Handler")
|
||||||
|
|||||||
+6
-1
@@ -32,13 +32,18 @@ export type ManagementRequest = {
|
|||||||
method: ManagementMethod
|
method: ManagementMethod
|
||||||
params: string[]
|
params: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ManagementResponse = {
|
||||||
|
result?: any
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Sends a management request to a relay
|
// Sends a management request to a relay
|
||||||
export declare const sendManagementRequest: (url: string, request: ManagementRequest, authEvent: SignedEvent) => Promise<any>
|
export declare const sendManagementRequest: (url: string, request: ManagementRequest, authEvent: SignedEvent) => Promise<ManagementResponse>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ Implementation of NIP-98 HTTP Authentication for authenticating HTTP requests wi
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Creates an HTTP auth event for authenticating requests
|
// Creates an HTTP auth event for authenticating requests
|
||||||
export declare const makeHttpAuth: (url: string, method?: string, body?: string) => Promise<Event>
|
export declare const makeHttpAuth: (url: string, method?: string, body?: string) => Promise<StampedEvent>
|
||||||
|
|
||||||
// Creates Authorization header from signed HTTP auth event
|
// Creates Authorization header from signed HTTP auth event
|
||||||
export declare const makeHttpAuthHeader: (event: SignedEvent) => string
|
export declare const makeHttpAuthHeader: (event: SignedEvent) => string
|
||||||
|
|||||||
+3
-1
@@ -11,6 +11,8 @@ The `Relay` module provides utilities for working with Nostr relays, including U
|
|||||||
export enum RelayMode {
|
export enum RelayMode {
|
||||||
Read = "read",
|
Read = "read",
|
||||||
Write = "write",
|
Write = "write",
|
||||||
|
Search = "search",
|
||||||
|
Blocked = "blocked",
|
||||||
Messaging = "messaging"
|
Messaging = "messaging"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +28,7 @@ export type RelayProfile = {
|
|||||||
version?: string;
|
version?: string;
|
||||||
negentropy?: number;
|
negentropy?: number;
|
||||||
description?: string;
|
description?: string;
|
||||||
supported_nips?: number[];
|
supported_nips?: string[];
|
||||||
limitation?: {
|
limitation?: {
|
||||||
min_pow_difficulty?: number;
|
min_pow_difficulty?: number;
|
||||||
payment_required?: boolean;
|
payment_required?: boolean;
|
||||||
|
|||||||
+1
-1
@@ -44,7 +44,7 @@ export declare const hrpToMillisat: (hrpString: string) => bigint;
|
|||||||
export declare const getInvoiceAmount: (bolt11: string) => number;
|
export declare const getInvoiceAmount: (bolt11: string) => number;
|
||||||
|
|
||||||
// Convert lightning address or URL to LNURL
|
// Convert lightning address or URL to LNURL
|
||||||
export declare const getLnUrl: (address: string) => string | null;
|
export declare const getLnUrl: (address: string) => string | undefined;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Zap Validation
|
### Zap Validation
|
||||||
|
|||||||
Reference in New Issue
Block a user