diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 8e8adf9e..daaa5ee2 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,6 +1,7 @@
{
"recommendations": [
"arcanis.vscode-zipfs",
- "dbaeumer.vscode-eslint"
+ "dbaeumer.vscode-eslint",
+ "esbenp.prettier-vscode"
]
}
diff --git a/.yarn/sdks/eslint/package.json b/.yarn/sdks/eslint/package.json
index 06e74e37..ff446fd6 100644
--- a/.yarn/sdks/eslint/package.json
+++ b/.yarn/sdks/eslint/package.json
@@ -1,6 +1,6 @@
{
"name": "eslint",
- "version": "8.44.0-sdk",
+ "version": "8.48.0-sdk",
"main": "./lib/api.js",
"type": "commonjs"
}
diff --git a/.yarn/sdks/prettier/index.js b/.yarn/sdks/prettier/index.js
new file mode 100755
index 00000000..8758e367
--- /dev/null
+++ b/.yarn/sdks/prettier/index.js
@@ -0,0 +1,20 @@
+#!/usr/bin/env node
+
+const {existsSync} = require(`fs`);
+const {createRequire} = require(`module`);
+const {resolve} = require(`path`);
+
+const relPnpApiPath = "../../../.pnp.cjs";
+
+const absPnpApiPath = resolve(__dirname, relPnpApiPath);
+const absRequire = createRequire(absPnpApiPath);
+
+if (existsSync(absPnpApiPath)) {
+ if (!process.versions.pnp) {
+ // Setup the environment to be able to require prettier
+ require(absPnpApiPath).setup();
+ }
+}
+
+// Defer to the real prettier your application uses
+module.exports = absRequire(`prettier`);
diff --git a/.yarn/sdks/prettier/package.json b/.yarn/sdks/prettier/package.json
new file mode 100644
index 00000000..c102fa29
--- /dev/null
+++ b/.yarn/sdks/prettier/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "prettier",
+ "version": "3.0.3-sdk",
+ "main": "./index.js",
+ "type": "commonjs"
+}
diff --git a/.yarn/sdks/typescript/package.json b/.yarn/sdks/typescript/package.json
index 7503a11c..0bfa4eb2 100644
--- a/.yarn/sdks/typescript/package.json
+++ b/.yarn/sdks/typescript/package.json
@@ -1,6 +1,6 @@
{
"name": "typescript",
- "version": "5.1.6-sdk",
+ "version": "5.2.2-sdk",
"main": "./lib/typescript.js",
"type": "commonjs"
}
diff --git a/package.json b/package.json
index 71e0208d..0d26662c 100644
--- a/package.json
+++ b/package.json
@@ -9,11 +9,6 @@
"test": "yarn workspace @snort/shared build && yarn workspace @snort/system build && yarn workspace @snort/app test && yarn workspace @snort/system test",
"pre:commit": "yarn workspace @snort/app intl-extract && yarn workspace @snort/app intl-compile && yarn prettier --write ."
},
- "devDependencies": {
- "@cloudflare/workers-types": "^4.20230307.0",
- "@tauri-apps/cli": "^1.2.3",
- "prettier": "^3.0.0"
- },
"prettier": {
"printWidth": 120,
"bracketSameLine": true,
@@ -21,7 +16,10 @@
},
"packageManager": "yarn@3.6.3",
"dependencies": {
+ "@cloudflare/workers-types": "^4.20230307.0",
+ "@tauri-apps/cli": "^1.2.3",
"eslint": "^8.48.0",
+ "prettier": "^3.0.3",
"typescript": "^5.2.2"
}
}
diff --git a/packages/app/src/Element/ChatParticipant.tsx b/packages/app/src/Element/ChatParticipant.tsx
new file mode 100644
index 00000000..2ccaca09
--- /dev/null
+++ b/packages/app/src/Element/ChatParticipant.tsx
@@ -0,0 +1,12 @@
+import { ChatParticipant } from "chat";
+import NoteToSelf from "./NoteToSelf";
+import ProfileImage from "./ProfileImage";
+import useLogin from "Hooks/useLogin";
+
+export function ChatParticipantProfile({ participant }: { participant: ChatParticipant }) {
+ const { publicKey } = useLogin(s => ({ publicKey: s.publicKey }));
+ if (participant.id === publicKey) {
+ return ;
+ }
+ return ;
+}
diff --git a/packages/app/src/Element/DmWindow.tsx b/packages/app/src/Element/DmWindow.tsx
index ef4715d2..2620500b 100644
--- a/packages/app/src/Element/DmWindow.tsx
+++ b/packages/app/src/Element/DmWindow.tsx
@@ -3,33 +3,19 @@ import { useMemo } from "react";
import ProfileImage from "Element/ProfileImage";
import DM from "Element/DM";
-import NoteToSelf from "Element/NoteToSelf";
import useLogin from "Hooks/useLogin";
import WriteMessage from "Element/WriteMessage";
-import { Chat, ChatParticipant, createEmptyChatObject, useChatSystem } from "chat";
+import { Chat, createEmptyChatObject, useChatSystem } from "chat";
import { FormattedMessage } from "react-intl";
+import { ChatParticipantProfile } from "./ChatParticipant";
export default function DmWindow({ id }: { id: string }) {
- const { publicKey } = useLogin(s => ({ publicKey: s.publicKey }));
const dms = useChatSystem();
const chat = dms.find(a => a.id === id) ?? createEmptyChatObject(id);
- function participant(p: ChatParticipant) {
- if (p.id === publicKey) {
- return ;
- }
- if (p.type === "pubkey") {
- return ;
- }
- if (p?.profile) {
- return ;
- }
- return ;
- }
-
function sender() {
if (chat.participants.length === 1) {
- return participant(chat.participants[0]);
+ return ;
} else {
return (
diff --git a/packages/app/src/Element/ProfilePreview.tsx b/packages/app/src/Element/ProfilePreview.tsx
index 1e2b31e4..dffd1da6 100644
--- a/packages/app/src/Element/ProfilePreview.tsx
+++ b/packages/app/src/Element/ProfilePreview.tsx
@@ -1,6 +1,6 @@
import "./ProfilePreview.css";
import { ReactNode } from "react";
-import { HexKey } from "@snort/system";
+import { HexKey, UserMetadata } from "@snort/system";
import { useUserProfile } from "@snort/system-react";
import { useInView } from "react-intersection-observer";
@@ -13,6 +13,7 @@ export interface ProfilePreviewProps {
about?: boolean;
linkToProfile?: boolean;
};
+ profile?: UserMetadata;
actions?: ReactNode;
className?: string;
onClick?: (e: React.MouseEvent
) => void;
@@ -41,6 +42,7 @@ export default function ProfilePreview(props: ProfilePreviewProps) {
<>
{user?.about} : undefined}
/>
diff --git a/packages/app/src/Feed/LoginFeed.ts b/packages/app/src/Feed/LoginFeed.ts
index 6de39538..1698a764 100644
--- a/packages/app/src/Feed/LoginFeed.ts
+++ b/packages/app/src/Feed/LoginFeed.ts
@@ -25,7 +25,7 @@ import { SubscriptionEvent } from "Subscription";
import useRelaysFeedFollows from "./RelaysFeedFollows";
import { FollowsFeed, GiftsCache, Notifications, UserRelays } from "Cache";
import { System } from "index";
-import { Nip4Chats } from "chat";
+import { Nip28Chats, Nip4Chats } from "chat";
import { useRefreshFeedCache } from "Hooks/useRefreshFeedcache";
/**
@@ -42,7 +42,7 @@ export default function useLoginFeed() {
useRefreshFeedCache(GiftsCache, true);
const subLogin = useMemo(() => {
- if (!pubKey) return null;
+ if (!login || !pubKey) return null;
const b = new RequestBuilder(`login:${pubKey.slice(0, 12)}`);
b.withOptions({
@@ -57,10 +57,16 @@ export default function useLoginFeed() {
.tag("p", [pubKey])
.limit(1);
- b.add(Nip4Chats.subscription(pubKey));
-
+ const n4Sub = Nip4Chats.subscription(login);
+ if (n4Sub) {
+ b.add(n4Sub);
+ }
+ const n28Sub = Nip28Chats.subscription(login);
+ if (n28Sub) {
+ b.add(n28Sub);
+ }
return b;
- }, [pubKey]);
+ }, [login]);
const subLists = useMemo(() => {
if (!pubKey) return null;
@@ -94,6 +100,7 @@ export default function useLoginFeed() {
}
Nip4Chats.onEvent(loginFeed.data);
+ Nip28Chats.onEvent(loginFeed.data);
const subs = loginFeed.data.filter(
a => a.kind === EventKind.SnortSubscriptions && a.pubkey === bech32ToHex(SnortPubKey),
diff --git a/packages/app/src/Login/LoginSession.ts b/packages/app/src/Login/LoginSession.ts
index 3550d375..12df2aa0 100644
--- a/packages/app/src/Login/LoginSession.ts
+++ b/packages/app/src/Login/LoginSession.ts
@@ -123,4 +123,9 @@ export interface LoginSession {
* Snort application data
*/
appData: Newest;
+
+ /**
+ * A list of chats which we have joined (NIP-28/NIP-29)
+ */
+ extraChats: Array;
}
diff --git a/packages/app/src/Login/MultiAccountStore.ts b/packages/app/src/Login/MultiAccountStore.ts
index 66015c98..258c6119 100644
--- a/packages/app/src/Login/MultiAccountStore.ts
+++ b/packages/app/src/Login/MultiAccountStore.ts
@@ -52,6 +52,7 @@ const LoggedOut = {
},
timestamp: 0,
},
+ extraChats: [],
} as LoginSession;
export class MultiAccountStore extends ExternalStore {
@@ -79,10 +80,11 @@ export class MultiAccountStore extends ExternalStore {
}
v.appData ??= {
item: {
- mutedWords: []
+ mutedWords: [],
},
- timestamp: 0
- }
+ timestamp: 0,
+ };
+ v.extraChats ??= [];
}
}
diff --git a/packages/app/src/Pages/MessagesPage.tsx b/packages/app/src/Pages/MessagesPage.tsx
index 963fd030..2d702640 100644
--- a/packages/app/src/Pages/MessagesPage.tsx
+++ b/packages/app/src/Pages/MessagesPage.tsx
@@ -3,7 +3,7 @@ import "./MessagesPage.css";
import React, { useEffect, useMemo, useState } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { useNavigate, useParams } from "react-router-dom";
-import { TLVEntryType, decodeTLV } from "@snort/system";
+import { NostrLink, NostrPrefix, TLVEntryType, UserMetadata, decodeTLV } from "@snort/system";
import { useUserProfile, useUserSearch } from "@snort/system-react";
import UnreadCount from "Element/UnreadCount";
@@ -21,6 +21,10 @@ import Text from "Element/Text";
import { Chat, ChatType, createChatLink, useChatSystem } from "chat";
import Modal from "Element/Modal";
import ProfilePreview from "Element/ProfilePreview";
+import { useEventFeed } from "Feed/EventFeed";
+import { LoginSession, LoginStore } from "Login";
+import { Nip28ChatSystem } from "chat/nip28";
+import { ChatParticipantProfile } from "Element/ChatParticipant";
const TwoCol = 768;
const ThreeCol = 1500;
@@ -57,18 +61,12 @@ export default function MessagesPage() {
function conversationIdent(cx: Chat) {
if (cx.participants.length === 1) {
- const p = cx.participants[0];
-
- if (p.type === "pubkey") {
- return ;
- } else {
- return ;
- }
+ return ;
} else {
return (
{cx.participants.map(v => (
-
+
))}
{cx.title ??
}
@@ -168,17 +166,17 @@ function ProfileDmActions({ id }: { id: string }) {
function NewChatWindow() {
const [show, setShow] = useState(false);
- const [newChat, setNewChat] = useState([]);
- const [results, setResults] = useState([]);
+ const [newChat, setNewChat] = useState>([]);
+ const [results, setResults] = useState>([]);
const [term, setSearchTerm] = useState("");
const navigate = useNavigate();
const search = useUserSearch();
- const { follows } = useLogin();
+ const login = useLogin();
useEffect(() => {
setNewChat([]);
setSearchTerm("");
- setResults(follows.item);
+ setResults(login.follows.item);
}, [show]);
useEffect(() => {
@@ -186,7 +184,7 @@ function NewChatWindow() {
if (term) {
search(term).then(setResults);
} else {
- setResults(follows.item);
+ setResults(login.follows.item);
}
});
}, [term]);
@@ -259,6 +257,19 @@ function NewChatWindow() {
/>
);
})}
+ {results.length === 1 && (
+ {
+ setShow(false);
+ LoginStore.updateSession({
+ ...login,
+ extraChats: appendDedupe(login.extraChats, [Nip28ChatSystem.chatId(id)]),
+ } as LoginSession);
+ navigate(createChatLink(ChatType.PublicGroupChat, id));
+ }}
+ />
+ )}
@@ -267,3 +278,19 @@ function NewChatWindow() {
>
);
}
+
+export function Nip28ChatProfile({ id, onClick }: { id: string; onClick: (id: string) => void }) {
+ const channel = useEventFeed(new NostrLink(NostrPrefix.Event, id, 40));
+ if (channel?.data) {
+ const meta = JSON.parse(channel.data.content) as UserMetadata;
+ return (
+ >}
+ onClick={() => onClick(id)}
+ />
+ );
+ }
+}
diff --git a/packages/app/src/chat/index.ts b/packages/app/src/chat/index.ts
index ada8472e..9f35d109 100644
--- a/packages/app/src/chat/index.ts
+++ b/packages/app/src/chat/index.ts
@@ -20,6 +20,8 @@ import { Nip29ChatSystem } from "./nip29";
import useModeration from "Hooks/useModeration";
import useLogin from "Hooks/useLogin";
import { Nip24ChatSystem } from "./nip24";
+import { LoginSession } from "Login";
+import { Nip28ChatSystem } from "./nip28";
export enum ChatType {
DirectMessage = 1,
@@ -60,7 +62,7 @@ export interface ChatSystem {
/**
* Create a request for this system to get updates
*/
- subscription(id: string): RequestBuilder | undefined;
+ subscription(session: LoginSession): RequestBuilder | undefined;
onEvent(evs: readonly TaggedNostrEvent[]): Promise | void;
listChats(pk: string): Array;
@@ -69,6 +71,7 @@ export interface ChatSystem {
export const Nip4Chats = new Nip4ChatSystem(Chats);
export const Nip29Chats = new Nip29ChatSystem(Chats);
export const Nip24Chats = new Nip24ChatSystem(GiftsCache);
+export const Nip28Chats = new Nip28ChatSystem(Chats);
/**
* Extract the P tag of the event
@@ -143,17 +146,23 @@ 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) {
- if (id.startsWith("chat4")) {
+ if (id.startsWith("chat41")) {
return Nip4ChatSystem.createChatObj(id, []);
}
- if (id.startsWith("chat24")) {
+ if (id.startsWith("chat241")) {
return Nip24ChatSystem.createChatObj(id, []);
}
+ if (id.startsWith("chat281")) {
+ return Nip28ChatSystem.createChatObj(id, []);
+ }
throw new Error("Cant create new empty chat, unknown id");
}
@@ -180,10 +189,18 @@ export function useNip24Chat() {
);
}
+export function useNip28Chat() {
+ return useSyncExternalStore(
+ c => Nip28Chats.hook(c),
+ () => Nip28Chats.snapshot(),
+ );
+}
+
export function useChatSystem() {
const nip4 = useNip4Chat();
//const nip24 = useNip24Chat();
+ const nip28 = useNip28Chat();
const { muted, blocked } = useModeration();
- return [...nip4].filter(a => !(muted.includes(a.id) || blocked.includes(a.id)));
+ return [...nip4, ...nip28].filter(a => !(muted.includes(a.id) || blocked.includes(a.id)));
}
diff --git a/packages/app/src/chat/nip28.ts b/packages/app/src/chat/nip28.ts
index e69de29b..cc0c5d86 100644
--- a/packages/app/src/chat/nip28.ts
+++ b/packages/app/src/chat/nip28.ts
@@ -0,0 +1,164 @@
+import debug from "debug";
+import { ExternalStore, FeedCache, unixNow, unwrap } from "@snort/shared";
+import {
+ EventKind,
+ NostrEvent,
+ NostrPrefix,
+ RequestBuilder,
+ SystemInterface,
+ TLVEntryType,
+ TaggedNostrEvent,
+ UserMetadata,
+ decodeTLV,
+ encodeTLVEntries,
+} from "@snort/system";
+
+import { LoginSession } from "Login";
+import { findTag } from "SnortUtils";
+import { Chat, ChatParticipant, ChatSystem, ChatType, lastReadInChat } from "chat";
+import { Day } from "Const";
+
+export class Nip28ChatSystem extends ExternalStore> implements ChatSystem {
+ #cache: FeedCache;
+ #log = debug("NIP-04");
+ readonly ChannelKinds = [
+ EventKind.PublicChatChannel,
+ EventKind.PublicChatMessage,
+ EventKind.PublicChatMetadata,
+ EventKind.PublicChatMuteMessage,
+ EventKind.PublicChatMuteUser,
+ ];
+
+ constructor(cache: FeedCache) {
+ super();
+ this.#cache = cache;
+ }
+
+ subscription(session: LoginSession): RequestBuilder | undefined {
+ const chats = (session.extraChats ?? []).filter(a => a.startsWith("chat281"));
+ if (chats.length === 0) return;
+
+ const chatId = (v: string) => unwrap(decodeTLV(v).find(a => a.type === TLVEntryType.Special)).value as string;
+
+ const messages = this.#chatChannels();
+ const rb = new RequestBuilder(`nip28:${session.id}`);
+ rb.withFilter()
+ .ids(chats.map(v => chatId(v)))
+ .kinds([EventKind.PublicChatChannel, EventKind.PublicChatMetadata]);
+ for (const c of chats) {
+ const id = chatId(c);
+ const lastMessage = messages[id]?.reduce((acc, v) => (v.created_at > acc ? v.created_at : acc), 0) ?? 0;
+ rb.withFilter()
+ .tag("e", [id])
+ .since(lastMessage === 0 ? unixNow() - 2 * Day : lastMessage)
+ .kinds(this.ChannelKinds);
+ }
+
+ return rb;
+ }
+
+ async onEvent(evs: readonly TaggedNostrEvent[]) {
+ const dms = evs.filter(a => this.ChannelKinds.includes(a.kind));
+ if (dms.length > 0) {
+ await this.#cache.bulkSet(dms);
+ this.notifyChange();
+ }
+ }
+
+ listChats(): Chat[] {
+ const chats = this.#chatChannels();
+ return Object.entries(chats).map(([k, v]) => {
+ return Nip28ChatSystem.createChatObj(Nip28ChatSystem.chatId(k), v);
+ });
+ }
+
+ static chatId(id: string) {
+ return encodeTLVEntries("chat28" as NostrPrefix, {
+ 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;
+ }
+
+ takeSnapshot(): Chat[] {
+ return this.listChats();
+ }
+
+ 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() {
+ const messages = this.#cache.snapshot();
+ const chats = messages.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];
+ }
+ }
+}
diff --git a/packages/app/src/chat/nip29.ts b/packages/app/src/chat/nip29.ts
index 261f7e86..ab7f3ce5 100644
--- a/packages/app/src/chat/nip29.ts
+++ b/packages/app/src/chat/nip29.ts
@@ -1,5 +1,6 @@
import { ExternalStore, FeedCache, dedupe } from "@snort/shared";
import { RequestBuilder, NostrEvent, EventKind, SystemInterface, TaggedNostrEvent } from "@snort/system";
+import { LoginSession } from "Login";
import { unwrap } from "SnortUtils";
import { Chat, ChatSystem, ChatType, lastReadInChat } from "chat";
@@ -15,7 +16,9 @@ export class Nip29ChatSystem extends ExternalStore> implements ChatS
return this.listChats();
}
- subscription(id: string) {
+ 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;
diff --git a/packages/app/src/chat/nip4.ts b/packages/app/src/chat/nip4.ts
index f9a3949b..222b8842 100644
--- a/packages/app/src/chat/nip4.ts
+++ b/packages/app/src/chat/nip4.ts
@@ -10,6 +10,7 @@ import {
TaggedNostrEvent,
decodeTLV,
} from "@snort/system";
+import { LoginSession } from "Login";
import { Chat, ChatSystem, ChatType, inChatWith, lastReadInChat } from "chat";
import { debug } from "debug";
@@ -30,7 +31,10 @@ export class Nip4ChatSystem extends ExternalStore> implements ChatSy
}
}
- subscription(pk: string) {
+ subscription(session: LoginSession) {
+ const pk = session.publicKey;
+ if (!pk) return;
+
const rb = new RequestBuilder(`nip4:${pk.slice(0, 12)}`);
const dms = this.#cache.snapshot();
const dmSince = dms.reduce(
diff --git a/packages/system/src/event-kind.ts b/packages/system/src/event-kind.ts
index 466a4818..e144a7b5 100644
--- a/packages/system/src/event-kind.ts
+++ b/packages/system/src/event-kind.ts
@@ -12,6 +12,11 @@ enum EventKind {
SimpleChatMessage = 9, // NIP-29
SealedRumor = 13, // NIP-59
ChatRumor = 14, // NIP-24
+ PublicChatChannel = 40, // NIP-28
+ PublicChatMetadata = 41, // NIP-28
+ PublicChatMessage = 42, // NIP-28
+ PublicChatMuteMessage = 43, // NIP-28
+ PublicChatMuteUser = 44, // NIP-28
SnortSubscriptions = 1000, // NIP-XX
Polls = 6969, // NIP-69
GiftWrap = 1059, // NIP-59
diff --git a/yarn.lock b/yarn.lock
index 2d992d76..5c7a35d6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10949,12 +10949,12 @@ __metadata:
languageName: node
linkType: hard
-"prettier@npm:^3.0.0":
- version: 3.0.2
- resolution: "prettier@npm:3.0.2"
+"prettier@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "prettier@npm:3.0.3"
bin:
prettier: bin/prettier.cjs
- checksum: 118b59ddb6c80abe2315ab6d0f4dd1b253be5cfdb20622fa5b65bb1573dcd362e6dd3dcf2711dd3ebfe64aecf7bdc75de8a69dc2422dcd35bdde7610586b677a
+ checksum: e10b9af02b281f6c617362ebd2571b1d7fc9fb8a3bd17e371754428cda992e5e8d8b7a046e8f7d3e2da1dcd21aa001e2e3c797402ebb6111b5cd19609dd228e0
languageName: node
linkType: hard
@@ -11726,7 +11726,7 @@ __metadata:
"@cloudflare/workers-types": ^4.20230307.0
"@tauri-apps/cli": ^1.2.3
eslint: ^8.48.0
- prettier: ^3.0.0
+ prettier: ^3.0.3
typescript: ^5.2.2
languageName: unknown
linkType: soft