applesauce-core 0.0.0-next-20250128143648 → 0.0.0-next-20250128154531
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/helpers/channels.d.ts +10 -0
- package/dist/helpers/channels.js +27 -0
- package/dist/helpers/index.d.ts +2 -0
- package/dist/helpers/index.js +2 -0
- package/dist/helpers/user-status.d.ts +18 -0
- package/dist/helpers/user-status.js +21 -0
- package/dist/queries/channels.d.ts +11 -0
- package/dist/queries/channels.js +73 -0
- package/dist/queries/index.d.ts +1 -0
- package/dist/queries/index.js +1 -0
- package/dist/queries/user-status.d.ts +11 -0
- package/dist/queries/user-status.js +39 -0
- package/package.json +3 -2
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { nip19, NostrEvent } from "nostr-tools";
|
|
2
|
+
import { ChannelMetadata } from "nostr-tools/nip28";
|
|
3
|
+
export declare const ChannelMetadataSymbol: unique symbol;
|
|
4
|
+
export type ChannelMetadataContent = ChannelMetadata & {
|
|
5
|
+
relays?: string[];
|
|
6
|
+
};
|
|
7
|
+
/** Gets the parsed metadata on a channel creation or channel metadata event */
|
|
8
|
+
export declare function getChannelMetadataContent(channel: NostrEvent): ChannelMetadataContent;
|
|
9
|
+
/** gets the EventPointer for a channel message or metadata event */
|
|
10
|
+
export declare function getChannelPointer(event: NostrEvent): nip19.EventPointer | undefined;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { getOrComputeCachedValue } from "./cache.js";
|
|
2
|
+
export const ChannelMetadataSymbol = Symbol.for("channel-metadata");
|
|
3
|
+
function parseChannelMetadataContent(channel) {
|
|
4
|
+
const metadata = JSON.parse(channel.content);
|
|
5
|
+
if (metadata.name === undefined)
|
|
6
|
+
throw new Error("Missing name");
|
|
7
|
+
if (metadata.about === undefined)
|
|
8
|
+
throw new Error("Missing about");
|
|
9
|
+
if (metadata.picture === undefined)
|
|
10
|
+
throw new Error("Missing picture");
|
|
11
|
+
if (metadata.relays && !Array.isArray(metadata.relays))
|
|
12
|
+
throw new Error("Invalid relays");
|
|
13
|
+
return metadata;
|
|
14
|
+
}
|
|
15
|
+
/** Gets the parsed metadata on a channel creation or channel metadata event */
|
|
16
|
+
export function getChannelMetadataContent(channel) {
|
|
17
|
+
return getOrComputeCachedValue(channel, ChannelMetadataSymbol, () => {
|
|
18
|
+
return parseChannelMetadataContent(channel);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/** gets the EventPointer for a channel message or metadata event */
|
|
22
|
+
export function getChannelPointer(event) {
|
|
23
|
+
const tag = event.tags.find((t) => t[0] === "e" && t[1]);
|
|
24
|
+
if (!tag)
|
|
25
|
+
return undefined;
|
|
26
|
+
return tag[2] ? { id: tag[1], relays: [tag[2]] } : { id: tag[1] };
|
|
27
|
+
}
|
package/dist/helpers/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from "./bolt11.js";
|
|
2
2
|
export * from "./bookmarks.js";
|
|
3
3
|
export * from "./cache.js";
|
|
4
|
+
export * from "./channels.js";
|
|
4
5
|
export * from "./comment.js";
|
|
5
6
|
export * from "./contacts.js";
|
|
6
7
|
export * from "./content.js";
|
|
@@ -28,4 +29,5 @@ export * from "./tags.js";
|
|
|
28
29
|
export * from "./threading.js";
|
|
29
30
|
export * from "./time.js";
|
|
30
31
|
export * from "./url.js";
|
|
32
|
+
export * from "./user-status.js";
|
|
31
33
|
export * from "./zap.js";
|
package/dist/helpers/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from "./bolt11.js";
|
|
2
2
|
export * from "./bookmarks.js";
|
|
3
3
|
export * from "./cache.js";
|
|
4
|
+
export * from "./channels.js";
|
|
4
5
|
export * from "./comment.js";
|
|
5
6
|
export * from "./contacts.js";
|
|
6
7
|
export * from "./content.js";
|
|
@@ -28,4 +29,5 @@ export * from "./tags.js";
|
|
|
28
29
|
export * from "./threading.js";
|
|
29
30
|
export * from "./time.js";
|
|
30
31
|
export * from "./url.js";
|
|
32
|
+
export * from "./user-status.js";
|
|
31
33
|
export * from "./zap.js";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { NostrEvent } from "nostr-tools";
|
|
2
|
+
import { AddressPointer, EventPointer, ProfilePointer } from "nostr-tools/nip19";
|
|
3
|
+
export declare const UserStatusPointerSymbol: unique symbol;
|
|
4
|
+
export type UserStatusPointer = {
|
|
5
|
+
type: "nevent";
|
|
6
|
+
data: EventPointer;
|
|
7
|
+
} | {
|
|
8
|
+
type: "nprofile";
|
|
9
|
+
data: ProfilePointer;
|
|
10
|
+
} | {
|
|
11
|
+
type: "naddr";
|
|
12
|
+
data: AddressPointer;
|
|
13
|
+
} | {
|
|
14
|
+
type: "url";
|
|
15
|
+
data: string;
|
|
16
|
+
};
|
|
17
|
+
/** Gets the {@link UserStatusPointer} for a status event */
|
|
18
|
+
export declare function getUserStatusPointer(status: NostrEvent): UserStatusPointer | null;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getAddressPointerFromATag, getEventPointerFromETag, getOrComputeCachedValue, getProfilePointerFromPTag, } from "applesauce-core/helpers";
|
|
2
|
+
export const UserStatusPointerSymbol = Symbol.for("user-status-pointer");
|
|
3
|
+
function getStatusPointer(status) {
|
|
4
|
+
const pTag = status.tags.find((t) => t[0] === "p" && t[1]);
|
|
5
|
+
if (pTag)
|
|
6
|
+
return { type: "nprofile", data: getProfilePointerFromPTag(pTag) };
|
|
7
|
+
const eTag = status.tags.find((t) => t[0] === "e" && t[1]);
|
|
8
|
+
if (eTag)
|
|
9
|
+
return { type: "nevent", data: getEventPointerFromETag(eTag) };
|
|
10
|
+
const aTag = status.tags.find((t) => t[0] === "a" && t[1]);
|
|
11
|
+
if (aTag)
|
|
12
|
+
return { type: "naddr", data: getAddressPointerFromATag(aTag) };
|
|
13
|
+
const rTag = status.tags.find((t) => t[0] === "r" && t[1]);
|
|
14
|
+
if (rTag)
|
|
15
|
+
return { type: "url", data: rTag[1] };
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
/** Gets the {@link UserStatusPointer} for a status event */
|
|
19
|
+
export function getUserStatusPointer(status) {
|
|
20
|
+
return getOrComputeCachedValue(status, UserStatusPointerSymbol, () => getStatusPointer(status));
|
|
21
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Query } from "applesauce-core";
|
|
2
|
+
import { NostrEvent } from "nostr-tools";
|
|
3
|
+
import { ChannelMetadataContent } from "../helpers/channels.js";
|
|
4
|
+
/** A query that returns a map of hidden messages Map<id, reason> */
|
|
5
|
+
export declare function ChannelHiddenQuery(channel: NostrEvent, authors?: string[]): Query<Map<string, string>>;
|
|
6
|
+
/** A query that returns all messages in a channel */
|
|
7
|
+
export declare function ChannelMessagesQuery(channel: NostrEvent): Query<NostrEvent[]>;
|
|
8
|
+
/** A query that returns the latest parsed metadata */
|
|
9
|
+
export declare function ChannelMetadataQuery(channel: NostrEvent): Query<ChannelMetadataContent | undefined>;
|
|
10
|
+
/** A query that returns a map of muted users Map<pubkey, reason> */
|
|
11
|
+
export declare function ChannelMutedQuery(channel: NostrEvent, authors?: string[]): Query<Map<string, string>>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { safeParse } from "applesauce-core/helpers/json";
|
|
2
|
+
import { kinds } from "nostr-tools";
|
|
3
|
+
import { map } from "rxjs";
|
|
4
|
+
import { getChannelMetadataContent } from "../helpers/channels.js";
|
|
5
|
+
/** A query that returns a map of hidden messages Map<id, reason> */
|
|
6
|
+
export function ChannelHiddenQuery(channel, authors = []) {
|
|
7
|
+
return {
|
|
8
|
+
key: channel.id,
|
|
9
|
+
run: (events) => {
|
|
10
|
+
const hidden = new Map();
|
|
11
|
+
return events
|
|
12
|
+
.stream([{ kinds: [kinds.ChannelHideMessage], "#e": [channel.id], authors: [channel.pubkey, ...authors] }])
|
|
13
|
+
.pipe(map((event) => {
|
|
14
|
+
const reason = safeParse(event.content)?.reason;
|
|
15
|
+
for (const tag of event.tags) {
|
|
16
|
+
if (tag[0] === "e" && tag[1])
|
|
17
|
+
hidden.set(tag[1], reason ?? "");
|
|
18
|
+
}
|
|
19
|
+
return hidden;
|
|
20
|
+
}));
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** A query that returns all messages in a channel */
|
|
25
|
+
export function ChannelMessagesQuery(channel) {
|
|
26
|
+
return {
|
|
27
|
+
key: channel.id,
|
|
28
|
+
run: (events) => events.timeline([{ kinds: [kinds.ChannelMessage], "#e": [channel.id] }]),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** A query that returns the latest parsed metadata */
|
|
32
|
+
export function ChannelMetadataQuery(channel) {
|
|
33
|
+
return {
|
|
34
|
+
key: channel.id,
|
|
35
|
+
run: (events) => {
|
|
36
|
+
const filters = [
|
|
37
|
+
{ ids: [channel.id] },
|
|
38
|
+
{ kinds: [kinds.ChannelMetadata], "#e": [channel.id], authors: [channel.pubkey] },
|
|
39
|
+
];
|
|
40
|
+
let latest = channel;
|
|
41
|
+
return events.stream(filters).pipe(map((event) => {
|
|
42
|
+
try {
|
|
43
|
+
if (event.pubkey === latest.pubkey && event.created_at > latest.created_at) {
|
|
44
|
+
latest = event;
|
|
45
|
+
}
|
|
46
|
+
return getChannelMetadataContent(latest);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}));
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** A query that returns a map of muted users Map<pubkey, reason> */
|
|
56
|
+
export function ChannelMutedQuery(channel, authors = []) {
|
|
57
|
+
return {
|
|
58
|
+
key: channel.id + authors.join(","),
|
|
59
|
+
run: (events) => {
|
|
60
|
+
const muted = new Map();
|
|
61
|
+
return events
|
|
62
|
+
.stream([{ kinds: [kinds.ChannelMuteUser], "#e": [channel.id], authors: [channel.pubkey, ...authors] }])
|
|
63
|
+
.pipe(map((event) => {
|
|
64
|
+
const reason = safeParse(event.content)?.reason;
|
|
65
|
+
for (const tag of event.tags) {
|
|
66
|
+
if (tag[0] === "p" && tag[1])
|
|
67
|
+
muted.set(tag[1], reason ?? "");
|
|
68
|
+
}
|
|
69
|
+
return muted;
|
|
70
|
+
}));
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
package/dist/queries/index.d.ts
CHANGED
package/dist/queries/index.js
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NostrEvent } from "nostr-tools";
|
|
2
|
+
import { UserStatusPointer } from "../helpers/user-status.js";
|
|
3
|
+
import { Query } from "../query-store/index.js";
|
|
4
|
+
export type UserStatus = UserStatusPointer & {
|
|
5
|
+
event: NostrEvent;
|
|
6
|
+
content: string;
|
|
7
|
+
};
|
|
8
|
+
/** Creates a Query that returns a parsed {@link UserStatus} for a certain type */
|
|
9
|
+
export declare function UserStatusQuery(pubkey: string, type?: string): Query<UserStatus | undefined | null>;
|
|
10
|
+
/** Creates a Query that returns a directory of parsed {@link UserStatus} for a pubkey */
|
|
11
|
+
export declare function UserStatusesQuery(pubkey: string): Query<Record<string, UserStatus>>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { kinds } from "nostr-tools";
|
|
2
|
+
import { map } from "rxjs";
|
|
3
|
+
import { getUserStatusPointer } from "../helpers/user-status.js";
|
|
4
|
+
import { getReplaceableIdentifier } from "../helpers/event.js";
|
|
5
|
+
/** Creates a Query that returns a parsed {@link UserStatus} for a certain type */
|
|
6
|
+
export function UserStatusQuery(pubkey, type = "general") {
|
|
7
|
+
return {
|
|
8
|
+
key: pubkey,
|
|
9
|
+
run: (events) => events.replaceable(kinds.UserStatuses, pubkey, type).pipe(map((event) => {
|
|
10
|
+
if (!event)
|
|
11
|
+
return undefined;
|
|
12
|
+
const pointer = getUserStatusPointer(event);
|
|
13
|
+
if (!pointer)
|
|
14
|
+
return null;
|
|
15
|
+
return {
|
|
16
|
+
...pointer,
|
|
17
|
+
event,
|
|
18
|
+
content: event.content,
|
|
19
|
+
};
|
|
20
|
+
})),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** Creates a Query that returns a directory of parsed {@link UserStatus} for a pubkey */
|
|
24
|
+
export function UserStatusesQuery(pubkey) {
|
|
25
|
+
return {
|
|
26
|
+
key: pubkey,
|
|
27
|
+
run: (events) => events.timeline([{ kinds: [kinds.UserStatuses], authors: [pubkey] }]).pipe(map((events) => {
|
|
28
|
+
return events.reduce((dir, event) => {
|
|
29
|
+
try {
|
|
30
|
+
const d = getReplaceableIdentifier(event);
|
|
31
|
+
return { ...dir, [d]: { event, ...getUserStatusPointer(event), content: event.content } };
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
return dir;
|
|
35
|
+
}
|
|
36
|
+
}, {});
|
|
37
|
+
})),
|
|
38
|
+
};
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "applesauce-core",
|
|
3
|
-
"version": "0.0.0-next-
|
|
3
|
+
"version": "0.0.0-next-20250128154531",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"author": "hzrd149",
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"files": [
|
|
14
|
-
"dist"
|
|
14
|
+
"dist",
|
|
15
|
+
"applesauce"
|
|
15
16
|
],
|
|
16
17
|
"exports": {
|
|
17
18
|
".": {
|