applesauce-core 0.0.0-next-20250725170333 → 0.0.0-next-20250726160247
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/event-store/event-store.d.ts +43 -24
- package/dist/event-store/event-store.js +80 -41
- package/dist/event-store/interface.d.ts +20 -18
- package/dist/models/blossom.d.ts +2 -1
- package/dist/models/blossom.js +4 -2
- package/dist/models/common.d.ts +14 -10
- package/dist/models/common.js +39 -76
- package/dist/models/contacts.d.ts +1 -1
- package/dist/models/contacts.js +4 -2
- package/dist/models/mailboxes.d.ts +2 -1
- package/dist/models/mailboxes.js +4 -2
- package/dist/models/mutes.d.ts +3 -2
- package/dist/models/mutes.js +4 -2
- package/dist/models/profile.d.ts +2 -1
- package/dist/models/profile.js +4 -2
- package/package.json +1 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Filter, NostrEvent } from "nostr-tools";
|
|
2
2
|
import { Observable } from "rxjs";
|
|
3
|
+
import { AddressPointer, EventPointer, ProfilePointer } from "nostr-tools/nip19";
|
|
4
|
+
import { AddressPointerWithoutD } from "../helpers/pointers.js";
|
|
3
5
|
import { EventSet } from "./event-set.js";
|
|
4
6
|
import { IEventStore, ModelConstructor } from "./interface.js";
|
|
5
|
-
import { AddressPointer, EventPointer } from "nostr-tools/nip19";
|
|
6
7
|
/** An extended {@link EventSet} that handles replaceable events, delets, and models */
|
|
7
8
|
export declare class EventStore implements IEventStore {
|
|
8
9
|
database: EventSet;
|
|
@@ -19,6 +20,21 @@ export declare class EventStore implements IEventStore {
|
|
|
19
20
|
update$: Observable<NostrEvent>;
|
|
20
21
|
/** A stream of events that have been removed */
|
|
21
22
|
remove$: Observable<NostrEvent>;
|
|
23
|
+
/**
|
|
24
|
+
* A method that will be called when an event isn't found in the store
|
|
25
|
+
* @experimental
|
|
26
|
+
*/
|
|
27
|
+
eventLoader?: (pointer: EventPointer) => Observable<NostrEvent>;
|
|
28
|
+
/**
|
|
29
|
+
* A method that will be called when a replaceable event isn't found in the store
|
|
30
|
+
* @experimental
|
|
31
|
+
*/
|
|
32
|
+
replaceableLoader?: (pointer: AddressPointerWithoutD) => Observable<NostrEvent>;
|
|
33
|
+
/**
|
|
34
|
+
* A method that will be called when an addressable event isn't found in the store
|
|
35
|
+
* @experimental
|
|
36
|
+
*/
|
|
37
|
+
addressableLoader?: (pointer: AddressPointer) => Observable<NostrEvent>;
|
|
22
38
|
constructor();
|
|
23
39
|
protected deletedIds: Set<string>;
|
|
24
40
|
protected deletedCoords: Map<string, number>;
|
|
@@ -76,36 +92,39 @@ export declare class EventStore implements IEventStore {
|
|
|
76
92
|
/** Creates an observable that emits when event is updated */
|
|
77
93
|
updated(event: string | NostrEvent): Observable<NostrEvent>;
|
|
78
94
|
/** Creates a {@link EventModel} */
|
|
79
|
-
event(
|
|
95
|
+
event(pointer: string | EventPointer): Observable<NostrEvent | undefined>;
|
|
80
96
|
/** Creates a {@link ReplaceableModel} */
|
|
97
|
+
replaceable(pointer: AddressPointer | AddressPointerWithoutD): Observable<NostrEvent | undefined>;
|
|
81
98
|
replaceable(kind: number, pubkey: string, identifier?: string): Observable<NostrEvent | undefined>;
|
|
99
|
+
/** Subscribe to an addressable event by pointer */
|
|
100
|
+
addressable(pointer: AddressPointer): Observable<NostrEvent | undefined>;
|
|
82
101
|
/** Creates a {@link TimelineModel} */
|
|
83
102
|
timeline(filters: Filter | Filter[], includeOldVersion?: boolean): Observable<NostrEvent[]>;
|
|
84
|
-
/**
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
/** Creates a {@link ProfileModel} */
|
|
93
|
-
profile(pubkey: string): Observable<import("../helpers/profile.js").ProfileContent | undefined>;
|
|
94
|
-
/** Creates a {@link ContactsModel} */
|
|
95
|
-
contacts(pubkey: string): Observable<import("nostr-tools/nip19").ProfilePointer[]>;
|
|
96
|
-
/** Creates a {@link MuteModel} */
|
|
97
|
-
mutes(pubkey: string): Observable<import("../helpers/mutes.js").Mutes | undefined>;
|
|
98
|
-
/** Creates a {@link ReactionsModel} */
|
|
99
|
-
reactions(event: NostrEvent): Observable<import("nostr-tools").Event[]>;
|
|
100
|
-
/** Creates a {@link MailboxesModel} */
|
|
101
|
-
mailboxes(pubkey: string): Observable<{
|
|
103
|
+
/** Subscribe to a users profile */
|
|
104
|
+
profile(user: string | ProfilePointer): Observable<import("../helpers/profile.js").ProfileContent | undefined>;
|
|
105
|
+
/** Subscribe to a users contacts */
|
|
106
|
+
contacts(user: string | ProfilePointer): Observable<ProfilePointer[]>;
|
|
107
|
+
/** Subscribe to a users mutes */
|
|
108
|
+
mutes(user: string | ProfilePointer): Observable<import("../helpers/mutes.js").Mutes | undefined>;
|
|
109
|
+
/** Subscribe to a users NIP-65 mailboxes */
|
|
110
|
+
mailboxes(user: string | ProfilePointer): Observable<{
|
|
102
111
|
inboxes: string[];
|
|
103
112
|
outboxes: string[];
|
|
104
113
|
} | undefined>;
|
|
105
|
-
/**
|
|
106
|
-
blossomServers(
|
|
107
|
-
/**
|
|
114
|
+
/** Subscribe to a users blossom servers */
|
|
115
|
+
blossomServers(user: string | ProfilePointer): Observable<URL[]>;
|
|
116
|
+
/** Subscribe to an event's reactions */
|
|
117
|
+
reactions(event: NostrEvent): Observable<import("nostr-tools").Event[]>;
|
|
118
|
+
/** Subscribe to a thread */
|
|
108
119
|
thread(root: string | EventPointer | AddressPointer): Observable<import("../models/thread.js").Thread>;
|
|
109
|
-
/**
|
|
120
|
+
/** Subscribe to a event's comments */
|
|
110
121
|
comments(event: NostrEvent): Observable<import("nostr-tools").Event[]>;
|
|
122
|
+
/** @deprecated use multiple {@link EventModel} instead */
|
|
123
|
+
events(ids: string[]): Observable<Record<string, NostrEvent | undefined>>;
|
|
124
|
+
/** @deprecated use multiple {@link ReplaceableModel} instead */
|
|
125
|
+
replaceableSet(pointers: {
|
|
126
|
+
kind: number;
|
|
127
|
+
pubkey: string;
|
|
128
|
+
identifier?: string;
|
|
129
|
+
}[]): Observable<Record<string, NostrEvent | undefined>>;
|
|
111
130
|
}
|
|
@@ -7,15 +7,15 @@ import { EventStoreSymbol, FromCacheSymbol, getReplaceableAddress, isReplaceable
|
|
|
7
7
|
import { matchFilters } from "../helpers/filter.js";
|
|
8
8
|
import { parseCoordinate } from "../helpers/pointers.js";
|
|
9
9
|
import { addSeenRelay, getSeenRelays } from "../helpers/relays.js";
|
|
10
|
+
import { UserBlossomServersModel } from "../models/blossom.js";
|
|
10
11
|
import { EventModel, EventsModel, ReplaceableModel, ReplaceableSetModel, TimelineModel } from "../models/common.js";
|
|
11
|
-
import { EventSet } from "./event-set.js";
|
|
12
|
-
import { ProfileModel } from "../models/profile.js";
|
|
13
12
|
import { ContactsModel } from "../models/contacts.js";
|
|
13
|
+
import { CommentsModel, ThreadModel } from "../models/index.js";
|
|
14
|
+
import { MailboxesModel } from "../models/mailboxes.js";
|
|
14
15
|
import { MuteModel } from "../models/mutes.js";
|
|
16
|
+
import { ProfileModel } from "../models/profile.js";
|
|
15
17
|
import { ReactionsModel } from "../models/reactions.js";
|
|
16
|
-
import {
|
|
17
|
-
import { UserBlossomServersModel } from "../models/blossom.js";
|
|
18
|
-
import { CommentsModel, ThreadModel } from "../models/index.js";
|
|
18
|
+
import { EventSet } from "./event-set.js";
|
|
19
19
|
/** An extended {@link EventSet} that handles replaceable events, delets, and models */
|
|
20
20
|
export class EventStore {
|
|
21
21
|
database;
|
|
@@ -32,6 +32,21 @@ export class EventStore {
|
|
|
32
32
|
update$;
|
|
33
33
|
/** A stream of events that have been removed */
|
|
34
34
|
remove$;
|
|
35
|
+
/**
|
|
36
|
+
* A method that will be called when an event isn't found in the store
|
|
37
|
+
* @experimental
|
|
38
|
+
*/
|
|
39
|
+
eventLoader;
|
|
40
|
+
/**
|
|
41
|
+
* A method that will be called when a replaceable event isn't found in the store
|
|
42
|
+
* @experimental
|
|
43
|
+
*/
|
|
44
|
+
replaceableLoader;
|
|
45
|
+
/**
|
|
46
|
+
* A method that will be called when an addressable event isn't found in the store
|
|
47
|
+
* @experimental
|
|
48
|
+
*/
|
|
49
|
+
addressableLoader;
|
|
35
50
|
constructor() {
|
|
36
51
|
this.database = new EventSet();
|
|
37
52
|
// verify events before they are added to the database
|
|
@@ -285,55 +300,79 @@ export class EventStore {
|
|
|
285
300
|
}
|
|
286
301
|
// Helper methods for creating models
|
|
287
302
|
/** Creates a {@link EventModel} */
|
|
288
|
-
event(
|
|
289
|
-
|
|
303
|
+
event(pointer) {
|
|
304
|
+
if (typeof pointer === "string")
|
|
305
|
+
pointer = { id: pointer };
|
|
306
|
+
return this.model(EventModel, pointer);
|
|
307
|
+
}
|
|
308
|
+
replaceable(...args) {
|
|
309
|
+
let pointer;
|
|
310
|
+
// Parse arguments
|
|
311
|
+
if (args.length === 1) {
|
|
312
|
+
pointer = args[0];
|
|
313
|
+
}
|
|
314
|
+
else if (args.length === 3 || args.length === 2) {
|
|
315
|
+
let [kind, pubkey, identifier] = args;
|
|
316
|
+
pointer = { kind, pubkey, identifier };
|
|
317
|
+
}
|
|
318
|
+
if (!pointer)
|
|
319
|
+
throw new Error("Invalid arguments, expected address pointer or kind, pubkey, identifier");
|
|
320
|
+
return this.model(ReplaceableModel, pointer);
|
|
290
321
|
}
|
|
291
|
-
/**
|
|
292
|
-
|
|
293
|
-
return this.model(ReplaceableModel,
|
|
322
|
+
/** Subscribe to an addressable event by pointer */
|
|
323
|
+
addressable(pointer) {
|
|
324
|
+
return this.model(ReplaceableModel, pointer);
|
|
294
325
|
}
|
|
295
326
|
/** Creates a {@link TimelineModel} */
|
|
296
327
|
timeline(filters, includeOldVersion = false) {
|
|
297
328
|
return this.model(TimelineModel, filters, includeOldVersion);
|
|
298
329
|
}
|
|
299
|
-
/**
|
|
300
|
-
|
|
301
|
-
return this.model(
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
return this.model(
|
|
314
|
-
}
|
|
315
|
-
/**
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
330
|
+
/** Subscribe to a users profile */
|
|
331
|
+
profile(user) {
|
|
332
|
+
return this.model(ProfileModel, user);
|
|
333
|
+
}
|
|
334
|
+
/** Subscribe to a users contacts */
|
|
335
|
+
contacts(user) {
|
|
336
|
+
if (typeof user === "string")
|
|
337
|
+
user = { pubkey: user };
|
|
338
|
+
return this.model(ContactsModel, user);
|
|
339
|
+
}
|
|
340
|
+
/** Subscribe to a users mutes */
|
|
341
|
+
mutes(user) {
|
|
342
|
+
if (typeof user === "string")
|
|
343
|
+
user = { pubkey: user };
|
|
344
|
+
return this.model(MuteModel, user);
|
|
345
|
+
}
|
|
346
|
+
/** Subscribe to a users NIP-65 mailboxes */
|
|
347
|
+
mailboxes(user) {
|
|
348
|
+
if (typeof user === "string")
|
|
349
|
+
user = { pubkey: user };
|
|
350
|
+
return this.model(MailboxesModel, user);
|
|
351
|
+
}
|
|
352
|
+
/** Subscribe to a users blossom servers */
|
|
353
|
+
blossomServers(user) {
|
|
354
|
+
if (typeof user === "string")
|
|
355
|
+
user = { pubkey: user };
|
|
356
|
+
return this.model(UserBlossomServersModel, user);
|
|
357
|
+
}
|
|
358
|
+
/** Subscribe to an event's reactions */
|
|
320
359
|
reactions(event) {
|
|
321
360
|
return this.model(ReactionsModel, event);
|
|
322
361
|
}
|
|
323
|
-
/**
|
|
324
|
-
mailboxes(pubkey) {
|
|
325
|
-
return this.model(MailboxesModel, pubkey);
|
|
326
|
-
}
|
|
327
|
-
/** Creates a {@link UserBlossomServersModel} */
|
|
328
|
-
blossomServers(pubkey) {
|
|
329
|
-
return this.model(UserBlossomServersModel, pubkey);
|
|
330
|
-
}
|
|
331
|
-
/** Creates a {@link ThreadModel} */
|
|
362
|
+
/** Subscribe to a thread */
|
|
332
363
|
thread(root) {
|
|
333
364
|
return this.model(ThreadModel, root);
|
|
334
365
|
}
|
|
335
|
-
/**
|
|
366
|
+
/** Subscribe to a event's comments */
|
|
336
367
|
comments(event) {
|
|
337
368
|
return this.model(CommentsModel, event);
|
|
338
369
|
}
|
|
370
|
+
/** @deprecated use multiple {@link EventModel} instead */
|
|
371
|
+
events(ids) {
|
|
372
|
+
return this.model(EventsModel, ids);
|
|
373
|
+
}
|
|
374
|
+
/** @deprecated use multiple {@link ReplaceableModel} instead */
|
|
375
|
+
replaceableSet(pointers) {
|
|
376
|
+
return this.model(ReplaceableSetModel, pointers);
|
|
377
|
+
}
|
|
339
378
|
}
|
|
@@ -65,25 +65,13 @@ export interface IEventStoreSubscriptions {
|
|
|
65
65
|
}
|
|
66
66
|
/** Methods for creating common models */
|
|
67
67
|
export interface IEventStoreModels {
|
|
68
|
+
model<T extends unknown, Args extends Array<any>>(constructor: ModelConstructor<T, Args>, ...args: Args): Observable<T>;
|
|
68
69
|
event(id: string): Observable<NostrEvent | undefined>;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
replaceableSet(pointers: {
|
|
72
|
-
kind: number;
|
|
73
|
-
pubkey: string;
|
|
74
|
-
identifier?: string;
|
|
75
|
-
}[]): Observable<Record<string, NostrEvent>>;
|
|
70
|
+
replaceable(pointer: AddressPointerWithoutD): Observable<NostrEvent | undefined>;
|
|
71
|
+
addressable(pointer: AddressPointer): Observable<NostrEvent | undefined>;
|
|
76
72
|
timeline(filters: Filter | Filter[], includeOldVersion?: boolean): Observable<NostrEvent[]>;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
mutes(pubkey: string): Observable<Mutes | undefined>;
|
|
80
|
-
reactions(event: NostrEvent): Observable<NostrEvent[]>;
|
|
81
|
-
mailboxes(pubkey: string): Observable<{
|
|
82
|
-
inboxes: string[];
|
|
83
|
-
outboxes: string[];
|
|
84
|
-
} | undefined>;
|
|
85
|
-
blossomServers(pubkey: string): Observable<URL[]>;
|
|
86
|
-
thread(root: string | EventPointer | AddressPointer): Observable<Thread>;
|
|
73
|
+
events(ids: string[]): Observable<Record<string, NostrEvent | undefined>>;
|
|
74
|
+
replaceableSet(pointers: (AddressPointer | AddressPointerWithoutD)[]): Observable<Record<string, NostrEvent | undefined>>;
|
|
87
75
|
}
|
|
88
76
|
/** A computed view of an event set or event store */
|
|
89
77
|
export type Model<T extends unknown> = (events: IEventStore) => Observable<T>;
|
|
@@ -99,5 +87,19 @@ export interface IEventStore extends IEventStoreRead, IEventStoreStreams, IEvent
|
|
|
99
87
|
filters(filters: Filter | Filter[]): Observable<NostrEvent>;
|
|
100
88
|
updated(id: string | NostrEvent): Observable<NostrEvent>;
|
|
101
89
|
removed(id: string): Observable<never>;
|
|
102
|
-
|
|
90
|
+
replaceable(kind: number, pubkey: string, identifier?: string): Observable<NostrEvent | undefined>;
|
|
91
|
+
replaceable(pointer: AddressPointerWithoutD): Observable<NostrEvent | undefined>;
|
|
92
|
+
eventLoader?: (pointer: EventPointer) => Observable<NostrEvent>;
|
|
93
|
+
replaceableLoader?: (pointer: AddressPointerWithoutD) => Observable<NostrEvent>;
|
|
94
|
+
addressableLoader?: (pointer: AddressPointer) => Observable<NostrEvent>;
|
|
95
|
+
profile(user: string | ProfilePointer): Observable<ProfileContent | undefined>;
|
|
96
|
+
contacts(user: string | ProfilePointer): Observable<ProfilePointer[]>;
|
|
97
|
+
mutes(user: string | ProfilePointer): Observable<Mutes | undefined>;
|
|
98
|
+
mailboxes(user: string | ProfilePointer): Observable<{
|
|
99
|
+
inboxes: string[];
|
|
100
|
+
outboxes: string[];
|
|
101
|
+
} | undefined>;
|
|
102
|
+
blossomServers(user: string | ProfilePointer): Observable<URL[]>;
|
|
103
|
+
reactions(event: NostrEvent): Observable<NostrEvent[]>;
|
|
104
|
+
thread(root: string | EventPointer | AddressPointer): Observable<Thread>;
|
|
103
105
|
}
|
package/dist/models/blossom.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ProfilePointer } from "nostr-tools/nip19";
|
|
1
2
|
import { Model } from "../event-store/interface.js";
|
|
2
3
|
/** A model that returns a users blossom servers */
|
|
3
|
-
export declare function UserBlossomServersModel(
|
|
4
|
+
export declare function UserBlossomServersModel(user: string | ProfilePointer): Model<URL[]>;
|
package/dist/models/blossom.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { map } from "rxjs/operators";
|
|
2
2
|
import { BLOSSOM_SERVER_LIST_KIND, getBlossomServersFromList } from "../helpers/blossom.js";
|
|
3
3
|
/** A model that returns a users blossom servers */
|
|
4
|
-
export function UserBlossomServersModel(
|
|
4
|
+
export function UserBlossomServersModel(user) {
|
|
5
|
+
if (typeof user === "string")
|
|
6
|
+
user = { pubkey: user };
|
|
5
7
|
return (store) => store
|
|
6
|
-
.replaceable(BLOSSOM_SERVER_LIST_KIND, pubkey)
|
|
8
|
+
.replaceable({ kind: BLOSSOM_SERVER_LIST_KIND, pubkey: user.pubkey, relays: user.relays })
|
|
7
9
|
.pipe(map((event) => (event ? getBlossomServersFromList(event) : [])));
|
|
8
10
|
}
|
package/dist/models/common.d.ts
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { Filter, NostrEvent } from "nostr-tools";
|
|
2
|
+
import { AddressPointer, EventPointer } from "nostr-tools/nip19";
|
|
2
3
|
import { Model } from "../event-store/interface.js";
|
|
4
|
+
import { AddressPointerWithoutD } from "../helpers/index.js";
|
|
3
5
|
/** A model that returns a single event or undefined when its removed */
|
|
4
|
-
export declare function EventModel(
|
|
6
|
+
export declare function EventModel(pointer: string | EventPointer): Model<NostrEvent | undefined>;
|
|
5
7
|
/** A model that returns the latest version of a replaceable event or undefined if its removed */
|
|
6
|
-
export declare function ReplaceableModel(
|
|
8
|
+
export declare function ReplaceableModel(pointer: AddressPointer | AddressPointerWithoutD): Model<NostrEvent | undefined>;
|
|
7
9
|
/** A model that returns an array of sorted events matching the filters */
|
|
8
10
|
export declare function TimelineModel(filters: Filter | Filter[], includeOldVersion?: boolean): Model<NostrEvent[]>;
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
11
|
+
/**
|
|
12
|
+
* A model that returns a multiple events in a map
|
|
13
|
+
* @deprecated use multiple {@link EventModel} instead
|
|
14
|
+
*/
|
|
15
|
+
export declare function EventsModel(ids: string[]): Model<Record<string, NostrEvent | undefined>>;
|
|
16
|
+
/**
|
|
17
|
+
* A model that returns a directory of events by their UID
|
|
18
|
+
* @deprecated use multiple {@link ReplaceableModel} instead
|
|
19
|
+
*/
|
|
20
|
+
export declare function ReplaceableSetModel(pointers: (AddressPointer | AddressPointerWithoutD)[]): Model<Record<string, NostrEvent | undefined>>;
|
package/dist/models/common.js
CHANGED
|
@@ -1,40 +1,52 @@
|
|
|
1
|
-
import { defer, distinctUntilChanged, EMPTY, endWith, filter, finalize,
|
|
1
|
+
import { combineLatest, defer, distinctUntilChanged, EMPTY, endWith, filter, finalize, map, merge, mergeWith, of, repeat, scan, takeUntil, tap, } from "rxjs";
|
|
2
|
+
import { insertEventIntoDescendingList } from "nostr-tools/utils";
|
|
2
3
|
import { createReplaceableAddress, getEventUID, getReplaceableIdentifier, isReplaceable, matchFilters, } from "../helpers/index.js";
|
|
3
4
|
import { claimEvents } from "../observable/claim-events.js";
|
|
4
5
|
import { claimLatest } from "../observable/claim-latest.js";
|
|
5
|
-
import { insertEventIntoDescendingList } from "nostr-tools/utils";
|
|
6
6
|
import { withImmediateValueOrDefault } from "../observable/with-immediate-value.js";
|
|
7
7
|
/** A model that returns a single event or undefined when its removed */
|
|
8
|
-
export function EventModel(
|
|
8
|
+
export function EventModel(pointer) {
|
|
9
|
+
if (typeof pointer === "string")
|
|
10
|
+
pointer = { id: pointer };
|
|
9
11
|
return (events) => merge(
|
|
10
12
|
// get current event and ignore if there is none
|
|
11
13
|
defer(() => {
|
|
12
|
-
let event = events.getEvent(id);
|
|
13
|
-
|
|
14
|
+
let event = events.getEvent(pointer.id);
|
|
15
|
+
if (event)
|
|
16
|
+
return of(event);
|
|
17
|
+
// If there is a loader, use it to get the event
|
|
18
|
+
return events.eventLoader?.(pointer) ?? EMPTY;
|
|
14
19
|
}),
|
|
15
|
-
//
|
|
16
|
-
events.insert$.pipe(filter((e) => e.id === id)),
|
|
17
|
-
// subscribe to updates
|
|
18
|
-
events.updated(id),
|
|
20
|
+
// Listen for new events
|
|
21
|
+
events.insert$.pipe(filter((e) => e.id === pointer.id)),
|
|
19
22
|
// emit undefined when deleted
|
|
20
|
-
events.removed(id).pipe(endWith(undefined))).pipe(
|
|
23
|
+
events.removed(pointer.id).pipe(endWith(undefined))).pipe(
|
|
21
24
|
// claim all events
|
|
22
25
|
claimLatest(events),
|
|
26
|
+
// ignore duplicate events
|
|
27
|
+
distinctUntilChanged((a, b) => a?.id === b?.id),
|
|
23
28
|
// always emit undefined so the observable is synchronous
|
|
24
29
|
withImmediateValueOrDefault(undefined));
|
|
25
30
|
}
|
|
26
31
|
/** A model that returns the latest version of a replaceable event or undefined if its removed */
|
|
27
|
-
export function ReplaceableModel(
|
|
32
|
+
export function ReplaceableModel(pointer) {
|
|
28
33
|
return (events) => {
|
|
29
34
|
let current = undefined;
|
|
30
35
|
return merge(
|
|
31
36
|
// lazily get current event
|
|
32
37
|
defer(() => {
|
|
33
|
-
let event = events.getReplaceable(kind, pubkey,
|
|
34
|
-
|
|
38
|
+
let event = events.getReplaceable(pointer.kind, pointer.pubkey, pointer.identifier);
|
|
39
|
+
if (event)
|
|
40
|
+
return of(event);
|
|
41
|
+
else if (pointer.identifier !== undefined)
|
|
42
|
+
return events.addressableLoader?.(pointer) ?? EMPTY;
|
|
43
|
+
else
|
|
44
|
+
return events.replaceableLoader?.(pointer) ?? EMPTY;
|
|
35
45
|
}),
|
|
36
46
|
// subscribe to new events
|
|
37
|
-
events.insert$.pipe(filter((e) => e.pubkey == pubkey &&
|
|
47
|
+
events.insert$.pipe(filter((e) => e.pubkey == pointer.pubkey &&
|
|
48
|
+
e.kind === pointer.kind &&
|
|
49
|
+
(pointer.identifier !== undefined ? getReplaceableIdentifier(e) === pointer.identifier : true)))).pipe(
|
|
38
50
|
// only update if event is newer
|
|
39
51
|
distinctUntilChanged((prev, event) => {
|
|
40
52
|
// are the events the same? i.e. is the prev event older
|
|
@@ -108,69 +120,20 @@ export function TimelineModel(filters, includeOldVersion) {
|
|
|
108
120
|
finalize(() => seen.clear()));
|
|
109
121
|
};
|
|
110
122
|
}
|
|
111
|
-
/**
|
|
123
|
+
/**
|
|
124
|
+
* A model that returns a multiple events in a map
|
|
125
|
+
* @deprecated use multiple {@link EventModel} instead
|
|
126
|
+
*/
|
|
112
127
|
export function EventsModel(ids) {
|
|
113
|
-
return (events) =>
|
|
114
|
-
// lazily get existing events
|
|
115
|
-
defer(() => from(ids.map((id) => events.getEvent(id)))),
|
|
116
|
-
// subscribe to new events
|
|
117
|
-
events.insert$.pipe(filter((e) => ids.includes(e.id))),
|
|
118
|
-
// subscribe to updates
|
|
119
|
-
events.update$.pipe(filter((e) => ids.includes(e.id)))).pipe(
|
|
120
|
-
// ignore empty messages
|
|
121
|
-
filter((e) => !!e),
|
|
122
|
-
// claim all events until cleanup
|
|
123
|
-
claimEvents(events),
|
|
124
|
-
// watch for removed events
|
|
125
|
-
mergeWith(events.remove$.pipe(filter((e) => ids.includes(e.id)), map((e) => e.id))),
|
|
126
|
-
// merge all events into a directory
|
|
127
|
-
scan((dir, event) => {
|
|
128
|
-
if (typeof event === "string") {
|
|
129
|
-
// delete event by id
|
|
130
|
-
const clone = { ...dir };
|
|
131
|
-
delete clone[event];
|
|
132
|
-
return clone;
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
// add even to directory
|
|
136
|
-
return { ...dir, [event.id]: event };
|
|
137
|
-
}
|
|
138
|
-
}, {}));
|
|
128
|
+
return (events) => combineLatest(Object.fromEntries(ids.map((id) => [id, events.model(EventModel, { id })])));
|
|
139
129
|
}
|
|
140
|
-
/**
|
|
130
|
+
/**
|
|
131
|
+
* A model that returns a directory of events by their UID
|
|
132
|
+
* @deprecated use multiple {@link ReplaceableModel} instead
|
|
133
|
+
*/
|
|
141
134
|
export function ReplaceableSetModel(pointers) {
|
|
142
|
-
return (events) =>
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
defer(() => from(pointers.map((p) => events.getReplaceable(p.kind, p.pubkey, p.identifier)))),
|
|
147
|
-
// subscribe to new events
|
|
148
|
-
events.insert$.pipe(filter((e) => isReplaceable(e.kind) && uids.has(getEventUID(e))))).pipe(
|
|
149
|
-
// filter out undefined
|
|
150
|
-
filter((e) => !!e),
|
|
151
|
-
// claim all events
|
|
152
|
-
claimEvents(events),
|
|
153
|
-
// convert events to add commands
|
|
154
|
-
map((e) => ["add", e]),
|
|
155
|
-
// watch for removed events
|
|
156
|
-
mergeWith(events.remove$.pipe(filter((e) => isReplaceable(e.kind) && uids.has(getEventUID(e))), map((e) => ["remove", e]))),
|
|
157
|
-
// reduce events into directory
|
|
158
|
-
scan((dir, [action, event]) => {
|
|
159
|
-
const uid = getEventUID(event);
|
|
160
|
-
if (action === "add") {
|
|
161
|
-
// add event to dir if its newer
|
|
162
|
-
if (!dir[uid] || dir[uid].created_at < event.created_at)
|
|
163
|
-
return { ...dir, [uid]: event };
|
|
164
|
-
}
|
|
165
|
-
else if (action === "remove" && dir[uid] === event) {
|
|
166
|
-
// remove event from dir
|
|
167
|
-
let newDir = { ...dir };
|
|
168
|
-
delete newDir[uid];
|
|
169
|
-
return newDir;
|
|
170
|
-
}
|
|
171
|
-
return dir;
|
|
172
|
-
}, {}),
|
|
173
|
-
// ignore changes that do not modify the directory
|
|
174
|
-
distinctUntilChanged());
|
|
175
|
-
};
|
|
135
|
+
return (events) => combineLatest(Object.fromEntries(pointers.map((pointer) => [
|
|
136
|
+
createReplaceableAddress(pointer.kind, pointer.pubkey, pointer.identifier),
|
|
137
|
+
events.model(ReplaceableModel, pointer),
|
|
138
|
+
])));
|
|
176
139
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ProfilePointer } from "nostr-tools/nip19";
|
|
2
2
|
import { Model } from "../event-store/interface.js";
|
|
3
3
|
/** A model that returns all contacts for a user */
|
|
4
|
-
export declare function ContactsModel(
|
|
4
|
+
export declare function ContactsModel(user: string | ProfilePointer): Model<ProfilePointer[]>;
|
|
5
5
|
/** A model that returns all public contacts for a user */
|
|
6
6
|
export declare function PublicContactsModel(pubkey: string): Model<ProfilePointer[] | undefined>;
|
|
7
7
|
/** A model that returns all hidden contacts for a user */
|
package/dist/models/contacts.js
CHANGED
|
@@ -3,8 +3,10 @@ import { map } from "rxjs/operators";
|
|
|
3
3
|
import { getContacts, getHiddenContacts, getPublicContacts } from "../helpers/contacts.js";
|
|
4
4
|
import { watchEventUpdates } from "../observable/index.js";
|
|
5
5
|
/** A model that returns all contacts for a user */
|
|
6
|
-
export function ContactsModel(
|
|
7
|
-
|
|
6
|
+
export function ContactsModel(user) {
|
|
7
|
+
if (typeof user === "string")
|
|
8
|
+
user = { pubkey: user };
|
|
9
|
+
return (events) => events.replaceable({ kind: kinds.Contacts, pubkey: user.pubkey, relays: user.relays }).pipe(
|
|
8
10
|
// listen for event updates (hidden tags unlocked)
|
|
9
11
|
watchEventUpdates(events),
|
|
10
12
|
// Get all contacts
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { ProfilePointer } from "nostr-tools/nip19";
|
|
1
2
|
import { Model } from "../event-store/interface.js";
|
|
2
3
|
/** A model that gets and parses the inbox and outbox relays for a pubkey */
|
|
3
|
-
export declare function MailboxesModel(
|
|
4
|
+
export declare function MailboxesModel(user: string | ProfilePointer): Model<{
|
|
4
5
|
inboxes: string[];
|
|
5
6
|
outboxes: string[];
|
|
6
7
|
} | undefined>;
|
package/dist/models/mailboxes.js
CHANGED
|
@@ -2,8 +2,10 @@ import { kinds } from "nostr-tools";
|
|
|
2
2
|
import { map } from "rxjs/operators";
|
|
3
3
|
import { getInboxes, getOutboxes } from "../helpers/mailboxes.js";
|
|
4
4
|
/** A model that gets and parses the inbox and outbox relays for a pubkey */
|
|
5
|
-
export function MailboxesModel(
|
|
6
|
-
|
|
5
|
+
export function MailboxesModel(user) {
|
|
6
|
+
if (typeof user === "string")
|
|
7
|
+
user = { pubkey: user };
|
|
8
|
+
return (events) => events.replaceable({ kind: kinds.RelayList, pubkey: user.pubkey, relays: user.relays }).pipe(map((event) => event && {
|
|
7
9
|
inboxes: getInboxes(event),
|
|
8
10
|
outboxes: getOutboxes(event),
|
|
9
11
|
}));
|
package/dist/models/mutes.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ProfilePointer } from "nostr-tools/nip19";
|
|
2
2
|
import { Model } from "../event-store/interface.js";
|
|
3
|
+
import { Mutes } from "../helpers/mutes.js";
|
|
3
4
|
/** A model that returns all a users muted things */
|
|
4
|
-
export declare function MuteModel(
|
|
5
|
+
export declare function MuteModel(user: string | ProfilePointer): Model<Mutes | undefined>;
|
|
5
6
|
/** A model that returns all a users public muted things */
|
|
6
7
|
export declare function PublicMuteModel(pubkey: string): Model<Mutes | undefined>;
|
|
7
8
|
/** A model that returns all a users hidden muted things */
|
package/dist/models/mutes.js
CHANGED
|
@@ -3,8 +3,10 @@ import { map } from "rxjs/operators";
|
|
|
3
3
|
import { getHiddenMutedThings, getMutedThings, getPublicMutedThings } from "../helpers/mutes.js";
|
|
4
4
|
import { watchEventUpdates } from "../observable/watch-event-updates.js";
|
|
5
5
|
/** A model that returns all a users muted things */
|
|
6
|
-
export function MuteModel(
|
|
7
|
-
|
|
6
|
+
export function MuteModel(user) {
|
|
7
|
+
if (typeof user === "string")
|
|
8
|
+
user = { pubkey: user };
|
|
9
|
+
return (events) => events.replaceable({ kind: kinds.Mutelist, pubkey: user.pubkey, relays: user.relays }).pipe(
|
|
8
10
|
// listen for event updates (hidden tags unlocked)
|
|
9
11
|
watchEventUpdates(events),
|
|
10
12
|
// Get all muted things
|
package/dist/models/profile.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Model } from "../event-store/interface.js";
|
|
2
2
|
import { ProfileContent } from "../helpers/profile.js";
|
|
3
|
+
import { ProfilePointer } from "nostr-tools/nip19";
|
|
3
4
|
/** A model that gets and parses the kind 0 metadata for a pubkey */
|
|
4
|
-
export declare function ProfileModel(
|
|
5
|
+
export declare function ProfileModel(user: string | ProfilePointer): Model<ProfileContent | undefined>;
|
package/dist/models/profile.js
CHANGED
|
@@ -3,8 +3,10 @@ import { filter, map } from "rxjs/operators";
|
|
|
3
3
|
import { getProfileContent, isValidProfile } from "../helpers/profile.js";
|
|
4
4
|
import { withImmediateValueOrDefault } from "../observable/with-immediate-value.js";
|
|
5
5
|
/** A model that gets and parses the kind 0 metadata for a pubkey */
|
|
6
|
-
export function ProfileModel(
|
|
7
|
-
|
|
6
|
+
export function ProfileModel(user) {
|
|
7
|
+
if (typeof user === "string")
|
|
8
|
+
user = { pubkey: user };
|
|
9
|
+
return (events) => events.replaceable({ kind: kinds.Metadata, pubkey: user.pubkey, relays: user.relays }).pipe(
|
|
8
10
|
// Filter out invalid profile events
|
|
9
11
|
filter(isValidProfile),
|
|
10
12
|
// Parse the profile event into a ProfileContent
|