applesauce-core 5.1.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/casts/cast.d.ts +31 -0
- package/dist/casts/cast.js +67 -0
- package/dist/casts/index.d.ts +3 -0
- package/dist/casts/index.js +3 -0
- package/dist/casts/pubkey.d.ts +27 -0
- package/dist/casts/pubkey.js +49 -0
- package/dist/casts/user.d.ts +19 -0
- package/dist/casts/user.js +25 -0
- package/dist/factories/delete.d.ts +18 -0
- package/dist/factories/delete.js +23 -0
- package/dist/factories/event.d.ts +61 -0
- package/dist/factories/event.js +164 -0
- package/dist/factories/index.d.ts +5 -0
- package/dist/factories/index.js +5 -0
- package/dist/factories/mailboxes.d.ts +33 -0
- package/dist/factories/mailboxes.js +57 -0
- package/dist/factories/profile.d.ts +46 -0
- package/dist/factories/profile.js +80 -0
- package/dist/factories/types.d.ts +56 -0
- package/dist/helpers/event.d.ts +11 -2
- package/dist/helpers/event.js +2 -1
- package/dist/helpers/mailboxes.d.ts +5 -1
- package/dist/helpers/mailboxes.js +5 -0
- package/dist/helpers/pipeline.d.ts +14 -1
- package/dist/helpers/pipeline.js +17 -2
- package/dist/helpers/pointers.d.ts +25 -21
- package/dist/helpers/pointers.js +33 -18
- package/dist/helpers/profile.d.ts +2 -2
- package/dist/helpers/regexp.d.ts +2 -0
- package/dist/helpers/regexp.js +8 -2
- package/dist/helpers/relays.d.ts +3 -1
- package/dist/helpers/relays.js +8 -10
- package/dist/helpers/url.d.ts +1 -4
- package/dist/helpers/url.js +1 -4
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4 -1
- package/dist/observable/catch-error-inline.d.ts +3 -0
- package/dist/observable/catch-error-inline.js +5 -0
- package/dist/observable/chainable.d.ts +36 -0
- package/dist/observable/chainable.js +72 -0
- package/dist/observable/combine-latest-by-index.d.ts +10 -0
- package/dist/observable/combine-latest-by-index.js +121 -0
- package/dist/observable/combine-latest-by-key.d.ts +10 -0
- package/dist/observable/combine-latest-by-key.js +136 -0
- package/dist/observable/combine-latest-by-value.d.ts +10 -0
- package/dist/observable/combine-latest-by-value.js +117 -0
- package/dist/observable/combine-latest-by.d.ts +16 -0
- package/dist/observable/combine-latest-by.js +12 -0
- package/dist/observable/index.d.ts +10 -4
- package/dist/observable/index.js +10 -4
- package/dist/observable/timeout-with-ignore.d.ts +24 -0
- package/dist/observable/timeout-with-ignore.js +33 -0
- package/dist/operations/client.d.ts +1 -1
- package/dist/operations/client.js +2 -2
- package/dist/operations/content.d.ts +5 -2
- package/dist/operations/content.js +13 -9
- package/dist/operations/delete.d.ts +1 -1
- package/dist/operations/encrypted-content.d.ts +9 -3
- package/dist/operations/encrypted-content.js +9 -3
- package/dist/operations/event.d.ts +6 -4
- package/dist/operations/event.js +20 -12
- package/dist/operations/hidden-content.d.ts +8 -3
- package/dist/operations/hidden-content.js +11 -6
- package/dist/operations/mailboxes.d.ts +5 -1
- package/dist/operations/mailboxes.js +76 -0
- package/dist/operations/profile.d.ts +1 -1
- package/dist/operations/tag/common.d.ts +22 -7
- package/dist/operations/tag/common.js +33 -18
- package/dist/operations/tag/relay.d.ts +1 -1
- package/dist/operations/tags.d.ts +10 -4
- package/dist/operations/tags.js +19 -13
- package/package.json +20 -5
- package/dist/event-factory/event-factory.d.ts +0 -57
- package/dist/event-factory/event-factory.js +0 -94
- package/dist/event-factory/index.d.ts +0 -3
- package/dist/event-factory/index.js +0 -3
- package/dist/event-factory/methods.d.ts +0 -17
- package/dist/event-factory/methods.js +0 -44
- package/dist/event-factory/types.d.ts +0 -76
- /package/dist/{event-factory → factories}/types.js +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Observable } from "rxjs";
|
|
2
|
+
import { EventModels, IEventStoreStreams, IEventSubscriptions } from "../event-store/index.js";
|
|
3
|
+
import { NostrEvent } from "../helpers/event.js";
|
|
4
|
+
import { ChainableObservable } from "../observable/chainable.js";
|
|
5
|
+
import { User } from "./user.js";
|
|
6
|
+
/** The type of event store that is passed to cast references */
|
|
7
|
+
export type CastRefEventStore = IEventSubscriptions & EventModels & IEventStoreStreams;
|
|
8
|
+
/** A symbol used to store all the cast instances for a given event */
|
|
9
|
+
export declare const CAST_REF_SYMBOL: unique symbol;
|
|
10
|
+
/** A symbol used to store all the casts for an event */
|
|
11
|
+
export declare const CASTS_SYMBOL: unique symbol;
|
|
12
|
+
/** A class that can be used to cast a Nostr event */
|
|
13
|
+
export type CastConstructor<C extends EventCast<NostrEvent>> = new (event: NostrEvent, store: CastRefEventStore) => C;
|
|
14
|
+
/** Cast a Nostr event to a specific class */
|
|
15
|
+
export declare function castEvent<C extends EventCast<NostrEvent>>(event: NostrEvent, cls: CastConstructor<C>, store?: CastRefEventStore): C;
|
|
16
|
+
/** The base class for all casts */
|
|
17
|
+
export declare class EventCast<T extends NostrEvent = NostrEvent> {
|
|
18
|
+
#private;
|
|
19
|
+
readonly event: T;
|
|
20
|
+
readonly store: CastRefEventStore;
|
|
21
|
+
get id(): string;
|
|
22
|
+
get uid(): string;
|
|
23
|
+
get createdAt(): Date;
|
|
24
|
+
/** Get the {@link User} that authored this event */
|
|
25
|
+
get author(): User;
|
|
26
|
+
/** Return the set of relays this event was seen on */
|
|
27
|
+
get seen(): Set<string> | undefined;
|
|
28
|
+
constructor(event: T, store: CastRefEventStore);
|
|
29
|
+
/** Internal method for creating a reference */
|
|
30
|
+
protected $$ref<Return extends unknown>(key: string, builder: (store: CastRefEventStore) => Observable<Return>): ChainableObservable<Return>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { getEventUID, getParentEventStore } from "../helpers/event.js";
|
|
2
|
+
import { getSeenRelays } from "../helpers/relays.js";
|
|
3
|
+
import { chainable } from "../observable/chainable.js";
|
|
4
|
+
import { castUser } from "./user.js";
|
|
5
|
+
/** A symbol used to store all the cast instances for a given event */
|
|
6
|
+
export const CAST_REF_SYMBOL = Symbol.for("cast-ref");
|
|
7
|
+
/** A symbol used to store all the casts for an event */
|
|
8
|
+
export const CASTS_SYMBOL = Symbol.for("casts");
|
|
9
|
+
/** Cast a Nostr event to a specific class */
|
|
10
|
+
export function castEvent(event, cls, store) {
|
|
11
|
+
const casts = Reflect.get(event, CASTS_SYMBOL);
|
|
12
|
+
// If the event has already been cast to this class, return the existing cast
|
|
13
|
+
const existing = casts?.get(cls);
|
|
14
|
+
if (existing)
|
|
15
|
+
return existing;
|
|
16
|
+
if (!store) {
|
|
17
|
+
store = getParentEventStore(event);
|
|
18
|
+
if (!store)
|
|
19
|
+
throw new Error("Event is not attached to an event store, an event store must be provided");
|
|
20
|
+
}
|
|
21
|
+
// Create a new instance of the class
|
|
22
|
+
const cast = new cls(event, store);
|
|
23
|
+
if (!casts)
|
|
24
|
+
Reflect.set(event, CASTS_SYMBOL, new Map([[cls, cast]]));
|
|
25
|
+
else
|
|
26
|
+
casts.set(cls, cast);
|
|
27
|
+
return cast;
|
|
28
|
+
}
|
|
29
|
+
/** The base class for all casts */
|
|
30
|
+
export class EventCast {
|
|
31
|
+
event;
|
|
32
|
+
store;
|
|
33
|
+
get id() {
|
|
34
|
+
return this.event.id;
|
|
35
|
+
}
|
|
36
|
+
get uid() {
|
|
37
|
+
return getEventUID(this.event);
|
|
38
|
+
}
|
|
39
|
+
get createdAt() {
|
|
40
|
+
return new Date(this.event.created_at * 1000);
|
|
41
|
+
}
|
|
42
|
+
/** Get the {@link User} that authored this event */
|
|
43
|
+
get author() {
|
|
44
|
+
return castUser(this.event, this.store);
|
|
45
|
+
}
|
|
46
|
+
/** Return the set of relays this event was seen on */
|
|
47
|
+
get seen() {
|
|
48
|
+
return getSeenRelays(this.event);
|
|
49
|
+
}
|
|
50
|
+
// Enfore kind check in constructor. this will force child classes to verify the event before calling super()
|
|
51
|
+
constructor(event, store) {
|
|
52
|
+
this.event = event;
|
|
53
|
+
this.store = store;
|
|
54
|
+
}
|
|
55
|
+
/** A cache of observable references */
|
|
56
|
+
#refs = {};
|
|
57
|
+
/** Internal method for creating a reference */
|
|
58
|
+
$$ref(key, builder) {
|
|
59
|
+
// Return cached observable
|
|
60
|
+
if (this.#refs[key])
|
|
61
|
+
return this.#refs[key];
|
|
62
|
+
// Build a new observable and cache it
|
|
63
|
+
const observable = chainable(builder(this.store));
|
|
64
|
+
this.#refs[key] = observable;
|
|
65
|
+
return observable;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** A constructor type for {@link PubkeyCast} subclasses */
|
|
2
|
+
import { Observable } from "rxjs";
|
|
3
|
+
import { NostrEvent } from "../helpers/event.js";
|
|
4
|
+
import type { ProfilePointer } from "../helpers/pointers.js";
|
|
5
|
+
import { ChainableObservable } from "../observable/chainable.js";
|
|
6
|
+
import { CastRefEventStore } from "./cast.js";
|
|
7
|
+
export type PubkeyCastConstructor<C extends PubkeyCast> = (new (pointer: ProfilePointer, store: CastRefEventStore) => C) & {
|
|
8
|
+
cache: Map<string, C>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Cast a pubkey to a specific class instance.
|
|
12
|
+
* Works like {@link castUser} - returns a cached singleton per pubkey+relay-hints combination.
|
|
13
|
+
*/
|
|
14
|
+
export declare function castPubkey<C extends PubkeyCast>(pubkey: string | NostrEvent | ProfilePointer, cls: PubkeyCastConstructor<C>, store: CastRefEventStore): C;
|
|
15
|
+
/** Base class for pubkey-based casts (analogous to {@link EventCast} for events) */
|
|
16
|
+
export declare class PubkeyCast {
|
|
17
|
+
#private;
|
|
18
|
+
readonly pointer: ProfilePointer;
|
|
19
|
+
readonly store: CastRefEventStore;
|
|
20
|
+
/** A global cache of pubkey -> instance, populated by {@link castPubkey} */
|
|
21
|
+
static cache: Map<string, PubkeyCast>;
|
|
22
|
+
constructor(pointer: ProfilePointer, store: CastRefEventStore);
|
|
23
|
+
/** The hex pubkey represented by this cast */
|
|
24
|
+
get pubkey(): string;
|
|
25
|
+
/** Internal method for creating a cached observable reference */
|
|
26
|
+
protected $$ref<Return extends unknown>(key: string, builder: (store: CastRefEventStore) => Observable<Return>): ChainableObservable<Return>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** A constructor type for {@link PubkeyCast} subclasses */
|
|
2
|
+
import { isEvent } from "../helpers/event.js";
|
|
3
|
+
import { isHexKey } from "../helpers/string.js";
|
|
4
|
+
import { chainable } from "../observable/chainable.js";
|
|
5
|
+
/**
|
|
6
|
+
* Cast a pubkey to a specific class instance.
|
|
7
|
+
* Works like {@link castUser} - returns a cached singleton per pubkey+relay-hints combination.
|
|
8
|
+
*/
|
|
9
|
+
export function castPubkey(pubkey, cls, store) {
|
|
10
|
+
if (isEvent(pubkey))
|
|
11
|
+
return castPubkey(pubkey.pubkey, cls, store);
|
|
12
|
+
const pointer = typeof pubkey === "string" ? { pubkey } : pubkey;
|
|
13
|
+
if (!isHexKey(pointer.pubkey))
|
|
14
|
+
throw new Error("Invalid pubkey");
|
|
15
|
+
const cacheKey = pointer.relays?.length ? `${pointer.pubkey}:${JSON.stringify(pointer.relays)}` : pointer.pubkey;
|
|
16
|
+
if (!cls.cache)
|
|
17
|
+
cls.cache = new Map();
|
|
18
|
+
const existing = cls.cache.get(cacheKey);
|
|
19
|
+
if (existing)
|
|
20
|
+
return existing;
|
|
21
|
+
const instance = new cls(pointer, store);
|
|
22
|
+
cls.cache.set(cacheKey, instance);
|
|
23
|
+
return instance;
|
|
24
|
+
}
|
|
25
|
+
/** Base class for pubkey-based casts (analogous to {@link EventCast} for events) */
|
|
26
|
+
export class PubkeyCast {
|
|
27
|
+
pointer;
|
|
28
|
+
store;
|
|
29
|
+
/** A global cache of pubkey -> instance, populated by {@link castPubkey} */
|
|
30
|
+
static cache = new Map();
|
|
31
|
+
constructor(pointer, store) {
|
|
32
|
+
this.pointer = pointer;
|
|
33
|
+
this.store = store;
|
|
34
|
+
}
|
|
35
|
+
/** The hex pubkey represented by this cast */
|
|
36
|
+
get pubkey() {
|
|
37
|
+
return this.pointer.pubkey;
|
|
38
|
+
}
|
|
39
|
+
/** A cache of observable references */
|
|
40
|
+
#refs = {};
|
|
41
|
+
/** Internal method for creating a cached observable reference */
|
|
42
|
+
$$ref(key, builder) {
|
|
43
|
+
if (this.#refs[key])
|
|
44
|
+
return this.#refs[key];
|
|
45
|
+
const observable = chainable(builder(this.store));
|
|
46
|
+
this.#refs[key] = observable;
|
|
47
|
+
return observable;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { NostrEvent } from "../helpers/event.js";
|
|
2
|
+
import { ProfilePointer } from "../helpers/pointers.js";
|
|
3
|
+
import { ChainableObservable } from "../observable/chainable.js";
|
|
4
|
+
import type { CastRefEventStore } from "./cast.js";
|
|
5
|
+
import { PubkeyCast } from "./pubkey.js";
|
|
6
|
+
/** Cast a Nostr event or pointer into a {@link User} */
|
|
7
|
+
export declare function castUser(event: NostrEvent, store: CastRefEventStore): User;
|
|
8
|
+
export declare function castUser(user: string | ProfilePointer, store: CastRefEventStore): User;
|
|
9
|
+
/** A class representing a Nostr user */
|
|
10
|
+
export declare class User extends PubkeyCast {
|
|
11
|
+
/** A global cache of pubkey -> {@link User} */
|
|
12
|
+
static cache: Map<string, User>;
|
|
13
|
+
get npub(): `npub1${string}`;
|
|
14
|
+
get nprofile(): `nprofile1${string}`;
|
|
15
|
+
/** Subscribe to a replaceable event for this user */
|
|
16
|
+
replaceable(kind: number, identifier?: string, relays?: string[]): ChainableObservable<NostrEvent | undefined>;
|
|
17
|
+
/** Subscribe to an addressable event for this user */
|
|
18
|
+
addressable(kind: number, identifier: string, relays?: string[]): ChainableObservable<NostrEvent | undefined>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { nprofileEncode, npubEncode } from "../helpers/pointers.js";
|
|
2
|
+
import { chainable } from "../observable/chainable.js";
|
|
3
|
+
import { castPubkey, PubkeyCast } from "./pubkey.js";
|
|
4
|
+
export function castUser(user, store) {
|
|
5
|
+
return castPubkey(user, User, store);
|
|
6
|
+
}
|
|
7
|
+
/** A class representing a Nostr user */
|
|
8
|
+
export class User extends PubkeyCast {
|
|
9
|
+
/** A global cache of pubkey -> {@link User} */
|
|
10
|
+
static cache = new Map();
|
|
11
|
+
get npub() {
|
|
12
|
+
return npubEncode(this.pubkey);
|
|
13
|
+
}
|
|
14
|
+
get nprofile() {
|
|
15
|
+
return nprofileEncode(this.pointer);
|
|
16
|
+
}
|
|
17
|
+
/** Subscribe to a replaceable event for this user */
|
|
18
|
+
replaceable(kind, identifier, relays) {
|
|
19
|
+
return chainable(this.store.replaceable({ kind, pubkey: this.pointer.pubkey, identifier, relays }));
|
|
20
|
+
}
|
|
21
|
+
/** Subscribe to an addressable event for this user */
|
|
22
|
+
addressable(kind, identifier, relays) {
|
|
23
|
+
return chainable(this.store.addressable({ kind, pubkey: this.pointer.pubkey, identifier, relays }));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { kinds, NostrEvent } from "nostr-tools";
|
|
2
|
+
import { KnownEventTemplate } from "../helpers/event.js";
|
|
3
|
+
import { EventFactory } from "./event.js";
|
|
4
|
+
export type DeleteTemplate = KnownEventTemplate<kinds.EventDeletion>;
|
|
5
|
+
/** A factory class for building delete events */
|
|
6
|
+
export declare class DeleteFactory extends EventFactory<kinds.EventDeletion, DeleteTemplate> {
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new delete factory from a list of event ids
|
|
9
|
+
* @param events - The list of event ids to delete
|
|
10
|
+
* @param reason - The reason for the deletion
|
|
11
|
+
* @returns A new delete factory
|
|
12
|
+
*/
|
|
13
|
+
static fromEvents(events: (string | NostrEvent)[], reason?: string): DeleteFactory;
|
|
14
|
+
/** Sets the reason for the deletion */
|
|
15
|
+
reason(reason: string): this;
|
|
16
|
+
/** Sets the events to delete */
|
|
17
|
+
events(events: (string | NostrEvent)[]): this;
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { kinds } from "nostr-tools";
|
|
2
|
+
import { blankEventTemplate, EventFactory } from "./event.js";
|
|
3
|
+
import { setDeleteEvents } from "../operations/delete.js";
|
|
4
|
+
/** A factory class for building delete events */
|
|
5
|
+
export class DeleteFactory extends EventFactory {
|
|
6
|
+
/**
|
|
7
|
+
* Creates a new delete factory from a list of event ids
|
|
8
|
+
* @param events - The list of event ids to delete
|
|
9
|
+
* @param reason - The reason for the deletion
|
|
10
|
+
* @returns A new delete factory
|
|
11
|
+
*/
|
|
12
|
+
static fromEvents(events, reason = "") {
|
|
13
|
+
return new DeleteFactory((res) => res(blankEventTemplate(kinds.EventDeletion))).events(events).reason(reason);
|
|
14
|
+
}
|
|
15
|
+
/** Sets the reason for the deletion */
|
|
16
|
+
reason(reason) {
|
|
17
|
+
return this.content(reason);
|
|
18
|
+
}
|
|
19
|
+
/** Sets the events to delete */
|
|
20
|
+
events(events) {
|
|
21
|
+
return this.chain(setDeleteEvents(events));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { EventSigner } from "./types.js";
|
|
2
|
+
import type { EventOperation } from "./types.js";
|
|
3
|
+
import { EncryptionMethod } from "../helpers/encrypted-content.js";
|
|
4
|
+
import { KnownEvent, KnownEventTemplate, KnownUnsignedEvent } from "../helpers/event.js";
|
|
5
|
+
import { MetaTagOptions } from "../operations/event.js";
|
|
6
|
+
import { modifyHiddenTags, modifyPublicTags, modifyTags } from "../operations/tags.js";
|
|
7
|
+
/** Creates a blank event template with the given kind and random "d" tag if addressable */
|
|
8
|
+
export declare function blankEventTemplate<K extends number = number>(kind: K): KnownEventTemplate<K>;
|
|
9
|
+
/** Converts a nostr event to an event template and updates the created_at timestamp */
|
|
10
|
+
export declare function toEventTemplate<K extends number>(event: KnownEvent<K>): KnownEventTemplate<K>;
|
|
11
|
+
/** Shared mutable signer container passed through the factory chain */
|
|
12
|
+
type SignerRef = {
|
|
13
|
+
signer?: EventSigner;
|
|
14
|
+
};
|
|
15
|
+
/** The base class for building or modifying events */
|
|
16
|
+
export declare class EventFactory<K extends number = number, T extends KnownEventTemplate<K> = KnownEventTemplate<K>> extends Promise<T> {
|
|
17
|
+
/** Create a new event factory from a kind */
|
|
18
|
+
static fromKind<K extends number>(kind: K): EventFactory<K>;
|
|
19
|
+
/** Create a new event factory from a nostr event */
|
|
20
|
+
static fromEvent<K extends number = number>(event: KnownEvent<K>): EventFactory<K, KnownEventTemplate<K>>;
|
|
21
|
+
/** Shared mutable reference to the signer, propagated through all chain links */
|
|
22
|
+
protected _signerRef: SignerRef;
|
|
23
|
+
/** The signer used to sign the event (reads from shared ref) */
|
|
24
|
+
protected get signer(): EventSigner | undefined;
|
|
25
|
+
protected set signer(value: EventSigner | undefined);
|
|
26
|
+
/** Custom .then method that wraps the resulting promise in a new event factory */
|
|
27
|
+
protected chain(operation: EventOperation<T>): this;
|
|
28
|
+
/** Sets the event signer to use when building this event */
|
|
29
|
+
as(signer: EventSigner): this;
|
|
30
|
+
/** Strips the pubkey, sig, and id from the event */
|
|
31
|
+
strip(): EventFactory<K>;
|
|
32
|
+
/** Stamps the pubkey onto the event template */
|
|
33
|
+
stamp(signer?: EventSigner | undefined): EventFactory<K, KnownUnsignedEvent<K>>;
|
|
34
|
+
/** Signs the event using a signer interface and returns a Promise */
|
|
35
|
+
sign(signer?: EventSigner | undefined): Promise<KnownEvent<K>>;
|
|
36
|
+
/** Sets the event kind and casts the result to a {@link KnownEventTemplate<Kind>} */
|
|
37
|
+
kind<Kind extends number>(kind: Kind): EventFactory<Kind, KnownEventTemplate<Kind>>;
|
|
38
|
+
/** Sets the event content */
|
|
39
|
+
content(content: string): this;
|
|
40
|
+
/** Set the event created_at timestamp in seconds. if no value is provided, the current unix timestamp will be used */
|
|
41
|
+
created(created?: number | Date): this;
|
|
42
|
+
/** Sets the meta tags for the event */
|
|
43
|
+
meta(options: MetaTagOptions): this;
|
|
44
|
+
/** Sets the NIP-31 alt tag for the event */
|
|
45
|
+
alt(alt: string): this;
|
|
46
|
+
/** Sets the NIP-40 expiration timestamp for the event */
|
|
47
|
+
expiration(timestamp: number): this;
|
|
48
|
+
/** Sets the NIP-36 content-warning tag for the event */
|
|
49
|
+
contentWarning(warning: string | boolean): this;
|
|
50
|
+
/** Sets the NIP-70 "-" tag for the event */
|
|
51
|
+
protected(isProtected: boolean): this;
|
|
52
|
+
/** Modifies the events public and optional hidden tags */
|
|
53
|
+
modifyTags(...args: Parameters<typeof modifyTags>): this;
|
|
54
|
+
/** Modifies the events public tags array */
|
|
55
|
+
modifyPublicTags(...args: Parameters<typeof modifyPublicTags>): this;
|
|
56
|
+
/** Modifies the events hidden tags array */
|
|
57
|
+
modifyHiddenTags(...args: Exclude<Parameters<typeof modifyHiddenTags>[1], undefined>[]): this;
|
|
58
|
+
/** Sets the encrypted content of the event */
|
|
59
|
+
encryptedContent(target: string, content: string, override?: EncryptionMethod): this;
|
|
60
|
+
}
|
|
61
|
+
export {};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { isAddressableKind, isKind } from "nostr-tools/kinds";
|
|
2
|
+
import { PRESERVE_EVENT_SYMBOLS } from "../helpers/pipeline.js";
|
|
3
|
+
import { unixNow } from "../helpers/time.js";
|
|
4
|
+
import { setEncryptedContent } from "../operations/encrypted-content.js";
|
|
5
|
+
import { includeAltTag, setExpirationTimestamp, setMetaTags, setProtected, sign, stamp, } from "../operations/event.js";
|
|
6
|
+
import { modifyHiddenTags, modifyPublicTags, modifyTags } from "../operations/tags.js";
|
|
7
|
+
import { setContentWarning } from "../operations/content.js";
|
|
8
|
+
import { nanoid } from "nanoid";
|
|
9
|
+
/** Creates a blank event template with the given kind and random "d" tag if addressable */
|
|
10
|
+
export function blankEventTemplate(kind) {
|
|
11
|
+
const tags = isAddressableKind(kind) ? [["d", nanoid()]] : [];
|
|
12
|
+
return { kind, created_at: unixNow(), tags, content: "" };
|
|
13
|
+
}
|
|
14
|
+
/** Converts a nostr event to an event template and updates the created_at timestamp */
|
|
15
|
+
export function toEventTemplate(event) {
|
|
16
|
+
return {
|
|
17
|
+
kind: event.kind,
|
|
18
|
+
created_at: unixNow(),
|
|
19
|
+
tags: Array.from(event.tags),
|
|
20
|
+
content: event.content,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** The base class for building or modifying events */
|
|
24
|
+
export class EventFactory extends Promise {
|
|
25
|
+
/** Create a new event factory from a kind */
|
|
26
|
+
static fromKind(kind) {
|
|
27
|
+
return new EventFactory((res) => res({ kind, created_at: unixNow(), tags: [], content: "" }));
|
|
28
|
+
}
|
|
29
|
+
/** Create a new event factory from a nostr event */
|
|
30
|
+
static fromEvent(event) {
|
|
31
|
+
return new EventFactory((res) => res(toEventTemplate(event)));
|
|
32
|
+
}
|
|
33
|
+
/** Shared mutable reference to the signer, propagated through all chain links */
|
|
34
|
+
_signerRef = {};
|
|
35
|
+
/** The signer used to sign the event (reads from shared ref) */
|
|
36
|
+
get signer() {
|
|
37
|
+
return this._signerRef.signer;
|
|
38
|
+
}
|
|
39
|
+
set signer(value) {
|
|
40
|
+
this._signerRef.signer = value;
|
|
41
|
+
}
|
|
42
|
+
/** Custom .then method that wraps the resulting promise in a new event factory */
|
|
43
|
+
chain(operation) {
|
|
44
|
+
const Constructor = this.constructor;
|
|
45
|
+
const next = new Constructor((res) => res(this.then(async (draft) => {
|
|
46
|
+
const result = await operation(draft);
|
|
47
|
+
// Strip any symbols that are not in the preserve list, matching the
|
|
48
|
+
// behaviour of eventPipe / pipeFromAsyncArray so stale caches (e.g.
|
|
49
|
+
// HiddenTagsSymbol set by a previous modifyHiddenTags step) never
|
|
50
|
+
// leak into subsequent chain operations.
|
|
51
|
+
for (const key of Reflect.ownKeys(result)) {
|
|
52
|
+
if (typeof key === "symbol" && !PRESERVE_EVENT_SYMBOLS.has(key)) {
|
|
53
|
+
Reflect.deleteProperty(result, key);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
})));
|
|
58
|
+
// Share the same signer reference so setting .as() on any link propagates to all
|
|
59
|
+
next._signerRef = this._signerRef;
|
|
60
|
+
return next;
|
|
61
|
+
}
|
|
62
|
+
/** Sets the event signer to use when building this event */
|
|
63
|
+
as(signer) {
|
|
64
|
+
this._signerRef.signer = signer;
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
/** Strips the pubkey, sig, and id from the event */
|
|
68
|
+
strip() {
|
|
69
|
+
return new EventFactory((res) => res(this.then((v) => ({
|
|
70
|
+
content: v.content,
|
|
71
|
+
tags: v.tags,
|
|
72
|
+
created_at: v.created_at,
|
|
73
|
+
kind: v.kind,
|
|
74
|
+
}))));
|
|
75
|
+
}
|
|
76
|
+
/** Stamps the pubkey onto the event template */
|
|
77
|
+
stamp(signer = this.signer) {
|
|
78
|
+
return new EventFactory((res, rej) => {
|
|
79
|
+
if (!signer)
|
|
80
|
+
return rej(new Error("Signer required for stamping"));
|
|
81
|
+
else
|
|
82
|
+
res(this.then((template) => stamp(signer)(template)));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/** Signs the event using a signer interface and returns a Promise */
|
|
86
|
+
async sign(signer = this.signer) {
|
|
87
|
+
if (!signer)
|
|
88
|
+
throw new Error("Missing signer");
|
|
89
|
+
// Ensure the signer is available to chain operations during resolution
|
|
90
|
+
if (!this.signer)
|
|
91
|
+
this.signer = signer;
|
|
92
|
+
const template = await this;
|
|
93
|
+
const signed = await sign(signer)(template);
|
|
94
|
+
// Verify the pubkey has not changed
|
|
95
|
+
if (Reflect.has(template, "pubkey") && Reflect.get(template, "pubkey") !== signed.pubkey)
|
|
96
|
+
throw new Error("Signer modified pubkey");
|
|
97
|
+
// If its the same kind, return the signed event
|
|
98
|
+
if (isKind(signed, template.kind))
|
|
99
|
+
return signed;
|
|
100
|
+
else
|
|
101
|
+
throw new Error("Signer modified event kind");
|
|
102
|
+
}
|
|
103
|
+
/** Sets the event kind and casts the result to a {@link KnownEventTemplate<Kind>} */
|
|
104
|
+
kind(kind) {
|
|
105
|
+
return new EventFactory((e) => ({ ...e, kind }));
|
|
106
|
+
}
|
|
107
|
+
/** Sets the event content */
|
|
108
|
+
content(content) {
|
|
109
|
+
return this.chain((e) => ({ ...e, content }));
|
|
110
|
+
}
|
|
111
|
+
/** Set the event created_at timestamp in seconds. if no value is provided, the current unix timestamp will be used */
|
|
112
|
+
created(created = unixNow()) {
|
|
113
|
+
if (created instanceof Date)
|
|
114
|
+
created = Math.floor(created.getTime() / 1000);
|
|
115
|
+
return this.chain((e) => ({ ...e, created_at: created }));
|
|
116
|
+
}
|
|
117
|
+
/** Sets the meta tags for the event */
|
|
118
|
+
meta(options) {
|
|
119
|
+
return this.chain(setMetaTags(options));
|
|
120
|
+
}
|
|
121
|
+
/** Sets the NIP-31 alt tag for the event */
|
|
122
|
+
alt(alt) {
|
|
123
|
+
return this.chain(includeAltTag(alt));
|
|
124
|
+
}
|
|
125
|
+
/** Sets the NIP-40 expiration timestamp for the event */
|
|
126
|
+
expiration(timestamp) {
|
|
127
|
+
return this.chain(setExpirationTimestamp(timestamp));
|
|
128
|
+
}
|
|
129
|
+
/** Sets the NIP-36 content-warning tag for the event */
|
|
130
|
+
contentWarning(warning) {
|
|
131
|
+
return this.chain(setContentWarning(warning));
|
|
132
|
+
}
|
|
133
|
+
/** Sets the NIP-70 "-" tag for the event */
|
|
134
|
+
protected(isProtected) {
|
|
135
|
+
return this.chain(setProtected(isProtected));
|
|
136
|
+
}
|
|
137
|
+
/** Modifies the events public and optional hidden tags */
|
|
138
|
+
modifyTags(...args) {
|
|
139
|
+
let result;
|
|
140
|
+
result = this.chain((e) => modifyTags(args[0], result.signer)(e));
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
/** Modifies the events public tags array */
|
|
144
|
+
modifyPublicTags(...args) {
|
|
145
|
+
return this.chain(modifyPublicTags(...args));
|
|
146
|
+
}
|
|
147
|
+
/** Modifies the events hidden tags array */
|
|
148
|
+
modifyHiddenTags(...args) {
|
|
149
|
+
let result;
|
|
150
|
+
result = this.chain((e) => modifyHiddenTags(result.signer, ...args)(e));
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
/** Sets the encrypted content of the event */
|
|
154
|
+
encryptedContent(target, content, override) {
|
|
155
|
+
let result;
|
|
156
|
+
result = this.chain((draft) => {
|
|
157
|
+
const signer = result.signer;
|
|
158
|
+
if (!signer)
|
|
159
|
+
throw new Error("Signer required for encrypted content");
|
|
160
|
+
return setEncryptedContent(target, content, signer, override)(draft);
|
|
161
|
+
});
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { kinds, KnownEvent, KnownEventTemplate } from "../helpers/event.js";
|
|
2
|
+
import { EventFactory } from "./event.js";
|
|
3
|
+
export type MailboxesTemplate = KnownEventTemplate<kinds.RelayList>;
|
|
4
|
+
export type MailboxesOptions = {
|
|
5
|
+
inboxes?: string[];
|
|
6
|
+
outboxes?: string[];
|
|
7
|
+
};
|
|
8
|
+
/** A factory class for building NIP-65 relay list (mailboxes) events */
|
|
9
|
+
export declare class MailboxesFactory extends EventFactory<kinds.RelayList, MailboxesTemplate> {
|
|
10
|
+
/**
|
|
11
|
+
* Creates a new mailboxes factory
|
|
12
|
+
* @returns A new mailboxes factory
|
|
13
|
+
*/
|
|
14
|
+
static create(opts?: MailboxesOptions): MailboxesFactory;
|
|
15
|
+
/** Creates a new mailboxes factory from an existing relay list event with validation */
|
|
16
|
+
static modify(event: KnownEvent<kinds.RelayList>): MailboxesFactory;
|
|
17
|
+
/** Adds an outbox relay (write) */
|
|
18
|
+
addOutbox(url: string | URL): this;
|
|
19
|
+
/** Removes an outbox relay (write) */
|
|
20
|
+
removeOutbox(url: string | URL): this;
|
|
21
|
+
/** Adds an inbox relay (read) */
|
|
22
|
+
addInbox(url: string | URL): this;
|
|
23
|
+
/** Removes an inbox relay (read) */
|
|
24
|
+
removeInbox(url: string | URL): this;
|
|
25
|
+
/** Adds a relay as both inbox and outbox */
|
|
26
|
+
addRelay(url: string | URL): this;
|
|
27
|
+
/** Completely removes a relay from mailboxes */
|
|
28
|
+
removeRelay(url: string | URL): this;
|
|
29
|
+
/** Sets all inbox relays (read), replacing existing ones */
|
|
30
|
+
inboxes(urls: (string | URL)[]): this;
|
|
31
|
+
/** Sets all outbox relays (write), replacing existing ones */
|
|
32
|
+
outboxes(urls: (string | URL)[]): this;
|
|
33
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { kinds } from "../helpers/event.js";
|
|
2
|
+
import { isMailboxesEvent } from "../helpers/mailboxes.js";
|
|
3
|
+
import { addInboxRelay, addMailboxRelay, addOutboxRelay, removeInboxRelay, removeMailboxRelay, removeOutboxRelay, setInboxRelays, setOutboxRelays, } from "../operations/mailboxes.js";
|
|
4
|
+
import { blankEventTemplate, EventFactory, toEventTemplate } from "./event.js";
|
|
5
|
+
/** A factory class for building NIP-65 relay list (mailboxes) events */
|
|
6
|
+
export class MailboxesFactory extends EventFactory {
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new mailboxes factory
|
|
9
|
+
* @returns A new mailboxes factory
|
|
10
|
+
*/
|
|
11
|
+
static create(opts) {
|
|
12
|
+
let factory = new MailboxesFactory((res) => res(blankEventTemplate(kinds.RelayList)));
|
|
13
|
+
if (opts?.inboxes)
|
|
14
|
+
factory = factory.inboxes(opts.inboxes);
|
|
15
|
+
if (opts?.outboxes)
|
|
16
|
+
factory = factory.outboxes(opts.outboxes);
|
|
17
|
+
return factory;
|
|
18
|
+
}
|
|
19
|
+
/** Creates a new mailboxes factory from an existing relay list event with validation */
|
|
20
|
+
static modify(event) {
|
|
21
|
+
if (!isMailboxesEvent(event))
|
|
22
|
+
throw new Error("Event is not a relay list");
|
|
23
|
+
return new MailboxesFactory((res) => res(toEventTemplate(event)));
|
|
24
|
+
}
|
|
25
|
+
/** Adds an outbox relay (write) */
|
|
26
|
+
addOutbox(url) {
|
|
27
|
+
return this.chain(addOutboxRelay(url));
|
|
28
|
+
}
|
|
29
|
+
/** Removes an outbox relay (write) */
|
|
30
|
+
removeOutbox(url) {
|
|
31
|
+
return this.chain(removeOutboxRelay(url));
|
|
32
|
+
}
|
|
33
|
+
/** Adds an inbox relay (read) */
|
|
34
|
+
addInbox(url) {
|
|
35
|
+
return this.chain(addInboxRelay(url));
|
|
36
|
+
}
|
|
37
|
+
/** Removes an inbox relay (read) */
|
|
38
|
+
removeInbox(url) {
|
|
39
|
+
return this.chain(removeInboxRelay(url));
|
|
40
|
+
}
|
|
41
|
+
/** Adds a relay as both inbox and outbox */
|
|
42
|
+
addRelay(url) {
|
|
43
|
+
return this.chain(addMailboxRelay(url));
|
|
44
|
+
}
|
|
45
|
+
/** Completely removes a relay from mailboxes */
|
|
46
|
+
removeRelay(url) {
|
|
47
|
+
return this.chain(removeMailboxRelay(url));
|
|
48
|
+
}
|
|
49
|
+
/** Sets all inbox relays (read), replacing existing ones */
|
|
50
|
+
inboxes(urls) {
|
|
51
|
+
return this.chain(setInboxRelays(urls));
|
|
52
|
+
}
|
|
53
|
+
/** Sets all outbox relays (write), replacing existing ones */
|
|
54
|
+
outboxes(urls) {
|
|
55
|
+
return this.chain(setOutboxRelays(urls));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { kinds, KnownEvent, KnownEventTemplate } from "../helpers/event.js";
|
|
2
|
+
import { ProfileContent } from "../helpers/index.js";
|
|
3
|
+
import { EventFactory } from "./event.js";
|
|
4
|
+
export type ProfileTemplate = KnownEventTemplate<kinds.Metadata>;
|
|
5
|
+
/** A factory class for building kind 0 profile/metadata events */
|
|
6
|
+
export declare class ProfileFactory<T extends ProfileTemplate = ProfileTemplate> extends EventFactory<kinds.Metadata, T> {
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new profile factory
|
|
9
|
+
* @returns A new profile factory
|
|
10
|
+
*/
|
|
11
|
+
static create(): ProfileFactory;
|
|
12
|
+
/**
|
|
13
|
+
* Creates a new profile factory from an existing metadata event with validation
|
|
14
|
+
* @param event - The existing metadata event
|
|
15
|
+
* @returns A new profile factory
|
|
16
|
+
*/
|
|
17
|
+
static modify(event: KnownEvent<kinds.Metadata>): ProfileFactory;
|
|
18
|
+
/** Sets the entire profile content, replacing any existing content */
|
|
19
|
+
override(content: ProfileContent): this;
|
|
20
|
+
/** Updates specific fields in the profile content, merging with existing content */
|
|
21
|
+
update(content: Partial<ProfileContent>): this;
|
|
22
|
+
/** Sets the display name */
|
|
23
|
+
name(name: string): this;
|
|
24
|
+
/** Sets the username */
|
|
25
|
+
username(username: string): this;
|
|
26
|
+
/** Sets the display name (alias for name) */
|
|
27
|
+
displayName(displayName: string): this;
|
|
28
|
+
/** Sets the about/bio text */
|
|
29
|
+
about(about: string): this;
|
|
30
|
+
/** Sets the profile picture URL */
|
|
31
|
+
picture(picture: string): this;
|
|
32
|
+
/** Sets the banner image URL */
|
|
33
|
+
banner(banner: string): this;
|
|
34
|
+
/** Sets the website URL */
|
|
35
|
+
website(website: string): this;
|
|
36
|
+
/** Sets the NIP-05 identifier */
|
|
37
|
+
nip05(nip05: string): this;
|
|
38
|
+
/** Sets the Lightning Network address */
|
|
39
|
+
lnurlp(lnurlp: string): this;
|
|
40
|
+
/** Sets the Lightning Network address (LNURL) */
|
|
41
|
+
lightningAddress(address: string): this;
|
|
42
|
+
/** Sets the bot flag */
|
|
43
|
+
bot(bot: boolean): this;
|
|
44
|
+
/** Sets the languages */
|
|
45
|
+
languages(languages: string[]): this;
|
|
46
|
+
}
|