applesauce-core 0.0.0-next-20250723224513 → 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 +44 -24
- package/dist/event-store/event-store.js +81 -41
- package/dist/event-store/interface.d.ts +20 -18
- package/dist/logger.d.ts +1 -0
- package/dist/logger.js +1 -0
- 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
- package/dist/event-store/common.d.ts +0 -1
- package/dist/event-store/common.js +0 -1
|
@@ -1,8 +1,10 @@
|
|
|
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
|
-
|
|
7
|
+
/** An extended {@link EventSet} that handles replaceable events, delets, and models */
|
|
6
8
|
export declare class EventStore implements IEventStore {
|
|
7
9
|
database: EventSet;
|
|
8
10
|
/** Enable this to keep old versions of replaceable events */
|
|
@@ -18,6 +20,21 @@ export declare class EventStore implements IEventStore {
|
|
|
18
20
|
update$: Observable<NostrEvent>;
|
|
19
21
|
/** A stream of events that have been removed */
|
|
20
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>;
|
|
21
38
|
constructor();
|
|
22
39
|
protected deletedIds: Set<string>;
|
|
23
40
|
protected deletedCoords: Map<string, number>;
|
|
@@ -75,36 +92,39 @@ export declare class EventStore implements IEventStore {
|
|
|
75
92
|
/** Creates an observable that emits when event is updated */
|
|
76
93
|
updated(event: string | NostrEvent): Observable<NostrEvent>;
|
|
77
94
|
/** Creates a {@link EventModel} */
|
|
78
|
-
event(
|
|
95
|
+
event(pointer: string | EventPointer): Observable<NostrEvent | undefined>;
|
|
79
96
|
/** Creates a {@link ReplaceableModel} */
|
|
97
|
+
replaceable(pointer: AddressPointer | AddressPointerWithoutD): Observable<NostrEvent | undefined>;
|
|
80
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>;
|
|
81
101
|
/** Creates a {@link TimelineModel} */
|
|
82
102
|
timeline(filters: Filter | Filter[], includeOldVersion?: boolean): Observable<NostrEvent[]>;
|
|
83
|
-
/**
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
/** Creates a {@link ProfileModel} */
|
|
92
|
-
profile(pubkey: string): Observable<import("../helpers/profile.js").ProfileContent | undefined>;
|
|
93
|
-
/** Creates a {@link ContactsModel} */
|
|
94
|
-
contacts(pubkey: string): Observable<import("nostr-tools/nip19").ProfilePointer[]>;
|
|
95
|
-
/** Creates a {@link MuteModel} */
|
|
96
|
-
mutes(pubkey: string): Observable<import("../helpers/mutes.js").Mutes | undefined>;
|
|
97
|
-
/** Creates a {@link ReactionsModel} */
|
|
98
|
-
reactions(event: NostrEvent): Observable<import("nostr-tools").Event[]>;
|
|
99
|
-
/** Creates a {@link MailboxesModel} */
|
|
100
|
-
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<{
|
|
101
111
|
inboxes: string[];
|
|
102
112
|
outboxes: string[];
|
|
103
113
|
} | undefined>;
|
|
104
|
-
/**
|
|
105
|
-
blossomServers(
|
|
106
|
-
/**
|
|
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 */
|
|
107
119
|
thread(root: string | EventPointer | AddressPointer): Observable<import("../models/thread.js").Thread>;
|
|
108
|
-
/**
|
|
120
|
+
/** Subscribe to a event's comments */
|
|
109
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>>;
|
|
110
130
|
}
|
|
@@ -7,15 +7,16 @@ 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
|
-
|
|
18
|
-
import { CommentsModel, ThreadModel } from "../models/index.js";
|
|
18
|
+
import { EventSet } from "./event-set.js";
|
|
19
|
+
/** An extended {@link EventSet} that handles replaceable events, delets, and models */
|
|
19
20
|
export class EventStore {
|
|
20
21
|
database;
|
|
21
22
|
/** Enable this to keep old versions of replaceable events */
|
|
@@ -31,6 +32,21 @@ export class EventStore {
|
|
|
31
32
|
update$;
|
|
32
33
|
/** A stream of events that have been removed */
|
|
33
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;
|
|
34
50
|
constructor() {
|
|
35
51
|
this.database = new EventSet();
|
|
36
52
|
// verify events before they are added to the database
|
|
@@ -284,55 +300,79 @@ export class EventStore {
|
|
|
284
300
|
}
|
|
285
301
|
// Helper methods for creating models
|
|
286
302
|
/** Creates a {@link EventModel} */
|
|
287
|
-
event(
|
|
288
|
-
|
|
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);
|
|
289
321
|
}
|
|
290
|
-
/**
|
|
291
|
-
|
|
292
|
-
return this.model(ReplaceableModel,
|
|
322
|
+
/** Subscribe to an addressable event by pointer */
|
|
323
|
+
addressable(pointer) {
|
|
324
|
+
return this.model(ReplaceableModel, pointer);
|
|
293
325
|
}
|
|
294
326
|
/** Creates a {@link TimelineModel} */
|
|
295
327
|
timeline(filters, includeOldVersion = false) {
|
|
296
328
|
return this.model(TimelineModel, filters, includeOldVersion);
|
|
297
329
|
}
|
|
298
|
-
/**
|
|
299
|
-
|
|
300
|
-
return this.model(
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
return this.model(
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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 */
|
|
319
359
|
reactions(event) {
|
|
320
360
|
return this.model(ReactionsModel, event);
|
|
321
361
|
}
|
|
322
|
-
/**
|
|
323
|
-
mailboxes(pubkey) {
|
|
324
|
-
return this.model(MailboxesModel, pubkey);
|
|
325
|
-
}
|
|
326
|
-
/** Creates a {@link UserBlossomServersModel} */
|
|
327
|
-
blossomServers(pubkey) {
|
|
328
|
-
return this.model(UserBlossomServersModel, pubkey);
|
|
329
|
-
}
|
|
330
|
-
/** Creates a {@link ThreadModel} */
|
|
362
|
+
/** Subscribe to a thread */
|
|
331
363
|
thread(root) {
|
|
332
364
|
return this.model(ThreadModel, root);
|
|
333
365
|
}
|
|
334
|
-
/**
|
|
366
|
+
/** Subscribe to a event's comments */
|
|
335
367
|
comments(event) {
|
|
336
368
|
return this.model(CommentsModel, event);
|
|
337
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
|
+
}
|
|
338
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/logger.d.ts
CHANGED
package/dist/logger.js
CHANGED
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
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|