diff --git a/packages/app/config/iris.json b/packages/app/config/iris.json
index 7f364cb6..fb8029de 100644
--- a/packages/app/config/iris.json
+++ b/packages/app/config/iris.json
@@ -45,8 +45,7 @@
"wss://relay.damus.io/": { "read": true, "write": true }
},
"chatChannels": [
- { "type": "telegram", "value": "https://t.me/irismessenger" },
- { "type": "nip28", "value": "23286a4602ada10cc10200553bff62a110e8dc0eacddf73277395a89ddf26a09" }
+ { "type": "telegram", "value": "https://t.me/irismessenger" }
],
"alby": {
"clientId": "5rYcHDrlDb",
diff --git a/packages/app/custom.d.ts b/packages/app/custom.d.ts
index 80de3eac..4c95121c 100644
--- a/packages/app/custom.d.ts
+++ b/packages/app/custom.d.ts
@@ -101,7 +101,7 @@ declare const CONFIG: {
// public chat channels for site
chatChannels?: Array<{
- type: "nip28" | "telegram";
+ type: "telegram";
value: string;
}>;
};
diff --git a/packages/app/src/Hooks/useEmptyChatSystem.tsx b/packages/app/src/Hooks/useEmptyChatSystem.tsx
deleted file mode 100644
index dd7294da..00000000
--- a/packages/app/src/Hooks/useEmptyChatSystem.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { unwrap } from "@snort/shared";
-import { decodeTLV, EventKind, NostrPrefix, RequestBuilder, TLVEntryType } from "@snort/system";
-import { useRequestBuilder } from "@snort/system-react";
-import { useMemo } from "react";
-
-import { createEmptyChatObject } from "@/chat";
-
-export function useEmptyChatSystem(id?: string) {
- const sub = useMemo(() => {
- if (id?.startsWith(NostrPrefix.Chat28)) {
- const cx = unwrap(decodeTLV(id).find(a => a.type === TLVEntryType.Special)).value as string;
- const rb = new RequestBuilder(`nip28:${id}`);
- rb.withFilter().ids([cx]).kinds([EventKind.PublicChatChannel, EventKind.PublicChatMetadata]);
- rb.withFilter()
- .tag("e", [cx])
- .kinds([EventKind.PublicChatChannel, EventKind.PublicChatMessage, EventKind.PublicChatMetadata]);
-
- return rb;
- } else {
- return new RequestBuilder(id ?? "");
- }
- }, [id]);
-
- const data = useRequestBuilder(sub);
- return useMemo(() => {
- if (!id) return;
- return createEmptyChatObject(id, data);
- }, [id, data.length]);
-}
diff --git a/packages/app/src/Pages/Donate/DonatePage.tsx b/packages/app/src/Pages/Donate/DonatePage.tsx
index a903c18d..e242ab76 100644
--- a/packages/app/src/Pages/Donate/DonatePage.tsx
+++ b/packages/app/src/Pages/Donate/DonatePage.tsx
@@ -4,7 +4,6 @@ import { FormattedMessage } from "react-intl";
import { Link, useNavigate } from "react-router-dom";
import Telegram from "@/assets/img/telegram.svg";
-import { Nip28ChatSystem } from "@/chat/nip28";
import AsyncButton from "@/Components/Button/AsyncButton";
import Copy from "@/Components/Copy/Copy";
import ZapButton from "@/Components/Event/ZapButton";
@@ -105,18 +104,6 @@ const DonatePage = () => {
);
}
- case "nip28": {
- return (
- {
- const id = Nip28ChatSystem.chatId(a.value);
- navigate(`/messages/${id}`);
- }}>
-
-
-
- );
- }
}
})}
diff --git a/packages/app/src/Pages/Messages/NewChatWindow.tsx b/packages/app/src/Pages/Messages/NewChatWindow.tsx
index c3d1e444..a4625baa 100644
--- a/packages/app/src/Pages/Messages/NewChatWindow.tsx
+++ b/packages/app/src/Pages/Messages/NewChatWindow.tsx
@@ -1,21 +1,15 @@
-import { decodeTLV, EventKind, NostrPrefix } from "@snort/system";
import { useUserSearch } from "@snort/system-react";
-import React, { useEffect, useState } from "react";
+import { useEffect, useState } from "react";
import { FormattedMessage } from "react-intl";
import { useNavigate } from "react-router-dom";
import { ChatType, createChatLink } from "@/chat";
-import { Nip28ChatSystem } from "@/chat/nip28";
import Icon from "@/Components/Icons/Icon";
import Modal from "@/Components/Modal/Modal";
import ProfileImage from "@/Components/User/ProfileImage";
import ProfilePreview from "@/Components/User/ProfilePreview";
-import useEventPublisher from "@/Hooks/useEventPublisher";
import useFollowsControls from "@/Hooks/useFollowControls";
-import useLogin from "@/Hooks/useLogin";
-import Nip28ChatProfile from "@/Pages/Messages/Nip28ChatProfile";
import { appendDedupe, debounce } from "@/Utils";
-import { LoginSession, LoginStore } from "@/Utils/Login";
export default function NewChatWindow() {
const [show, setShow] = useState(false);
@@ -24,8 +18,6 @@ export default function NewChatWindow() {
const [term, setSearchTerm] = useState("");
const navigate = useNavigate();
const search = useUserSearch();
- const login = useLogin();
- const { system, publisher } = useEventPublisher();
const { followList } = useFollowsControls();
useEffect(() => {
@@ -115,32 +107,6 @@ export default function NewChatWindow() {
/>
);
})}
- {results.length === 1 && (
- {
- setShow(false);
- const chats = appendDedupe(login.extraChats, [Nip28ChatSystem.chatId(id)]);
- LoginStore.updateSession({
- ...login,
- extraChats: chats,
- } as LoginSession);
- const evList = await publisher?.generic(eb => {
- eb.kind(EventKind.PublicChatsList);
- chats.forEach(c => {
- if (c.startsWith(NostrPrefix.Chat28)) {
- eb.tag(["e", decodeTLV(c)[0].value as string]);
- }
- });
- return eb;
- });
- if (evList) {
- await system.BroadcastEvent(evList);
- }
- navigate(createChatLink(ChatType.PublicGroupChat, id));
- }}
- />
- )}
diff --git a/packages/app/src/Pages/Messages/Nip28ChatProfile.tsx b/packages/app/src/Pages/Messages/Nip28ChatProfile.tsx
deleted file mode 100644
index c0a2cda2..00000000
--- a/packages/app/src/Pages/Messages/Nip28ChatProfile.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { NostrLink, UserMetadata } from "@snort/system";
-import { useEventFeed } from "@snort/system-react";
-import React from "react";
-
-import ProfilePreview from "@/Components/User/ProfilePreview";
-
-export default function Nip28ChatProfile({ id, onClick }: { id: string; onClick: (id: string) => void }) {
- const channel = useEventFeed(new NostrLink(CONFIG.eventLinkPrefix, id, 40));
- if (channel) {
- const meta = JSON.parse(channel.content) as UserMetadata;
- return (
- >}
- onClick={() => onClick(id)}
- />
- );
- }
-}
diff --git a/packages/app/src/chat/index.ts b/packages/app/src/chat/index.ts
index 3700a6f4..8e8932d0 100644
--- a/packages/app/src/chat/index.ts
+++ b/packages/app/src/chat/index.ts
@@ -15,7 +15,6 @@ import {
import { useRequestBuilder } from "@snort/system-react";
import { useEffect, useMemo } from "react";
-import { useEmptyChatSystem } from "@/Hooks/useEmptyChatSystem";
import useEventPublisher from "@/Hooks/useEventPublisher";
import useLogin from "@/Hooks/useLogin";
import useModeration from "@/Hooks/useModeration";
@@ -23,7 +22,6 @@ import { findTag } from "@/Utils";
import { LoginSession } from "@/Utils/Login";
import { Nip17Chats, Nip17ChatSystem } from "./nip17";
-import { Nip28Chats, Nip28ChatSystem } from "./nip28";
export enum ChatType {
PublicGroupChat = 2,
@@ -135,20 +133,14 @@ export function createChatLink(type: ChatType, ...params: Array) {
),
)}`;
}
- case ChatType.PublicGroupChat: {
- return `/messages/${Nip28ChatSystem.chatId(params[0])}`;
- }
}
throw new Error("Unknown chat type");
}
-export function createEmptyChatObject(id: string, messages?: Array) {
+export function createEmptyChatObject(id: string) {
if (id.startsWith(NostrPrefix.Chat17)) {
return Nip17ChatSystem.createChatObj(id, []);
}
- if (id.startsWith(NostrPrefix.Chat28)) {
- return Nip28ChatSystem.createChatObj(id, messages ?? []);
- }
throw new Error("Cant create new empty chat, unknown id");
}
@@ -179,10 +171,9 @@ export function useChatSystem(chat: ChatSystem) {
}
export function useChatSystems() {
- const nip28 = useChatSystem(Nip28Chats);
const nip17 = useChatSystem(Nip17Chats);
- return [...nip28, ...nip17];
+ return nip17;
}
export function useChat(id: string) {
@@ -190,12 +181,8 @@ export function useChat(id: string) {
if (id.startsWith(NostrPrefix.Chat17)) {
return Nip17Chats;
}
- if (id.startsWith(NostrPrefix.Chat28)) {
- return Nip28Chats;
- }
throw new Error("Unsupported chat system");
};
const ret = useChatSystem(getStore()).find(a => a.id === id);
- const emptyChat = useEmptyChatSystem(ret === undefined ? id : undefined);
- return ret ?? emptyChat;
+ return ret;
}
diff --git a/packages/app/src/chat/nip28.ts b/packages/app/src/chat/nip28.ts
deleted file mode 100644
index 88f19137..00000000
--- a/packages/app/src/chat/nip28.ts
+++ /dev/null
@@ -1,144 +0,0 @@
-import { unwrap } from "@snort/shared";
-import {
- decodeTLV,
- encodeTLVEntries,
- EventKind,
- NostrEvent,
- NostrPrefix,
- RequestBuilder,
- SystemInterface,
- TaggedNostrEvent,
- TLVEntryType,
- UserMetadata,
-} from "@snort/system";
-
-import { Chat, ChatParticipant, ChatSystem, ChatType, lastReadInChat } from "@/chat";
-import { findTag } from "@/Utils";
-import { LoginSession } from "@/Utils/Login";
-
-export class Nip28ChatSystem implements ChatSystem {
- readonly ChannelKinds = [
- EventKind.PublicChatChannel,
- EventKind.PublicChatMessage,
- EventKind.PublicChatMetadata,
- EventKind.PublicChatMuteMessage,
- EventKind.PublicChatMuteUser,
- ];
-
- subscription(session: LoginSession): RequestBuilder {
- const chats = (session.extraChats ?? []).filter(a => a.startsWith(NostrPrefix.Chat28));
- const chatId = (v: string) => unwrap(decodeTLV(v).find(a => a.type === TLVEntryType.Special)).value as string;
-
- const rb = new RequestBuilder(`nip28:${session.id}`);
- if (chats.length > 0) {
- rb.withFilter()
- .ids(chats.map(v => chatId(v)))
- .kinds([EventKind.PublicChatChannel, EventKind.PublicChatMetadata]);
- for (const c of chats) {
- const id = chatId(c);
- rb.withFilter().tag("e", [id]).kinds(this.ChannelKinds);
- }
- }
- return rb;
- }
-
- processEvents(): Promise {
- // nothing to do
- return Promise.resolve();
- }
-
- listChats(pk: string, evs: Array): Chat[] {
- const chats = this.#chatChannels(evs);
- const ret = Object.entries(chats).map(([k, v]) => {
- return Nip28ChatSystem.createChatObj(Nip28ChatSystem.chatId(k), v);
- });
- return ret;
- }
-
- static chatId(id: string) {
- return encodeTLVEntries(NostrPrefix.Chat28, {
- type: TLVEntryType.Special,
- value: id,
- length: id.length,
- });
- }
-
- static createChatObj(id: string, messages: Array) {
- const last = lastReadInChat(id);
- const participants = decodeTLV(id)
- .filter(v => v.type === TLVEntryType.Special)
- .map(
- v =>
- ({
- type: "generic",
- id: v.value as string,
- profile: this.#chatProfileFromMessages(messages),
- }) as ChatParticipant,
- );
- return {
- type: ChatType.PublicGroupChat,
- id,
- unread: messages.reduce((acc, v) => (v.created_at > last ? acc++ : acc), 0),
- lastMessage: messages.reduce((acc, v) => (v.created_at > acc ? v.created_at : acc), 0),
- participants,
- messages: messages
- .filter(a => a.kind === EventKind.PublicChatMessage)
- .map(m => ({
- id: m.id,
- created_at: m.created_at,
- from: m.pubkey,
- tags: m.tags,
- content: m.content,
- needsDecryption: false,
- })),
- createMessage: async (msg, pub) => {
- return [
- await pub.generic(eb => {
- return eb.kind(EventKind.PublicChatMessage).content(msg).tag(["e", participants[0].id, "", "root"]);
- }),
- ];
- },
- sendMessage: (ev, system: SystemInterface) => {
- ev.forEach(a => system.BroadcastEvent(a));
- },
- } as Chat;
- }
-
- static #chatProfileFromMessages(messages: Array) {
- const chatDefs = messages.filter(
- a => a.kind === EventKind.PublicChatChannel || a.kind === EventKind.PublicChatMetadata,
- );
- const chatDef =
- chatDefs.length > 0
- ? chatDefs.reduce((acc, v) => (acc.created_at > v.created_at ? acc : v), chatDefs[0])
- : undefined;
- return chatDef ? (JSON.parse(chatDef.content) as UserMetadata) : undefined;
- }
-
- #chatChannels(evs: Array) {
- const chats = evs.reduce(
- (acc, v) => {
- const k = this.#chatId(v);
- if (k) {
- acc[k] ??= [];
- acc[k].push(v);
- }
- return acc;
- },
- {} as Record>,
- );
- return chats;
- }
-
- #chatId(ev: NostrEvent) {
- if (ev.kind === EventKind.PublicChatChannel) {
- return ev.id;
- } else if (ev.kind === EventKind.PublicChatMetadata) {
- return findTag(ev, "e");
- } else if (this.ChannelKinds.includes(ev.kind)) {
- return ev.tags.find(a => a[0] === "e" && a[3] === "root")?.[1];
- }
- }
-}
-
-export const Nip28Chats = new Nip28ChatSystem();
diff --git a/packages/app/src/chat/nip29.ts b/packages/app/src/chat/nip29.ts
deleted file mode 100644
index 6435601c..00000000
--- a/packages/app/src/chat/nip29.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import { dedupe, ExternalStore, FeedCache, removeUndefined } from "@snort/shared";
-import { EventKind, NostrEvent, RequestBuilder, SystemInterface, TaggedNostrEvent } from "@snort/system";
-
-import { Chat, ChatSystem, ChatType, lastReadInChat } from "@/chat";
-import { LoginSession } from "@/Utils/Login";
-
-export class Nip29ChatSystem extends ExternalStore> implements ChatSystem {
- readonly #cache: FeedCache;
-
- constructor(cache: FeedCache) {
- super();
- this.#cache = cache;
- }
-
- processEvents(): Promise {
- return Promise.resolve();
- }
-
- takeSnapshot(): Chat[] {
- return this.listChats();
- }
-
- subscription(session: LoginSession) {
- const id = session.publicKey;
- if (!id) return;
- const gs = id.split("/", 2);
- const rb = new RequestBuilder(`nip29:${id}`);
- const last = this.listChats().find(a => a.id === id)?.lastMessage;
- rb.withFilter()
- .relay(`wss://${gs[0]}`)
- .kinds([EventKind.SimpleChatMessage])
- .tag("g", [`/${gs[1]}`])
- .since(last);
- rb.withFilter()
- .relay(`wss://${gs[0]}`)
- .kinds([EventKind.SimpleChatMetadata])
- .tag("d", [`/${gs[1]}`]);
- return rb;
- }
-
- async onEvent(evs: readonly TaggedNostrEvent[]) {
- const msg = evs.filter(a => a.kind === EventKind.SimpleChatMessage && a.tags.some(b => b[0] === "g"));
- if (msg.length > 0) {
- await this.#cache.bulkSet(msg);
- this.notifyChange();
- }
- }
-
- listChats(): Chat[] {
- const allMessages = this.#nip29Chats();
- const groups = dedupe(
- removeUndefined(allMessages.map(a => a.tags.find(b => b[0] === "g"))).map(a => `${a[2]}${a[1]}`),
- );
- return groups.map(g => {
- const [relay, channel] = g.split("/", 2);
- const messages = allMessages.filter(
- a => `${a.tags.find(b => b[0] === "g")?.[2]}${a.tags.find(b => b[0] === "g")?.[1]}` === g,
- );
- const lastRead = lastReadInChat(g);
- return {
- type: ChatType.PublicGroupChat,
- id: g,
- title: `${relay}/${channel}`,
- unread: messages.reduce((acc, v) => (v.created_at > lastRead ? acc++ : acc), 0),
- lastMessage: messages.reduce((acc, v) => (v.created_at > acc ? v.created_at : acc), 0),
- messages: messages.map(m => ({
- id: m.id,
- created_at: m.created_at,
- from: m.pubkey,
- tags: m.tags,
- needsDecryption: false,
- content: m.content,
- decrypt: async () => {
- return m.content;
- },
- })),
- participants: [
- {
- type: "generic",
- id: "",
- profile: {
- name: `${relay}/${channel}`,
- },
- },
- ],
- createMessage: async (msg, pub) => {
- return [
- await pub.generic(eb => {
- return eb
- .kind(EventKind.SimpleChatMessage)
- .tag(["g", `/${channel}`, relay])
- .content(msg);
- }),
- ];
- },
- sendMessage: async (ev, system: SystemInterface) => {
- ev.forEach(async a => {
- system.HandleEvent("*", { ...a, relays: [] });
- await system.WriteOnceToRelay(`wss://${relay}`, a);
- });
- },
- } as Chat;
- });
- }
-
- #nip29Chats() {
- return this.#cache.snapshot().filter(a => a.kind === EventKind.SimpleChatMessage);
- }
-}
diff --git a/packages/system/src/links.ts b/packages/system/src/links.ts
index 0c8a71d4..2afa922e 100644
--- a/packages/system/src/links.ts
+++ b/packages/system/src/links.ts
@@ -14,7 +14,6 @@ export enum NostrPrefix {
Address = "naddr",
Req = "nreq",
Chat17 = "nchat17",
- Chat28 = "nchat28",
}
export enum TLVEntryType {