feat: update rust nostr
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
"build": "turbo run build",
|
"build": "turbo run build",
|
||||||
"dev": "turbo run dev",
|
"dev": "turbo run dev",
|
||||||
"web:dev": "turbo run dev --filter web",
|
"web:dev": "turbo run dev --filter web",
|
||||||
"desktop:dev": "turbo run dev --filter desktop2",
|
"desktop:dev": "turbo run dev --filter desktop",
|
||||||
"tauri": "tauri"
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -6,11 +6,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@getalby/sdk": "^3.2.3",
|
"@getalby/sdk": "^3.2.3",
|
||||||
"@lume/icons": "workspace:^",
|
"@lume/icons": "workspace:^",
|
||||||
"@lume/ndk-cache-tauri": "workspace:^",
|
|
||||||
"@lume/storage": "workspace:^",
|
|
||||||
"@lume/utils": "workspace:^",
|
"@lume/utils": "workspace:^",
|
||||||
"@nostr-dev-kit/ndk": "^2.4.0",
|
|
||||||
"@nostr-fetch/adapter-ndk": "^0.15.0",
|
|
||||||
"@radix-ui/react-avatar": "^1.0.4",
|
"@radix-ui/react-avatar": "^1.0.4",
|
||||||
"@radix-ui/react-collapsible": "^1.0.3",
|
"@radix-ui/react-collapsible": "^1.0.3",
|
||||||
"@radix-ui/react-dialog": "^1.0.5",
|
"@radix-ui/react-dialog": "^1.0.5",
|
||||||
@@ -21,13 +17,9 @@
|
|||||||
"@tanstack/react-query": "^5.18.1",
|
"@tanstack/react-query": "^5.18.1",
|
||||||
"get-urls": "^12.1.0",
|
"get-urls": "^12.1.0",
|
||||||
"jotai": "^2.6.4",
|
"jotai": "^2.6.4",
|
||||||
"linkify-react": "^4.1.3",
|
|
||||||
"linkifyjs": "^4.1.3",
|
|
||||||
"media-chrome": "^2.1.0",
|
"media-chrome": "^2.1.0",
|
||||||
"minidenticons": "^4.2.0",
|
"minidenticons": "^4.2.0",
|
||||||
"nanoid": "^5.0.5",
|
"nanoid": "^5.0.5",
|
||||||
"nostr-fetch": "^0.15.0",
|
|
||||||
"nostr-tools": "1.17.0",
|
|
||||||
"qrcode.react": "^3.1.0",
|
"qrcode.react": "^3.1.0",
|
||||||
"re-resizable": "^6.9.11",
|
"re-resizable": "^6.9.11",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
@@ -37,8 +29,6 @@
|
|||||||
"react-string-replace": "^1.1.1",
|
"react-string-replace": "^1.1.1",
|
||||||
"sonner": "^1.4.0",
|
"sonner": "^1.4.0",
|
||||||
"string-strip-html": "^13.4.6",
|
"string-strip-html": "^13.4.6",
|
||||||
"tippy.js": "^6.3.7",
|
|
||||||
"use-context-selector": "^1.4.1",
|
|
||||||
"virtua": "^0.23.3"
|
"virtua": "^0.23.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -46,7 +36,6 @@
|
|||||||
"@lume/tsconfig": "workspace:^",
|
"@lume/tsconfig": "workspace:^",
|
||||||
"@lume/types": "workspace:^",
|
"@lume/types": "workspace:^",
|
||||||
"@types/react": "^18.2.52",
|
"@types/react": "^18.2.52",
|
||||||
"tailwind-merge": "^2.2.1",
|
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,301 +1,56 @@
|
|||||||
import { Account, type NDKEventWithReplies, type NIP05 } from "@lume/types";
|
import { type CurrentAccount, Event, Metadata } from "@lume/types";
|
||||||
import NDK, {
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
NDKEvent,
|
|
||||||
NDKFilter,
|
|
||||||
NDKKind,
|
|
||||||
NDKNip46Signer,
|
|
||||||
NDKPrivateKeySigner,
|
|
||||||
NDKRelay,
|
|
||||||
NDKSubscriptionCacheUsage,
|
|
||||||
NDKTag,
|
|
||||||
NDKUser,
|
|
||||||
NostrEvent,
|
|
||||||
} from "@nostr-dev-kit/ndk";
|
|
||||||
import { ndkAdapter } from "@nostr-fetch/adapter-ndk";
|
|
||||||
import { open } from "@tauri-apps/plugin-dialog";
|
|
||||||
import { readFile } from "@tauri-apps/plugin-fs";
|
|
||||||
import { fetch } from "@tauri-apps/plugin-http";
|
|
||||||
import { NostrFetcher, normalizeRelayUrl } from "nostr-fetch";
|
|
||||||
import { nip19 } from "nostr-tools";
|
|
||||||
|
|
||||||
export class Ark {
|
export class Ark {
|
||||||
public ndk: NDK;
|
public account: CurrentAccount;
|
||||||
public account: Account;
|
|
||||||
|
|
||||||
constructor({
|
constructor(account: CurrentAccount) {
|
||||||
ndk,
|
|
||||||
account,
|
|
||||||
}: {
|
|
||||||
ndk: NDK;
|
|
||||||
account: Account;
|
|
||||||
}) {
|
|
||||||
this.ndk = ndk;
|
|
||||||
this.account = account;
|
this.account = account;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async connectDepot() {
|
public async event_to_bech32(id: string, relays: string[]) {
|
||||||
return this.ndk.addExplicitRelay(
|
|
||||||
new NDKRelay(normalizeRelayUrl("ws://localhost:6090")),
|
|
||||||
undefined,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateNostrSigner({
|
|
||||||
signer,
|
|
||||||
}: { signer: NDKNip46Signer | NDKPrivateKeySigner }) {
|
|
||||||
this.ndk.signer = signer;
|
|
||||||
return this.ndk.signer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public subscribe({
|
|
||||||
filter,
|
|
||||||
closeOnEose = false,
|
|
||||||
cb,
|
|
||||||
}: {
|
|
||||||
filter: NDKFilter;
|
|
||||||
closeOnEose: boolean;
|
|
||||||
cb: (event: NDKEvent) => void;
|
|
||||||
}) {
|
|
||||||
const sub = this.ndk.subscribe(filter, { closeOnEose });
|
|
||||||
sub.addListener("event", (event: NDKEvent) => cb(event));
|
|
||||||
return sub;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNDKEvent(event: NostrEvent) {
|
|
||||||
return new NDKEvent(this.ndk, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async createEvent({
|
|
||||||
kind,
|
|
||||||
tags,
|
|
||||||
content,
|
|
||||||
rootReplyTo = undefined,
|
|
||||||
replyTo = undefined,
|
|
||||||
}: {
|
|
||||||
kind: NDKKind | number;
|
|
||||||
tags: NDKTag[];
|
|
||||||
content?: string;
|
|
||||||
rootReplyTo?: string;
|
|
||||||
replyTo?: string;
|
|
||||||
}) {
|
|
||||||
try {
|
try {
|
||||||
const event = new NDKEvent(this.ndk);
|
const cmd: string = await invoke("event_to_bech32", {
|
||||||
if (content) event.content = content;
|
id,
|
||||||
event.kind = kind;
|
relays,
|
||||||
event.tags = tags;
|
|
||||||
|
|
||||||
if (rootReplyTo) {
|
|
||||||
const rootEvent = await this.ndk.fetchEvent(rootReplyTo);
|
|
||||||
if (rootEvent) event.tag(rootEvent, "root");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (replyTo) {
|
|
||||||
const replyEvent = await this.ndk.fetchEvent(replyTo);
|
|
||||||
if (replyEvent) event.tag(replyEvent, "reply");
|
|
||||||
}
|
|
||||||
|
|
||||||
const publish = await event.publish();
|
|
||||||
|
|
||||||
if (!publish) throw new Error("Failed to publish event");
|
|
||||||
return {
|
|
||||||
id: event.id,
|
|
||||||
seens: [...publish.values()].map((item) => item.url),
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public getCleanPubkey(pubkey: string) {
|
|
||||||
try {
|
|
||||||
let hexstring = pubkey
|
|
||||||
.replace("nostr:", "")
|
|
||||||
.split("'")[0]
|
|
||||||
.split(".")[0]
|
|
||||||
.split(",")[0]
|
|
||||||
.split("?")[0];
|
|
||||||
|
|
||||||
if (
|
|
||||||
hexstring.startsWith("npub1") ||
|
|
||||||
hexstring.startsWith("nprofile1") ||
|
|
||||||
hexstring.startsWith("naddr1")
|
|
||||||
) {
|
|
||||||
const decoded = nip19.decode(hexstring);
|
|
||||||
|
|
||||||
if (decoded.type === "nprofile") hexstring = decoded.data.pubkey;
|
|
||||||
if (decoded.type === "npub") hexstring = decoded.data;
|
|
||||||
if (decoded.type === "naddr") hexstring = decoded.data.pubkey;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hexstring;
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getUserProfile(pubkey?: string) {
|
|
||||||
try {
|
|
||||||
const currentUserPubkey = this.account.pubkey;
|
|
||||||
const hexstring = pubkey
|
|
||||||
? this.getCleanPubkey(pubkey)
|
|
||||||
: currentUserPubkey;
|
|
||||||
|
|
||||||
const user = this.ndk.getUser({
|
|
||||||
pubkey: hexstring,
|
|
||||||
});
|
});
|
||||||
|
return cmd;
|
||||||
const profile = await user.fetchProfile({
|
|
||||||
cacheUsage: NDKSubscriptionCacheUsage.CACHE_FIRST,
|
|
||||||
});
|
|
||||||
|
|
||||||
return profile;
|
|
||||||
} catch {
|
} catch {
|
||||||
throw new Error("user not found");
|
console.error("get nevent id failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getUserContacts(pubkey?: string) {
|
public async get_event(id: string) {
|
||||||
try {
|
try {
|
||||||
const currentUserPubkey = this.account.pubkey;
|
const cmd: string = await invoke("get_event", { id });
|
||||||
const hexstring = pubkey
|
const event = JSON.parse(cmd) as Event;
|
||||||
? this.getCleanPubkey(pubkey)
|
|
||||||
: currentUserPubkey;
|
|
||||||
|
|
||||||
const user = this.ndk.getUser({
|
|
||||||
pubkey: hexstring,
|
|
||||||
});
|
|
||||||
|
|
||||||
const contacts = [...(await user.follows(undefined, false))].map(
|
|
||||||
(user) => user.pubkey,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!pubkey || pubkey === this.account.pubkey) {
|
|
||||||
this.account.contacts = contacts;
|
|
||||||
}
|
|
||||||
|
|
||||||
return contacts;
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getUserRelays({ pubkey }: { pubkey?: string }) {
|
|
||||||
try {
|
|
||||||
const user = this.ndk.getUser({
|
|
||||||
pubkey: pubkey ? pubkey : this.account.pubkey,
|
|
||||||
});
|
|
||||||
return await user.relayList();
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async newContactList({ tags }: { tags: NDKTag[] }) {
|
|
||||||
const publish = await this.createEvent({
|
|
||||||
kind: NDKKind.Contacts,
|
|
||||||
tags: tags,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (publish) {
|
|
||||||
this.account.contacts = tags.map((item) => item[1]);
|
|
||||||
return publish;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async createContact(pubkey: string) {
|
|
||||||
const user = this.ndk.getUser({ pubkey: this.account.pubkey });
|
|
||||||
const contacts = await user.follows();
|
|
||||||
return await user.follow(new NDKUser({ pubkey: pubkey }), contacts);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async deleteContact(pubkey: string) {
|
|
||||||
const user = this.ndk.getUser({ pubkey: this.account.pubkey });
|
|
||||||
const contacts = await user.follows();
|
|
||||||
contacts.delete(new NDKUser({ pubkey: pubkey }));
|
|
||||||
|
|
||||||
const event = new NDKEvent(this.ndk);
|
|
||||||
event.content = "";
|
|
||||||
event.kind = NDKKind.Contacts;
|
|
||||||
event.tags = [...contacts].map((item) => [
|
|
||||||
"p",
|
|
||||||
item.pubkey,
|
|
||||||
item.relayUrls?.[0] || "",
|
|
||||||
"",
|
|
||||||
]);
|
|
||||||
|
|
||||||
return await event.publish();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getAllEvents({ filter }: { filter: NDKFilter }) {
|
|
||||||
const events = await this.ndk.fetchEvents(filter);
|
|
||||||
if (!events) return [];
|
|
||||||
return [...events];
|
|
||||||
}
|
|
||||||
|
|
||||||
public getCleanEventId(id: string) {
|
|
||||||
let eventId: string = id.replace("nostr:", "").split("'")[0].split(".")[0];
|
|
||||||
|
|
||||||
if (
|
|
||||||
eventId.startsWith("nevent1") ||
|
|
||||||
eventId.startsWith("note1") ||
|
|
||||||
eventId.startsWith("naddr1")
|
|
||||||
) {
|
|
||||||
const decode = nip19.decode(eventId);
|
|
||||||
if (decode.type === "nevent") eventId = decode.data.id;
|
|
||||||
if (decode.type === "note") eventId = decode.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
return eventId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getEventById(id: string) {
|
|
||||||
try {
|
|
||||||
const eventId = this.getCleanEventId(id);
|
|
||||||
return await this.ndk.fetchEvent(eventId);
|
|
||||||
} catch {
|
|
||||||
throw new Error("event not found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getEventByFilter({
|
|
||||||
filter,
|
|
||||||
cache,
|
|
||||||
}: { filter: NDKFilter; cache?: NDKSubscriptionCacheUsage }) {
|
|
||||||
const event = await this.ndk.fetchEvent(filter, {
|
|
||||||
cacheUsage: cache || NDKSubscriptionCacheUsage.CACHE_FIRST,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!event) return null;
|
|
||||||
return event;
|
return event;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("failed to get event", id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getEvents(filter: NDKFilter) {
|
public parse_event_thread({
|
||||||
const events = await this.ndk.fetchEvents(filter);
|
|
||||||
if (!events) return [];
|
|
||||||
return [...events];
|
|
||||||
}
|
|
||||||
|
|
||||||
public getEventThread({
|
|
||||||
content,
|
content,
|
||||||
tags,
|
tags,
|
||||||
}: { content: string; tags: NDKTag[] }) {
|
}: { content: string; tags: string[][] }) {
|
||||||
let rootEventId: string = null;
|
let rootEventId: string = null;
|
||||||
let replyEventId: string = null;
|
let replyEventId: string = null;
|
||||||
|
|
||||||
|
// Ignore quote repost
|
||||||
if (content.includes("nostr:note1") || content.includes("nostr:nevent1"))
|
if (content.includes("nostr:note1") || content.includes("nostr:nevent1"))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
// Get all event references from tags, ignore mention
|
||||||
const events = tags.filter((el) => el[0] === "e" && el[3] !== "mention");
|
const events = tags.filter((el) => el[0] === "e" && el[3] !== "mention");
|
||||||
|
|
||||||
if (!events.length) return null;
|
if (!events.length) return null;
|
||||||
|
if (events.length === 1) {
|
||||||
if (events.length === 1)
|
|
||||||
return {
|
return {
|
||||||
rootEventId: events[0][1],
|
rootEventId: events[0][1],
|
||||||
replyEventId: null,
|
replyEventId: null,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
if (events.length > 1) {
|
if (events.length > 1) {
|
||||||
rootEventId = events.find((el) => el[3] === "root")?.[1];
|
rootEventId = events.find((el) => el[3] === "root")?.[1];
|
||||||
replyEventId = events.find((el) => el[3] === "reply")?.[1];
|
replyEventId = events.find((el) => el[3] === "reply")?.[1];
|
||||||
@@ -312,310 +67,24 @@ export class Ark {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getThreads(id: string) {
|
public async get_metadata(id: string) {
|
||||||
const eventId = this.getCleanEventId(id);
|
|
||||||
const fetcher = NostrFetcher.withCustomPool(ndkAdapter(this.ndk));
|
|
||||||
const relayUrls = Array.from(this.ndk.pool.relays.keys());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const rawEvents = (await fetcher.fetchAllEvents(
|
const cmd: Metadata = await invoke("get_metadata", { id });
|
||||||
relayUrls,
|
return cmd;
|
||||||
{
|
|
||||||
kinds: [NDKKind.Text],
|
|
||||||
"#e": [eventId],
|
|
||||||
},
|
|
||||||
{ since: 0 },
|
|
||||||
{ sort: true },
|
|
||||||
)) as unknown as NostrEvent[];
|
|
||||||
|
|
||||||
const events = rawEvents.map(
|
|
||||||
(event) => new NDKEvent(this.ndk, event),
|
|
||||||
) as NDKEvent[] as NDKEventWithReplies[];
|
|
||||||
|
|
||||||
if (events.length > 0) {
|
|
||||||
const replies = new Set();
|
|
||||||
for (const event of events) {
|
|
||||||
const tags = event.tags.filter(
|
|
||||||
(el) => el[0] === "e" && el[1] !== id && el[3] !== "mention",
|
|
||||||
);
|
|
||||||
if (tags.length > 0) {
|
|
||||||
for (const tag of tags) {
|
|
||||||
const rootIndex = events.findIndex((el) => el.id === tag[1]);
|
|
||||||
if (rootIndex !== -1) {
|
|
||||||
const rootEvent = events[rootIndex];
|
|
||||||
if (rootEvent?.replies) {
|
|
||||||
rootEvent.replies.push(event);
|
|
||||||
} else {
|
|
||||||
rootEvent.replies = [event];
|
|
||||||
}
|
|
||||||
replies.add(event.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const cleanEvents = events.filter((ev) => !replies.has(ev.id));
|
|
||||||
return cleanEvents;
|
|
||||||
}
|
|
||||||
|
|
||||||
return events;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.error("failed to get metadata", id);
|
||||||
} finally {
|
|
||||||
fetcher.shutdown();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAllRelaysFromContacts({ signal }: { signal: AbortSignal }) {
|
public async user_to_bech32(key: string, relays: string[]) {
|
||||||
const fetcher = NostrFetcher.withCustomPool(ndkAdapter(this.ndk));
|
|
||||||
const connectedRelays = Array.from(this.ndk.pool.relays.keys());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const relayMap = new Map<string, string[]>();
|
const cmd: string = await invoke("user_to_bech32", {
|
||||||
const relayEvents = fetcher.fetchLatestEventsPerAuthor(
|
key,
|
||||||
{
|
relays,
|
||||||
authors: this.account.contacts,
|
|
||||||
relayUrls: connectedRelays,
|
|
||||||
},
|
|
||||||
{ kinds: [NDKKind.RelayList] },
|
|
||||||
1,
|
|
||||||
{ abortSignal: signal },
|
|
||||||
);
|
|
||||||
|
|
||||||
for await (const { author, events } of relayEvents) {
|
|
||||||
if (events.length) {
|
|
||||||
const relayTags = events[0].tags.filter((item) => item[0] === "r");
|
|
||||||
for (const tag of relayTags) {
|
|
||||||
const item = relayMap.get(tag[1]);
|
|
||||||
if (item?.length) {
|
|
||||||
item.push(author);
|
|
||||||
} else {
|
|
||||||
relayMap.set(tag[1], [author]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return relayMap;
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
} finally {
|
|
||||||
fetcher.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getInfiniteEvents({
|
|
||||||
filter,
|
|
||||||
limit,
|
|
||||||
pageParam = 0,
|
|
||||||
signal = undefined,
|
|
||||||
dedup = true,
|
|
||||||
}: {
|
|
||||||
filter: NDKFilter;
|
|
||||||
limit: number;
|
|
||||||
pageParam?: number;
|
|
||||||
signal?: AbortSignal;
|
|
||||||
dedup?: boolean;
|
|
||||||
}) {
|
|
||||||
const fetcher = NostrFetcher.withCustomPool(ndkAdapter(this.ndk));
|
|
||||||
const relayUrls = Array.from(this.ndk.pool.relays.keys());
|
|
||||||
const seenIds = new Set<string>();
|
|
||||||
const dedupQueue = new Set<string>();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const events = await fetcher.fetchLatestEvents(relayUrls, filter, limit, {
|
|
||||||
asOf: pageParam === 0 ? undefined : pageParam,
|
|
||||||
abortSignal: signal,
|
|
||||||
});
|
});
|
||||||
|
return cmd;
|
||||||
const ndkEvents = events.map((event) => {
|
} catch {
|
||||||
return new NDKEvent(this.ndk, event);
|
console.error("get nprofile id failed");
|
||||||
});
|
|
||||||
|
|
||||||
if (dedup) {
|
|
||||||
for (const event of ndkEvents) {
|
|
||||||
const tags = event.tags
|
|
||||||
.filter((el) => el[0] === "e")
|
|
||||||
?.map((item) => item[1]);
|
|
||||||
|
|
||||||
if (tags.length) {
|
|
||||||
for (const tag of tags) {
|
|
||||||
if (seenIds.has(tag)) {
|
|
||||||
dedupQueue.add(event.id);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
seenIds.add(tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ndkEvents
|
|
||||||
.filter((event) => !dedupQueue.has(event.id))
|
|
||||||
.sort((a, b) => b.created_at - a.created_at);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ndkEvents.sort((a, b) => b.created_at - a.created_at);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
} finally {
|
|
||||||
fetcher.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getRelayEvents({
|
|
||||||
relayUrl,
|
|
||||||
filter,
|
|
||||||
limit,
|
|
||||||
pageParam = 0,
|
|
||||||
signal = undefined,
|
|
||||||
}: {
|
|
||||||
relayUrl: string;
|
|
||||||
filter: NDKFilter;
|
|
||||||
limit: number;
|
|
||||||
pageParam?: number;
|
|
||||||
signal?: AbortSignal;
|
|
||||||
dedup?: boolean;
|
|
||||||
}) {
|
|
||||||
const fetcher = NostrFetcher.withCustomPool(ndkAdapter(this.ndk));
|
|
||||||
|
|
||||||
try {
|
|
||||||
const events = await fetcher.fetchLatestEvents(
|
|
||||||
[normalizeRelayUrl(relayUrl)],
|
|
||||||
filter,
|
|
||||||
limit,
|
|
||||||
{
|
|
||||||
asOf: pageParam === 0 ? undefined : pageParam,
|
|
||||||
abortSignal: signal,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const ndkEvents = events.map((event) => {
|
|
||||||
return new NDKEvent(this.ndk, event);
|
|
||||||
});
|
|
||||||
|
|
||||||
return ndkEvents.sort((a, b) => b.created_at - a.created_at);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
} finally {
|
|
||||||
fetcher.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Upload media file to nostr.build
|
|
||||||
* @todo support multiple backends
|
|
||||||
*/
|
|
||||||
public async upload({ fileExts }: { fileExts?: string[] }) {
|
|
||||||
const defaultExts = ["png", "jpeg", "jpg", "gif"].concat(fileExts);
|
|
||||||
|
|
||||||
const selected = await open({
|
|
||||||
multiple: false,
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
name: "Image",
|
|
||||||
extensions: defaultExts,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!selected) return null;
|
|
||||||
|
|
||||||
const file = await readFile(selected.path);
|
|
||||||
const blob = new Blob([file]);
|
|
||||||
|
|
||||||
const data = new FormData();
|
|
||||||
data.append("fileToUpload", blob);
|
|
||||||
data.append("submit", "Upload Image");
|
|
||||||
|
|
||||||
const res = await fetch("https://nostr.build/api/v2/upload/files", {
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) return null;
|
|
||||||
|
|
||||||
const json = await res.json();
|
|
||||||
const content = json.data[0];
|
|
||||||
|
|
||||||
return content.url as string;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async validateNIP05({
|
|
||||||
pubkey,
|
|
||||||
nip05,
|
|
||||||
signal,
|
|
||||||
}: {
|
|
||||||
pubkey: string;
|
|
||||||
nip05: string;
|
|
||||||
signal?: AbortSignal;
|
|
||||||
}) {
|
|
||||||
const localPath = nip05.split("@")[0];
|
|
||||||
const service = nip05.split("@")[1];
|
|
||||||
const verifyURL = `https://${service}/.well-known/nostr.json?name=${localPath}`;
|
|
||||||
|
|
||||||
const res = await fetch(verifyURL, {
|
|
||||||
method: "GET",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json; charset=utf-8",
|
|
||||||
},
|
|
||||||
signal,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) throw new Error(`Failed to fetch NIP-05 service: ${nip05}`);
|
|
||||||
|
|
||||||
const data: NIP05 = await res.json();
|
|
||||||
|
|
||||||
if (!data.names) return false;
|
|
||||||
if (data.names[localPath.toLowerCase()] === pubkey) return true;
|
|
||||||
if (data.names[localPath] === pubkey) return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getAppRecommend({
|
|
||||||
unknownKind,
|
|
||||||
author,
|
|
||||||
}: { unknownKind: string; author?: string }) {
|
|
||||||
const event = await this.ndk.fetchEvent({
|
|
||||||
kinds: [NDKKind.AppRecommendation],
|
|
||||||
"#d": [unknownKind],
|
|
||||||
authors: this.account.contacts || [author],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (event) return event.tags.filter((item) => item[0] !== "d");
|
|
||||||
|
|
||||||
const altEvent = await this.ndk.fetchEvent({
|
|
||||||
kinds: [NDKKind.AppHandler],
|
|
||||||
"#k": [unknownKind],
|
|
||||||
authors: this.account.contacts || [author],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (altEvent) return altEvent.tags.filter((item) => item[0] !== "d");
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getOAuthServices() {
|
|
||||||
const trusted: NDKEvent[] = [];
|
|
||||||
|
|
||||||
const services = await this.ndk.fetchEvents({
|
|
||||||
kinds: [NDKKind.AppHandler],
|
|
||||||
"#k": ["24133"],
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const service of services) {
|
|
||||||
const nip05 = JSON.parse(service.content).nip05 as string;
|
|
||||||
try {
|
|
||||||
const validate = await this.validateNIP05({
|
|
||||||
pubkey: service.pubkey,
|
|
||||||
nip05,
|
|
||||||
});
|
|
||||||
if (validate) trusted.push(service);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return trusted;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useStorage } from "@lume/storage";
|
import { Kind } from "@lume/types";
|
||||||
import {
|
import {
|
||||||
AUDIOS,
|
AUDIOS,
|
||||||
IMAGES,
|
IMAGES,
|
||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
cn,
|
cn,
|
||||||
regionNames,
|
regionNames,
|
||||||
} from "@lume/utils";
|
} from "@lume/utils";
|
||||||
import { NDKKind } from "@nostr-dev-kit/ndk";
|
|
||||||
import { fetch } from "@tauri-apps/plugin-http";
|
import { fetch } from "@tauri-apps/plugin-http";
|
||||||
import getUrls from "get-urls";
|
import getUrls from "get-urls";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
@@ -32,7 +31,6 @@ export function NoteContent({
|
|||||||
}: {
|
}: {
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
const storage = useStorage();
|
|
||||||
const event = useNoteContext();
|
const event = useNoteContext();
|
||||||
|
|
||||||
const [content, setContent] = useState(event.content);
|
const [content, setContent] = useState(event.content);
|
||||||
@@ -42,7 +40,7 @@ export function NoteContent({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const richContent = useMemo(() => {
|
const richContent = useMemo(() => {
|
||||||
if (event.kind !== NDKKind.Text) return content;
|
if (event.kind !== Kind.Text) return content;
|
||||||
|
|
||||||
let parsedContent: string | ReactNode[] = stripHtml(
|
let parsedContent: string | ReactNode[] = stripHtml(
|
||||||
content.replace(/\n{2,}\s*/g, "\n"),
|
content.replace(/\n{2,}\s*/g, "\n"),
|
||||||
|
|||||||
@@ -2,32 +2,22 @@ import { HorizontalDotsIcon } from "@lume/icons";
|
|||||||
import { COL_TYPES } from "@lume/utils";
|
import { COL_TYPES } from "@lume/utils";
|
||||||
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
||||||
import { writeText } from "@tauri-apps/plugin-clipboard-manager";
|
import { writeText } from "@tauri-apps/plugin-clipboard-manager";
|
||||||
import { nip19 } from "nostr-tools";
|
|
||||||
import { type EventPointer } from "nostr-tools/lib/types/nip19";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import { toast } from "sonner";
|
import { useArk } from "../../hooks/useArk";
|
||||||
import { useColumnContext } from "../column/provider";
|
import { useColumnContext } from "../column/provider";
|
||||||
import { useNoteContext } from "./provider";
|
import { useNoteContext } from "./provider";
|
||||||
|
|
||||||
export function NoteMenu() {
|
export function NoteMenu() {
|
||||||
|
const ark = useArk();
|
||||||
const event = useNoteContext();
|
const event = useNoteContext();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { addColumn } = useColumnContext();
|
const { addColumn } = useColumnContext();
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
|
|
||||||
const copyID = async () => {
|
const copyID = async () => {
|
||||||
await writeText(
|
await writeText(await ark.event_to_bech32(event.id, [""]));
|
||||||
nip19.neventEncode({
|
|
||||||
id: event.id,
|
|
||||||
author: event.pubkey,
|
|
||||||
} as EventPointer),
|
|
||||||
);
|
|
||||||
setOpen(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const copyRaw = async () => {
|
const copyRaw = async () => {
|
||||||
@@ -35,26 +25,17 @@ export function NoteMenu() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const copyNpub = async () => {
|
const copyNpub = async () => {
|
||||||
await writeText(nip19.npubEncode(event.pubkey));
|
await writeText(await ark.user_to_bech32(event.pubkey, [""]));
|
||||||
};
|
};
|
||||||
|
|
||||||
const copyLink = async () => {
|
const copyLink = async () => {
|
||||||
await writeText(
|
await writeText(
|
||||||
`https://njump.me/${nip19.neventEncode({
|
`https://njump.me/${await ark.event_to_bech32(event.id, [""])}`,
|
||||||
id: event.id,
|
|
||||||
author: event.pubkey,
|
|
||||||
} as EventPointer)}`,
|
|
||||||
);
|
);
|
||||||
setOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const muteUser = async () => {
|
|
||||||
event.muted();
|
|
||||||
toast.info("You've muted this user");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu.Root open={open} onOpenChange={setOpen}>
|
<DropdownMenu.Root>
|
||||||
<DropdownMenu.Trigger asChild>
|
<DropdownMenu.Trigger asChild>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -134,15 +115,6 @@ export function NoteMenu() {
|
|||||||
{t("note.menu.copyRaw")}
|
{t("note.menu.copyRaw")}
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
<DropdownMenu.Item asChild>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={muteUser}
|
|
||||||
className="inline-flex items-center gap-3 px-3 text-sm font-medium text-red-500 rounded-lg h-9 hover:bg-red-500 hover:text-red-50 focus:outline-none"
|
|
||||||
>
|
|
||||||
{t("note.menu.mute")}
|
|
||||||
</button>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
</DropdownMenu.Portal>
|
</DropdownMenu.Portal>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export function NoteThread({
|
|||||||
}) {
|
}) {
|
||||||
const ark = useArk();
|
const ark = useArk();
|
||||||
const event = useNoteContext();
|
const event = useNoteContext();
|
||||||
const thread = ark.getEventThread({
|
const thread = ark.parse_event_thread({
|
||||||
content: event.content,
|
content: event.content,
|
||||||
tags: event.tags,
|
tags: event.tags,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { NDKUserProfile } from "@nostr-dev-kit/ndk";
|
import { Metadata } from "@lume/types";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { ReactNode, createContext, useContext } from "react";
|
import { ReactNode, createContext, useContext } from "react";
|
||||||
import { useArk } from "../../hooks/useArk";
|
import { useArk } from "../../hooks/useArk";
|
||||||
|
|
||||||
const UserContext = createContext<NDKUserProfile>(null);
|
const UserContext = createContext<Metadata>(null);
|
||||||
|
|
||||||
export function UserProvider({
|
export function UserProvider({
|
||||||
pubkey,
|
pubkey,
|
||||||
@@ -14,9 +14,10 @@ export function UserProvider({
|
|||||||
const { data: user } = useQuery({
|
const { data: user } = useQuery({
|
||||||
queryKey: ["user", pubkey],
|
queryKey: ["user", pubkey],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (embed) return JSON.parse(embed) as NDKUserProfile;
|
if (embed) return JSON.parse(embed) as Metadata;
|
||||||
|
|
||||||
|
const profile = await ark.get_metadata(pubkey);
|
||||||
|
|
||||||
const profile = await ark.getUserProfile(pubkey);
|
|
||||||
if (!profile)
|
if (!profile)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Cannot get metadata for ${pubkey}, will be retry after 10 seconds`,
|
`Cannot get metadata for ${pubkey}, will be retry after 10 seconds`,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export function useEvent(id: string) {
|
|||||||
const { isLoading, isError, data } = useQuery({
|
const { isLoading, isError, data } = useQuery({
|
||||||
queryKey: ["event", id],
|
queryKey: ["event", id],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const event = await ark.getEventById(id);
|
const event = await ark.get_event(id);
|
||||||
if (!event)
|
if (!event)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Cannot get event with ${id}, will be retry after 10 seconds`,
|
`Cannot get event with ${id}, will be retry after 10 seconds`,
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
import { NDKUserProfile } from "@nostr-dev-kit/ndk";
|
|
||||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { useArk } from "./useArk";
|
import { useArk } from "./useArk";
|
||||||
|
|
||||||
export function useProfile(pubkey: string) {
|
export function useProfile(pubkey: string) {
|
||||||
const ark = useArk();
|
const ark = useArk();
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isLoading,
|
isLoading,
|
||||||
isError,
|
isError,
|
||||||
@@ -13,16 +10,13 @@ export function useProfile(pubkey: string) {
|
|||||||
} = useQuery({
|
} = useQuery({
|
||||||
queryKey: ["user", pubkey],
|
queryKey: ["user", pubkey],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const profile = await ark.getUserProfile(pubkey);
|
const profile = await ark.get_metadata(pubkey);
|
||||||
if (!profile)
|
if (!profile)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Cannot get metadata for ${pubkey}, will be retry after 10 seconds`,
|
`Cannot get metadata for ${pubkey}, will be retry after 10 seconds`,
|
||||||
);
|
);
|
||||||
return profile;
|
return profile;
|
||||||
},
|
},
|
||||||
initialData: () => {
|
|
||||||
return queryClient.getQueryData(["user", pubkey]) as NDKUserProfile;
|
|
||||||
},
|
|
||||||
refetchOnMount: false,
|
refetchOnMount: false,
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
refetchOnReconnect: false,
|
refetchOnReconnect: false,
|
||||||
|
|||||||
@@ -1,255 +1,18 @@
|
|||||||
import { LoaderIcon } from "@lume/icons";
|
|
||||||
import { NDKCacheAdapterTauri } from "@lume/ndk-cache-tauri";
|
|
||||||
import { useStorage } from "@lume/storage";
|
|
||||||
import {
|
|
||||||
FETCH_LIMIT,
|
|
||||||
QUOTES,
|
|
||||||
activityUnreadAtom,
|
|
||||||
sendNativeNotification,
|
|
||||||
} from "@lume/utils";
|
|
||||||
import NDK, {
|
|
||||||
NDKEvent,
|
|
||||||
NDKKind,
|
|
||||||
NDKNip46Signer,
|
|
||||||
NDKPrivateKeySigner,
|
|
||||||
NDKRelay,
|
|
||||||
NDKRelayAuthPolicies,
|
|
||||||
NDKUser,
|
|
||||||
} from "@nostr-dev-kit/ndk";
|
|
||||||
import { useQueryClient } from "@tanstack/react-query";
|
|
||||||
import { message } from "@tauri-apps/plugin-dialog";
|
|
||||||
import { fetch } from "@tauri-apps/plugin-http";
|
|
||||||
import { useSetAtom } from "jotai";
|
|
||||||
import Linkify from "linkify-react";
|
|
||||||
import { normalizeRelayUrlSet } from "nostr-fetch";
|
|
||||||
import { PropsWithChildren, useEffect, useState } from "react";
|
import { PropsWithChildren, useEffect, useState } from "react";
|
||||||
import { toast } from "sonner";
|
|
||||||
import { Ark } from "./ark";
|
import { Ark } from "./ark";
|
||||||
import { LumeContext } from "./context";
|
import { LumeContext } from "./context";
|
||||||
|
|
||||||
export const LumeProvider = ({ children }: PropsWithChildren<object>) => {
|
export const LumeProvider = ({ children }: PropsWithChildren<object>) => {
|
||||||
const storage = useStorage();
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const setUnreadActivity = useSetAtom(activityUnreadAtom);
|
|
||||||
|
|
||||||
const [ark, setArk] = useState<Ark>(undefined);
|
const [ark, setArk] = useState<Ark>(undefined);
|
||||||
const [ndk, setNDK] = useState<NDK>(undefined);
|
|
||||||
|
|
||||||
async function initNostrSigner({
|
|
||||||
nsecbunker,
|
|
||||||
}: {
|
|
||||||
nsecbunker?: boolean;
|
|
||||||
}) {
|
|
||||||
try {
|
|
||||||
if (!storage.currentUser) return null;
|
|
||||||
|
|
||||||
// NIP-46 Signer
|
|
||||||
if (nsecbunker) {
|
|
||||||
const localSignerPrivkey = await storage.loadPrivkey(
|
|
||||||
storage.currentUser.pubkey,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!localSignerPrivkey) return null;
|
|
||||||
|
|
||||||
const localSigner = new NDKPrivateKeySigner(localSignerPrivkey);
|
|
||||||
const bunker = new NDK({
|
|
||||||
explicitRelayUrls: normalizeRelayUrlSet([
|
|
||||||
"wss://relay.nsecbunker.com/",
|
|
||||||
"wss://nostr.vulpem.com/",
|
|
||||||
]),
|
|
||||||
});
|
|
||||||
await bunker.connect(2000);
|
|
||||||
|
|
||||||
const remoteSigner = new NDKNip46Signer(
|
|
||||||
bunker,
|
|
||||||
storage.currentUser.pubkey,
|
|
||||||
localSigner,
|
|
||||||
);
|
|
||||||
await remoteSigner.blockUntilReady();
|
|
||||||
|
|
||||||
return remoteSigner;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Privkey Signer
|
|
||||||
const userPrivkey = await storage.loadPrivkey(storage.currentUser.pubkey);
|
|
||||||
if (!userPrivkey) return null;
|
|
||||||
|
|
||||||
// load nwc
|
|
||||||
storage.nwc = await storage.loadPrivkey(
|
|
||||||
`${storage.currentUser.pubkey}.nwc`,
|
|
||||||
);
|
|
||||||
|
|
||||||
return new NDKPrivateKeySigner(userPrivkey);
|
|
||||||
} catch (e) {
|
|
||||||
toast.error(String(e));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function initNDK() {
|
|
||||||
try {
|
|
||||||
const explicitRelayUrls = normalizeRelayUrlSet([
|
|
||||||
"wss://nostr.mutinywallet.com/",
|
|
||||||
"wss://bostr.nokotaro.com/",
|
|
||||||
"wss://purplepag.es/",
|
|
||||||
]);
|
|
||||||
|
|
||||||
const outboxRelayUrls = normalizeRelayUrlSet(["wss://purplepag.es/"]);
|
|
||||||
|
|
||||||
const tauriCache = new NDKCacheAdapterTauri(storage);
|
|
||||||
const ndk = new NDK({
|
|
||||||
cacheAdapter: tauriCache,
|
|
||||||
explicitRelayUrls,
|
|
||||||
outboxRelayUrls,
|
|
||||||
enableOutboxModel: !storage.settings.lowPower,
|
|
||||||
autoConnectUserRelays: !storage.settings.lowPower,
|
|
||||||
autoFetchUserMutelist: false, // #TODO: add support mute list
|
|
||||||
clientName: "Lume",
|
|
||||||
});
|
|
||||||
|
|
||||||
// use tauri fetch
|
|
||||||
ndk.httpFetch = fetch;
|
|
||||||
|
|
||||||
// add signer
|
|
||||||
const signer = await initNostrSigner({
|
|
||||||
nsecbunker: storage.settings.nsecbunker,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (signer) ndk.signer = signer;
|
|
||||||
|
|
||||||
// connect
|
|
||||||
await ndk.connect(3000);
|
|
||||||
|
|
||||||
// auth
|
|
||||||
ndk.relayAuthDefaultPolicy = async (
|
|
||||||
relay: NDKRelay,
|
|
||||||
challenge: string,
|
|
||||||
) => {
|
|
||||||
const signIn = NDKRelayAuthPolicies.signIn({ ndk });
|
|
||||||
const event = await signIn(relay, challenge).catch((e) =>
|
|
||||||
console.log("auth failed", e),
|
|
||||||
);
|
|
||||||
if (event) {
|
|
||||||
await sendNativeNotification(
|
|
||||||
`You've sign in sucessfully to relay: ${relay.url}`,
|
|
||||||
);
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
setNDK(ndk);
|
|
||||||
} catch (e) {
|
|
||||||
toast.error(String(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function initArk() {
|
|
||||||
if (!ndk) await message("Something wrong!", { type: "error" });
|
|
||||||
|
|
||||||
// ark utils
|
|
||||||
const ark = new Ark({ ndk, account: storage.currentUser });
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (ndk && storage.currentUser) {
|
|
||||||
const user = new NDKUser({ pubkey: storage.currentUser.pubkey });
|
|
||||||
ndk.activeUser = user;
|
|
||||||
|
|
||||||
// update contacts
|
|
||||||
const contacts = await ark.getUserContacts();
|
|
||||||
|
|
||||||
if (contacts?.length) {
|
|
||||||
console.log("total contacts: ", contacts.length);
|
|
||||||
for (const pubkey of ark.account.contacts) {
|
|
||||||
await queryClient.prefetchQuery({
|
|
||||||
queryKey: ["user", pubkey],
|
|
||||||
queryFn: async () => {
|
|
||||||
return await ark.getUserProfile(pubkey);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// subscribe for new activity
|
|
||||||
const activitySub = ndk.subscribe(
|
|
||||||
{
|
|
||||||
kinds: [NDKKind.Text, NDKKind.Repost, NDKKind.Zap],
|
|
||||||
since: Math.floor(Date.now() / 1000),
|
|
||||||
"#p": [ark.account.pubkey],
|
|
||||||
},
|
|
||||||
{ closeOnEose: false, groupable: false },
|
|
||||||
);
|
|
||||||
|
|
||||||
activitySub.addListener("event", async (event: NDKEvent) => {
|
|
||||||
if (event.pubkey === storage.currentUser.pubkey) return;
|
|
||||||
|
|
||||||
setUnreadActivity((state) => state + 1);
|
|
||||||
const profile = await ark.getUserProfile(event.pubkey);
|
|
||||||
|
|
||||||
switch (event.kind) {
|
|
||||||
case NDKKind.Text:
|
|
||||||
return await sendNativeNotification(
|
|
||||||
`${
|
|
||||||
profile.displayName || profile.name || "Anon"
|
|
||||||
} has replied to your note`,
|
|
||||||
);
|
|
||||||
case NDKKind.Repost:
|
|
||||||
return await sendNativeNotification(
|
|
||||||
`${
|
|
||||||
profile.displayName || profile.name || "Anon"
|
|
||||||
} has reposted to your note`,
|
|
||||||
);
|
|
||||||
case NDKKind.Zap:
|
|
||||||
return await sendNativeNotification(
|
|
||||||
`${
|
|
||||||
profile.displayName || profile.name || "Anon"
|
|
||||||
} has zapped to your note`,
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
toast.error(String(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
setArk(ark);
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ndk) initArk();
|
async function setupArk() {
|
||||||
}, [ndk]);
|
const _ark = new Ark();
|
||||||
|
setArk(_ark);
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
if (!ark) setupArk();
|
||||||
if (!ark && !ndk) initNDK();
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!ark) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
data-tauri-drag-region
|
|
||||||
className="relative flex items-center justify-center w-screen h-screen bg-white dark:bg-black"
|
|
||||||
>
|
|
||||||
<div className="flex flex-col items-start max-w-2xl gap-1">
|
|
||||||
<h5 className="font-semibold uppercase">TIP:</h5>
|
|
||||||
<Linkify
|
|
||||||
options={{
|
|
||||||
target: "_blank",
|
|
||||||
className: "text-blue-500 hover:text-blue-600",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="text-4xl font-semibold leading-snug text-neutral-300 dark:text-neutral-700">
|
|
||||||
{QUOTES[Math.floor(Math.random() * QUOTES.length)]}
|
|
||||||
</div>
|
|
||||||
</Linkify>
|
|
||||||
</div>
|
|
||||||
<div className="absolute bottom-5 right-5 inline-flex items-center gap-2.5">
|
|
||||||
<LoaderIcon className="w-6 h-6 text-blue-500 animate-spin" />
|
|
||||||
<p className="font-semibold">Starting</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <LumeContext.Provider value={ark}>{children}</LumeContext.Provider>;
|
return <LumeContext.Provider value={ark}>{children}</LumeContext.Provider>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,6 +16,6 @@
|
|||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tailwindcss-radix-colors": "^1.2.0"
|
"@evilmartians/harmony": "^1.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import harmonyPalette from "@evilmartians/harmony/tailwind";
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
theme: {
|
theme: {
|
||||||
|
colors: harmonyPalette,
|
||||||
extend: {
|
extend: {
|
||||||
keyframes: {
|
keyframes: {
|
||||||
slideDownAndFade: {
|
slideDownAndFade: {
|
||||||
@@ -41,7 +44,6 @@ const config = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
require("tailwindcss-radix-colors"),
|
|
||||||
require("@tailwindcss/forms"),
|
require("@tailwindcss/forms"),
|
||||||
require("@tailwindcss/typography"),
|
require("@tailwindcss/typography"),
|
||||||
require("tailwind-scrollbar")({ nocompatible: true }),
|
require("tailwind-scrollbar")({ nocompatible: true }),
|
||||||
|
|||||||
72
packages/types/index.d.ts
vendored
72
packages/types/index.d.ts
vendored
@@ -1,8 +1,56 @@
|
|||||||
import {
|
import { type NDKEvent, type NDKUserProfile } from "@nostr-dev-kit/ndk";
|
||||||
type NDKEvent,
|
|
||||||
NDKRelayList,
|
export interface Keys {
|
||||||
type NDKUserProfile,
|
npub: string;
|
||||||
} from "@nostr-dev-kit/ndk";
|
nsec: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Kind {
|
||||||
|
Metadata = 0,
|
||||||
|
Text = 1,
|
||||||
|
RecommendRelay = 2,
|
||||||
|
Contacts = 3,
|
||||||
|
Repost = 6,
|
||||||
|
Reaction = 7,
|
||||||
|
// NIP-89: App Metadata
|
||||||
|
AppRecommendation = 31989,
|
||||||
|
AppHandler = 31990,
|
||||||
|
// #TODO: Add all nostr kinds
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Event {
|
||||||
|
id: string;
|
||||||
|
pubkey: string;
|
||||||
|
created_at: number;
|
||||||
|
kind: Kind;
|
||||||
|
tags: string[][];
|
||||||
|
content: string;
|
||||||
|
sig: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Metadata {
|
||||||
|
name: Option<string>;
|
||||||
|
display_name: Option<string>;
|
||||||
|
about: Option<string>;
|
||||||
|
website: Option<string>;
|
||||||
|
picture: Option<string>;
|
||||||
|
banner: Option<string>;
|
||||||
|
nip05: Option<string>;
|
||||||
|
lud06: Option<string>;
|
||||||
|
lud16: Option<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CurrentAccount {
|
||||||
|
npub: string;
|
||||||
|
contacts: string[];
|
||||||
|
interests: Interests;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Interests {
|
||||||
|
hashtags: string[];
|
||||||
|
users: string[];
|
||||||
|
words: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface RichContent {
|
export interface RichContent {
|
||||||
parsed: string;
|
parsed: string;
|
||||||
@@ -12,14 +60,6 @@ export interface RichContent {
|
|||||||
notes: string[];
|
notes: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Account {
|
|
||||||
id: string;
|
|
||||||
pubkey: string;
|
|
||||||
is_active: number;
|
|
||||||
contacts: string[];
|
|
||||||
relayList: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IColumn {
|
export interface IColumn {
|
||||||
id?: number;
|
id?: number;
|
||||||
kind: number;
|
kind: number;
|
||||||
@@ -115,9 +155,3 @@ export interface NIP05 {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Interests {
|
|
||||||
hashtags: string[];
|
|
||||||
users: string[];
|
|
||||||
words: string[];
|
|
||||||
}
|
|
||||||
|
|||||||
587
pnpm-lock.yaml
generated
587
pnpm-lock.yaml
generated
@@ -345,42 +345,30 @@ importers:
|
|||||||
'@lume/icons':
|
'@lume/icons':
|
||||||
specifier: workspace:^
|
specifier: workspace:^
|
||||||
version: link:../icons
|
version: link:../icons
|
||||||
'@lume/ndk-cache-tauri':
|
|
||||||
specifier: workspace:^
|
|
||||||
version: link:../ndk-cache-tauri
|
|
||||||
'@lume/storage':
|
|
||||||
specifier: workspace:^
|
|
||||||
version: link:../storage
|
|
||||||
'@lume/utils':
|
'@lume/utils':
|
||||||
specifier: workspace:^
|
specifier: workspace:^
|
||||||
version: link:../utils
|
version: link:../utils
|
||||||
'@nostr-dev-kit/ndk':
|
|
||||||
specifier: ^2.4.0
|
|
||||||
version: 2.4.0(typescript@5.3.3)
|
|
||||||
'@nostr-fetch/adapter-ndk':
|
|
||||||
specifier: ^0.15.0
|
|
||||||
version: 0.15.0(@nostr-dev-kit/ndk@2.4.0)(nostr-fetch@0.15.0)
|
|
||||||
'@radix-ui/react-avatar':
|
'@radix-ui/react-avatar':
|
||||||
specifier: ^1.0.4
|
specifier: ^1.0.4
|
||||||
version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
version: 1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@radix-ui/react-collapsible':
|
'@radix-ui/react-collapsible':
|
||||||
specifier: ^1.0.3
|
specifier: ^1.0.3
|
||||||
version: 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
version: 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@radix-ui/react-dialog':
|
'@radix-ui/react-dialog':
|
||||||
specifier: ^1.0.5
|
specifier: ^1.0.5
|
||||||
version: 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
version: 1.0.5(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@radix-ui/react-dropdown-menu':
|
'@radix-ui/react-dropdown-menu':
|
||||||
specifier: ^2.0.6
|
specifier: ^2.0.6
|
||||||
version: 2.0.6(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
version: 2.0.6(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@radix-ui/react-hover-card':
|
'@radix-ui/react-hover-card':
|
||||||
specifier: ^1.0.7
|
specifier: ^1.0.7
|
||||||
version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
version: 1.0.7(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@radix-ui/react-popover':
|
'@radix-ui/react-popover':
|
||||||
specifier: ^1.0.7
|
specifier: ^1.0.7
|
||||||
version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
version: 1.0.7(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@radix-ui/react-tooltip':
|
'@radix-ui/react-tooltip':
|
||||||
specifier: ^1.0.7
|
specifier: ^1.0.7
|
||||||
version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
version: 1.0.7(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: ^5.18.1
|
specifier: ^5.18.1
|
||||||
version: 5.18.1(react@18.2.0)
|
version: 5.18.1(react@18.2.0)
|
||||||
@@ -390,12 +378,6 @@ importers:
|
|||||||
jotai:
|
jotai:
|
||||||
specifier: ^2.6.4
|
specifier: ^2.6.4
|
||||||
version: 2.6.4(@types/react@18.2.52)(react@18.2.0)
|
version: 2.6.4(@types/react@18.2.52)(react@18.2.0)
|
||||||
linkify-react:
|
|
||||||
specifier: ^4.1.3
|
|
||||||
version: 4.1.3(linkifyjs@4.1.3)(react@18.2.0)
|
|
||||||
linkifyjs:
|
|
||||||
specifier: ^4.1.3
|
|
||||||
version: 4.1.3
|
|
||||||
media-chrome:
|
media-chrome:
|
||||||
specifier: ^2.1.0
|
specifier: ^2.1.0
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
@@ -405,12 +387,6 @@ importers:
|
|||||||
nanoid:
|
nanoid:
|
||||||
specifier: ^5.0.5
|
specifier: ^5.0.5
|
||||||
version: 5.0.5
|
version: 5.0.5
|
||||||
nostr-fetch:
|
|
||||||
specifier: ^0.15.0
|
|
||||||
version: 0.15.0
|
|
||||||
nostr-tools:
|
|
||||||
specifier: 1.17.0
|
|
||||||
version: 1.17.0(typescript@5.3.3)
|
|
||||||
qrcode.react:
|
qrcode.react:
|
||||||
specifier: ^3.1.0
|
specifier: ^3.1.0
|
||||||
version: 3.1.0(react@18.2.0)
|
version: 3.1.0(react@18.2.0)
|
||||||
@@ -438,12 +414,6 @@ importers:
|
|||||||
string-strip-html:
|
string-strip-html:
|
||||||
specifier: ^13.4.6
|
specifier: ^13.4.6
|
||||||
version: 13.4.6
|
version: 13.4.6
|
||||||
tippy.js:
|
|
||||||
specifier: ^6.3.7
|
|
||||||
version: 6.3.7
|
|
||||||
use-context-selector:
|
|
||||||
specifier: ^1.4.1
|
|
||||||
version: 1.4.1(react-dom@18.2.0)(react@18.2.0)(scheduler@0.23.0)
|
|
||||||
virtua:
|
virtua:
|
||||||
specifier: ^0.23.3
|
specifier: ^0.23.3
|
||||||
version: 0.23.3(react-dom@18.2.0)(react@18.2.0)
|
version: 0.23.3(react-dom@18.2.0)(react@18.2.0)
|
||||||
@@ -460,9 +430,6 @@ importers:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: ^18.2.52
|
specifier: ^18.2.52
|
||||||
version: 18.2.52
|
version: 18.2.52
|
||||||
tailwind-merge:
|
|
||||||
specifier: ^2.2.1
|
|
||||||
version: 2.2.1
|
|
||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: ^3.4.1
|
specifier: ^3.4.1
|
||||||
version: 3.4.1
|
version: 3.4.1
|
||||||
@@ -1110,9 +1077,9 @@ importers:
|
|||||||
|
|
||||||
packages/tailwindcss:
|
packages/tailwindcss:
|
||||||
dependencies:
|
dependencies:
|
||||||
tailwindcss-radix-colors:
|
'@evilmartians/harmony':
|
||||||
specifier: ^1.2.0
|
specifier: ^1.2.0
|
||||||
version: 1.2.0(tailwindcss@3.4.1)
|
version: 1.2.0
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@tailwindcss/forms':
|
'@tailwindcss/forms':
|
||||||
specifier: ^0.5.7
|
specifier: ^0.5.7
|
||||||
@@ -2275,6 +2242,10 @@ packages:
|
|||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
/@evilmartians/harmony@1.2.0:
|
||||||
|
resolution: {integrity: sha512-Ua8gpC+28Eo9D2/xynTrrZIrSawgtobwtRLLYq4wH8N19qoMspWZ1vqfsDDVPgQFa+iHsVAk/SbdmoPAj6OH1g==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@floating-ui/core@1.6.0:
|
/@floating-ui/core@1.6.0:
|
||||||
resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==}
|
resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -2452,17 +2423,6 @@ packages:
|
|||||||
- typescript
|
- typescript
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@nostr-fetch/adapter-ndk@0.15.0(@nostr-dev-kit/ndk@2.4.0)(nostr-fetch@0.15.0):
|
|
||||||
resolution: {integrity: sha512-Mug2yTmX4n4hFWfQV1GWiXZd88PbfbsT29lOtM5/sM59a+eYXeYvNmHddxmk2dK5VAdlT2VwKdHEmebzko6Y7w==}
|
|
||||||
peerDependencies:
|
|
||||||
'@nostr-dev-kit/ndk': ^1.0.0
|
|
||||||
nostr-fetch: ^0.15.0
|
|
||||||
dependencies:
|
|
||||||
'@nostr-dev-kit/ndk': 2.4.0(typescript@5.3.3)
|
|
||||||
'@nostr-fetch/kernel': 0.15.0
|
|
||||||
nostr-fetch: 0.15.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@nostr-fetch/kernel@0.15.0:
|
/@nostr-fetch/kernel@0.15.0:
|
||||||
resolution: {integrity: sha512-Sq3PjSUrPSK9uJzq2yPDe/xMVdcn5PkYxRo6KKBykigefYcuQqk9ulXxUX/Z2FyvsN3QcY+3aEwKsgaQcC+TiA==}
|
resolution: {integrity: sha512-Sq3PjSUrPSK9uJzq2yPDe/xMVdcn5PkYxRo6KKBykigefYcuQqk9ulXxUX/Z2FyvsN3QcY+3aEwKsgaQcC+TiA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -2521,14 +2481,6 @@ packages:
|
|||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@popperjs/core@2.11.8:
|
|
||||||
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@radix-ui/colors@3.0.0:
|
|
||||||
resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@radix-ui/number@1.0.1:
|
/@radix-ui/number@1.0.1:
|
||||||
resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==}
|
resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -2617,6 +2569,26 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-arrow@1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-avatar@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-avatar@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-kVK2K7ZD3wwj3qhle0ElXhOjbezIgyl2hVvgwfIdexL3rN6zJmy5AqqIf+D31lxVppdzV8CjAfZ6PklkmInZLw==}
|
resolution: {integrity: sha512-kVK2K7ZD3wwj3qhle0ElXhOjbezIgyl2hVvgwfIdexL3rN6zJmy5AqqIf+D31lxVppdzV8CjAfZ6PklkmInZLw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2641,6 +2613,29 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-avatar@1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-kVK2K7ZD3wwj3qhle0ElXhOjbezIgyl2hVvgwfIdexL3rN6zJmy5AqqIf+D31lxVppdzV8CjAfZ6PklkmInZLw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-checkbox@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-checkbox@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==}
|
resolution: {integrity: sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2697,6 +2692,33 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-collapsible@1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-id': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-presence': 1.0.1(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==}
|
resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2721,6 +2743,29 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-collection@1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.52)(react@18.2.0):
|
/@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.52)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
|
resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2783,6 +2828,39 @@ packages:
|
|||||||
react-remove-scroll: 2.5.5(@types/react@18.2.52)(react@18.2.0)
|
react-remove-scroll: 2.5.5(@types/react@18.2.52)(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-dialog@1.0.5(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-dismissable-layer': 1.0.5(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-focus-scope': 1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-id': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-portal': 1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-presence': 1.0.1(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
aria-hidden: 1.2.3
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
react-remove-scroll: 2.5.5(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-direction@1.0.1(@types/react@18.2.52)(react@18.2.0):
|
/@radix-ui/react-direction@1.0.1(@types/react@18.2.52)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==}
|
resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2822,6 +2900,30 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-dismissable-layer@1.0.5(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-dropdown-menu@2.0.6(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-dropdown-menu@2.0.6(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA==}
|
resolution: {integrity: sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2849,6 +2951,32 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-dropdown-menu@2.0.6(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-id': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-menu': 2.0.6(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.52)(react@18.2.0):
|
/@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.52)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==}
|
resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2886,6 +3014,28 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-focus-scope@1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-hover-card@1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-hover-card@1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-OcUN2FU0YpmajD/qkph3XzMcK/NmSk9hGWnjV68p6QiZMgILugusgQwnLSDs3oFSJYGKf3Y49zgFedhGh04k9A==}
|
resolution: {integrity: sha512-OcUN2FU0YpmajD/qkph3XzMcK/NmSk9hGWnjV68p6QiZMgILugusgQwnLSDs3oFSJYGKf3Y49zgFedhGh04k9A==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2915,6 +3065,34 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-hover-card@1.0.7(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-OcUN2FU0YpmajD/qkph3XzMcK/NmSk9hGWnjV68p6QiZMgILugusgQwnLSDs3oFSJYGKf3Y49zgFedhGh04k9A==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-dismissable-layer': 1.0.5(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-popper': 1.1.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-portal': 1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-presence': 1.0.1(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-id@1.0.1(@types/react@18.2.52)(react@18.2.0):
|
/@radix-ui/react-id@1.0.1(@types/react@18.2.52)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==}
|
resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2968,6 +3146,43 @@ packages:
|
|||||||
react-remove-scroll: 2.5.5(@types/react@18.2.52)(react@18.2.0)
|
react-remove-scroll: 2.5.5(@types/react@18.2.52)(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-menu@2.0.6(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-collection': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-direction': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-dismissable-layer': 1.0.5(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-focus-scope': 1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-id': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-popper': 1.1.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-portal': 1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-presence': 1.0.1(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-roving-focus': 1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
aria-hidden: 1.2.3
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
react-remove-scroll: 2.5.5(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-popover@1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-popover@1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ==}
|
resolution: {integrity: sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3003,6 +3218,40 @@ packages:
|
|||||||
react-remove-scroll: 2.5.5(@types/react@18.2.52)(react@18.2.0)
|
react-remove-scroll: 2.5.5(@types/react@18.2.52)(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-popover@1.0.7(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-dismissable-layer': 1.0.5(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-focus-scope': 1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-id': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-popper': 1.1.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-portal': 1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-presence': 1.0.1(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
aria-hidden: 1.2.3
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
react-remove-scroll: 2.5.5(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==}
|
resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3033,6 +3282,35 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-popper@1.1.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@floating-ui/react-dom': 2.0.8(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-arrow': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-size': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/rect': 1.0.1
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==}
|
resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3054,6 +3332,26 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-portal@1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==}
|
resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3076,6 +3374,27 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-presence@1.0.1(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==}
|
resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3097,6 +3416,26 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-primitive@1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==}
|
resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3126,6 +3465,34 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-roving-focus@1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-collection': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-direction': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-id': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-select@2.0.0(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-select@2.0.0(@types/react-dom@18.2.18)(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-RH5b7af4oHtkcHS7pG6Sgv5rk5Wxa7XI8W5gvB1N/yiuDGZxko1ynvOiVhFM7Cis2A8zxF9bTOUVbRDzPepe6w==}
|
resolution: {integrity: sha512-RH5b7af4oHtkcHS7pG6Sgv5rk5Wxa7XI8W5gvB1N/yiuDGZxko1ynvOiVhFM7Cis2A8zxF9bTOUVbRDzPepe6w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3241,6 +3608,37 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-tooltip@1.0.7(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-dismissable-layer': 1.0.5(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-id': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-popper': 1.1.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-portal': 1.0.4(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-presence': 1.0.1(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.52)(react@18.2.0)
|
||||||
|
'@radix-ui/react-visually-hidden': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.52)(react@18.2.0):
|
/@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.52)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
|
resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3364,6 +3762,26 @@ packages:
|
|||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-visually-hidden@1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.23.9
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react@18.2.52)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.52
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/rect@1.0.1:
|
/@radix-ui/rect@1.0.1:
|
||||||
resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==}
|
resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -6474,20 +6892,6 @@ packages:
|
|||||||
/lines-and-columns@1.2.4:
|
/lines-and-columns@1.2.4:
|
||||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||||
|
|
||||||
/linkify-react@4.1.3(linkifyjs@4.1.3)(react@18.2.0):
|
|
||||||
resolution: {integrity: sha512-rhI3zM/fxn5BfRPHfi4r9N7zgac4vOIxub1wHIWXLA5ENTMs+BGaIaFO1D1PhmxgwhIKmJz3H7uCP0Dg5JwSlA==}
|
|
||||||
peerDependencies:
|
|
||||||
linkifyjs: ^4.0.0
|
|
||||||
react: '>= 15.0.0'
|
|
||||||
dependencies:
|
|
||||||
linkifyjs: 4.1.3
|
|
||||||
react: 18.2.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/linkifyjs@4.1.3:
|
|
||||||
resolution: {integrity: sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/load-yaml-file@0.2.0:
|
/load-yaml-file@0.2.0:
|
||||||
resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==}
|
resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -9367,15 +9771,6 @@ packages:
|
|||||||
tailwindcss: 3.4.1
|
tailwindcss: 3.4.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/tailwindcss-radix-colors@1.2.0(tailwindcss@3.4.1):
|
|
||||||
resolution: {integrity: sha512-2rr3l7NV89UEwRTJFN4LlQIm5aasi7OZeJFF7iaDJ2hKwylR8BNMAC6GoiDl0G7wq18keN1YQ3V5sMbvtREO6w==}
|
|
||||||
peerDependencies:
|
|
||||||
tailwindcss: '>=3.0.0'
|
|
||||||
dependencies:
|
|
||||||
'@radix-ui/colors': 3.0.0
|
|
||||||
tailwindcss: 3.4.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/tailwindcss@3.4.1:
|
/tailwindcss@3.4.1:
|
||||||
resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==}
|
resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@@ -9491,12 +9886,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
|
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/tippy.js@6.3.7:
|
|
||||||
resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==}
|
|
||||||
dependencies:
|
|
||||||
'@popperjs/core': 2.11.8
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/tlds@1.249.0:
|
/tlds@1.249.0:
|
||||||
resolution: {integrity: sha512-PfcE+oqaEhs0U3RDNg4uGg37793cGvlK6+aLAetwR0ImFyV3R2ts1KvU2RfJdtoLn7IFnUEftFFz4br5Wr3caA==}
|
resolution: {integrity: sha512-PfcE+oqaEhs0U3RDNg4uGg37793cGvlK6+aLAetwR0ImFyV3R2ts1KvU2RfJdtoLn7IFnUEftFFz4br5Wr3caA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -9880,24 +10269,6 @@ packages:
|
|||||||
tslib: 2.6.2
|
tslib: 2.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/use-context-selector@1.4.1(react-dom@18.2.0)(react@18.2.0)(scheduler@0.23.0):
|
|
||||||
resolution: {integrity: sha512-Io2ArvcRO+6MWIhkdfMFt+WKQX+Vb++W8DS2l03z/Vw/rz3BclKpM0ynr4LYGyU85Eke+Yx5oIhTY++QR0ZDoA==}
|
|
||||||
peerDependencies:
|
|
||||||
react: '>=16.8.0'
|
|
||||||
react-dom: '*'
|
|
||||||
react-native: '*'
|
|
||||||
scheduler: '>=0.19.0'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
react-dom:
|
|
||||||
optional: true
|
|
||||||
react-native:
|
|
||||||
optional: true
|
|
||||||
dependencies:
|
|
||||||
react: 18.2.0
|
|
||||||
react-dom: 18.2.0(react@18.2.0)
|
|
||||||
scheduler: 0.23.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/use-debounce@10.0.0(react@18.2.0):
|
/use-debounce@10.0.0(react@18.2.0):
|
||||||
resolution: {integrity: sha512-XRjvlvCB46bah9IBXVnq/ACP2lxqXyZj0D9hj4K5OzNroMDpTEBg8Anuh1/UfRTRs7pLhQ+RiNxxwZu9+MVl1A==}
|
resolution: {integrity: sha512-XRjvlvCB46bah9IBXVnq/ACP2lxqXyZj0D9hj4K5OzNroMDpTEBg8Anuh1/UfRTRs7pLhQ+RiNxxwZu9+MVl1A==}
|
||||||
engines: {node: '>= 16.0.0'}
|
engines: {node: '>= 16.0.0'}
|
||||||
|
|||||||
41
src-tauri/capabilities/main.json
Normal file
41
src-tauri/capabilities/main.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"$schema": "../gen/schemas/desktop-schema.json",
|
||||||
|
"identifier": "desktop-capability",
|
||||||
|
"description": "Capability for the desktop",
|
||||||
|
"platforms": ["linux", "macOS", "windows"],
|
||||||
|
"windows": ["main", "settings", "event-*", "user-*", "column-*"],
|
||||||
|
"permissions": [
|
||||||
|
"path:default",
|
||||||
|
"event:default",
|
||||||
|
"window:default",
|
||||||
|
"app:default",
|
||||||
|
"resources:default",
|
||||||
|
"menu:default",
|
||||||
|
"tray:default",
|
||||||
|
"theme:allow-set-theme",
|
||||||
|
"theme:allow-get-theme",
|
||||||
|
"notification:allow-is-permission-granted",
|
||||||
|
"notification:allow-request-permission",
|
||||||
|
"notification:default",
|
||||||
|
"os:allow-locale",
|
||||||
|
{
|
||||||
|
"identifier": "http:default",
|
||||||
|
"allow": [
|
||||||
|
{
|
||||||
|
"url": "http://**/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://**/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identifier": "fs:allow-read-text-file",
|
||||||
|
"allow": [
|
||||||
|
{
|
||||||
|
"path": "$RESOURCE/locales/*"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "./schemas/desktop-schema.json",
|
|
||||||
"identifier": "desktop-capability",
|
|
||||||
"description": "Capability for the desktop",
|
|
||||||
"platforms": ["linux", "macOS", "windows"],
|
|
||||||
"windows": ["main", "settings", "event-*", "user-*", "column-*"],
|
|
||||||
"permissions": [
|
|
||||||
"path:default",
|
|
||||||
"event:default",
|
|
||||||
"window:default",
|
|
||||||
"app:default",
|
|
||||||
"resources:default",
|
|
||||||
"menu:default",
|
|
||||||
"tray:default",
|
|
||||||
"shell:open",
|
|
||||||
"theme:allow-set-theme",
|
|
||||||
"theme:allow-get-theme",
|
|
||||||
"notification:allow-is-permission-granted",
|
|
||||||
"notification:allow-request-permission",
|
|
||||||
"notification:allow-notify",
|
|
||||||
{
|
|
||||||
"identifier": "http:default",
|
|
||||||
"allow": [
|
|
||||||
{
|
|
||||||
"url": "http://**/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://**/"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identifier": "fs:scope",
|
|
||||||
"allow": [
|
|
||||||
{
|
|
||||||
"path": "$APPDATA/*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "$LOCALDATA/*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "$DESKTOP/*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "$DOCUMENT/*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "$DOWNLOAD/*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "$HOME/*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "$PICTURE/*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "$PUBLIC/*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "$VIDEO/*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "$RESOURCE"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "$RESOURCE/*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "$RESOURCE/locales/*"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1 +1 @@
|
|||||||
{}
|
{"desktop-capability":{"identifier":"desktop-capability","description":"Capability for the desktop","context":"local","windows":["main","settings","event-*","user-*","column-*"],"permissions":["path:default","event:default","window:default","app:default","resources:default","menu:default","tray:default","theme:allow-set-theme","theme:allow-get-theme","notification:allow-is-permission-granted","notification:allow-request-permission","notification:default","os:allow-locale",{"identifier":"http:default","allow":[{"url":"http://**/"},{"url":"https://**/"}]},{"identifier":"fs:allow-read-text-file","allow":[{"path":"$RESOURCE/locales/*"}]}],"platforms":["linux","macOS","windows"]}}
|
||||||
@@ -13,11 +13,13 @@ use db::api::v1::Account;
|
|||||||
use keyring::Entry;
|
use keyring::Entry;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
use tauri_plugin_autostart::MacosLauncher;
|
use tauri_plugin_autostart::MacosLauncher;
|
||||||
|
|
||||||
pub struct Nostr {
|
pub struct Nostr {
|
||||||
pub client: Arc<Client>,
|
pub client: Arc<Client>,
|
||||||
|
pub contact_list: Option<Vec<Contact>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -28,7 +30,7 @@ fn main() {
|
|||||||
let config_dir = handle.path().app_config_dir().unwrap();
|
let config_dir = handle.path().app_config_dir().unwrap();
|
||||||
|
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
// Create database connection
|
// Create nostr database connection
|
||||||
let nostr_db = SQLiteDatabase::open(config_dir.join("nostr.db"))
|
let nostr_db = SQLiteDatabase::open(config_dir.join("nostr.db"))
|
||||||
.await
|
.await
|
||||||
.expect("Open database failed.");
|
.expect("Open database failed.");
|
||||||
@@ -36,40 +38,18 @@ fn main() {
|
|||||||
// Create nostr connection
|
// Create nostr connection
|
||||||
let client = ClientBuilder::default().database(nostr_db).build();
|
let client = ClientBuilder::default().database(nostr_db).build();
|
||||||
|
|
||||||
// create app database connection
|
// Create app database connection
|
||||||
let db = DATABASE_BUILDER
|
let db = DATABASE_BUILDER
|
||||||
.create(config_dir.join("app.db"))
|
.create(config_dir.join("app.db"))
|
||||||
.expect("failed to create app database");
|
.expect("failed to create app database");
|
||||||
|
|
||||||
// run db migrate
|
// Run migration for app database
|
||||||
let rw = db
|
let rw = db
|
||||||
.rw_transaction()
|
.rw_transaction()
|
||||||
.expect("failed to create rw migration transaction");
|
.expect("failed to create rw migration transaction");
|
||||||
rw.migrate::<Account>().expect("failed to migrate Account");
|
rw.migrate::<Account>().expect("failed to migrate Account");
|
||||||
rw.commit().expect("failed to commit migration");
|
rw.commit().expect("failed to commit migration");
|
||||||
|
|
||||||
// get stored account
|
|
||||||
let r = db.r_transaction().expect("failed to create ro transaction");
|
|
||||||
let accounts: Vec<Account> = r
|
|
||||||
.scan()
|
|
||||||
.secondary(AccountKey::status)
|
|
||||||
.expect("failed to scan accounts")
|
|
||||||
.start_with("active")
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if let Some(account) = accounts.into_iter().nth(0) {
|
|
||||||
let entry = Entry::new("Lume", &account.pubkey).expect("failed to load secret");
|
|
||||||
|
|
||||||
if let Ok(key) = entry.get_password() {
|
|
||||||
let secret_key = SecretKey::from_bech32(key).unwrap();
|
|
||||||
let keys = Keys::new(secret_key);
|
|
||||||
let signer = ClientSigner::Keys(keys);
|
|
||||||
|
|
||||||
// update client's signer
|
|
||||||
client.set_signer(Some(signer)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add some bootstrap relays
|
// Add some bootstrap relays
|
||||||
// #TODO: Pull bootstrap relays from user's settings
|
// #TODO: Pull bootstrap relays from user's settings
|
||||||
client
|
client
|
||||||
@@ -84,9 +64,43 @@ fn main() {
|
|||||||
// Connect
|
// Connect
|
||||||
client.connect().await;
|
client.connect().await;
|
||||||
|
|
||||||
|
// Get stored account
|
||||||
|
let r = db.r_transaction().expect("failed to create ro transaction");
|
||||||
|
let accounts: Vec<Account> = r
|
||||||
|
.scan()
|
||||||
|
.secondary(AccountKey::status)
|
||||||
|
.expect("failed to scan accounts")
|
||||||
|
.start_with("active")
|
||||||
|
.collect();
|
||||||
|
let mut contact_list = None;
|
||||||
|
|
||||||
|
// Run somethings if account existed
|
||||||
|
if let Some(account) = accounts.into_iter().nth(0) {
|
||||||
|
// Add signer with stored private key
|
||||||
|
let entry = Entry::new("Lume", &account.pubkey).expect("failed to load secret");
|
||||||
|
|
||||||
|
if let Ok(key) = entry.get_password() {
|
||||||
|
let secret_key = SecretKey::from_bech32(key).unwrap();
|
||||||
|
let keys = Keys::new(secret_key);
|
||||||
|
let signer = ClientSigner::Keys(keys);
|
||||||
|
|
||||||
|
// Update client's signer
|
||||||
|
client.set_signer(Some(signer)).await;
|
||||||
|
|
||||||
|
// Get contact list
|
||||||
|
contact_list = Some(
|
||||||
|
client
|
||||||
|
.get_contact_list(Some(Duration::from_secs(10)))
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Init global state
|
// Init global state
|
||||||
handle.manage(Nostr {
|
handle.manage(Nostr {
|
||||||
client: client.into(),
|
client: client.into(),
|
||||||
|
contact_list: contact_list.into(),
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -113,6 +127,8 @@ fn main() {
|
|||||||
nostr::keys::get_public_key,
|
nostr::keys::get_public_key,
|
||||||
nostr::keys::update_signer,
|
nostr::keys::update_signer,
|
||||||
nostr::keys::verify_signer,
|
nostr::keys::verify_signer,
|
||||||
|
nostr::keys::event_to_bech32,
|
||||||
|
nostr::keys::user_to_bech32,
|
||||||
nostr::metadata::get_metadata,
|
nostr::metadata::get_metadata,
|
||||||
nostr::event::get_event,
|
nostr::event::get_event,
|
||||||
commands::secret::secure_save,
|
commands::secret::secure_save,
|
||||||
|
|||||||
@@ -4,17 +4,26 @@ use std::time::Duration;
|
|||||||
use tauri::State;
|
use tauri::State;
|
||||||
|
|
||||||
#[tauri::command(async)]
|
#[tauri::command(async)]
|
||||||
pub async fn get_event(id: String, nostr: State<'_, Nostr>) -> Result<String, ()> {
|
pub async fn get_event(id: &str, nostr: State<'_, Nostr>) -> Result<String, ()> {
|
||||||
let client = &nostr.client;
|
let client = &nostr.client;
|
||||||
|
let event_id;
|
||||||
|
|
||||||
|
if id.starts_with("note1") {
|
||||||
|
event_id = EventId::from_bech32(id).unwrap();
|
||||||
|
} else if id.starts_with("nevent1") {
|
||||||
|
event_id = EventId::from_bech32(id).unwrap();
|
||||||
|
} else if id.starts_with("naddr1") {
|
||||||
|
event_id = EventId::from_bech32(id).unwrap();
|
||||||
|
} else {
|
||||||
|
event_id = EventId::from_hex(id).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
let event_id = EventId::from_bech32(id).unwrap();
|
|
||||||
let filter = Filter::new().id(event_id);
|
let filter = Filter::new().id(event_id);
|
||||||
|
|
||||||
let events = client
|
let events = client
|
||||||
.get_events_of(vec![filter], Some(Duration::from_secs(10)))
|
.get_events_of(vec![filter], Some(Duration::from_secs(10)))
|
||||||
.await
|
.await
|
||||||
.expect("Get metadata failed");
|
.expect("Get event failed");
|
||||||
let event = events.into_iter().nth(0).unwrap().as_json();
|
let event = events.first().unwrap().as_json();
|
||||||
|
|
||||||
Ok(event)
|
Ok(event)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::Nostr;
|
use crate::Nostr;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
|
use std::str::FromStr;
|
||||||
use tauri::State;
|
use tauri::State;
|
||||||
|
|
||||||
#[derive(serde::Serialize)]
|
#[derive(serde::Serialize)]
|
||||||
@@ -23,15 +24,16 @@ pub fn create_keys() -> Result<CreateKeysResponse, ()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_public_key(secret_key: SecretKey) -> Result<String, ()> {
|
pub fn get_public_key(nsec: String) -> Result<String, ()> {
|
||||||
|
let secret_key = SecretKey::from_bech32(nsec).unwrap();
|
||||||
let keys = Keys::new(secret_key);
|
let keys = Keys::new(secret_key);
|
||||||
Ok(keys.public_key().to_bech32().expect("secret key failed"))
|
Ok(keys.public_key().to_bech32().expect("secret key failed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn update_signer(key: String, nostr: State<'_, Nostr>) -> Result<(), ()> {
|
pub async fn update_signer(nsec: String, nostr: State<'_, Nostr>) -> Result<(), ()> {
|
||||||
let client = &nostr.client;
|
let client = &nostr.client;
|
||||||
let secret_key = SecretKey::from_bech32(key).unwrap();
|
let secret_key = SecretKey::from_bech32(nsec).unwrap();
|
||||||
let keys = Keys::new(secret_key);
|
let keys = Keys::new(secret_key);
|
||||||
let signer = ClientSigner::Keys(keys);
|
let signer = ClientSigner::Keys(keys);
|
||||||
|
|
||||||
@@ -47,3 +49,19 @@ pub async fn verify_signer(nostr: State<'_, Nostr>) -> Result<bool, ()> {
|
|||||||
|
|
||||||
Ok(status)
|
Ok(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn event_to_bech32(id: &str, relays: Vec<String>) -> Result<String, ()> {
|
||||||
|
let event_id = EventId::from_hex(id).unwrap();
|
||||||
|
let event = Nip19Event::new(event_id, relays);
|
||||||
|
|
||||||
|
Ok(event.to_bech32().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn user_to_bech32(key: &str, relays: Vec<String>) -> Result<String, ()> {
|
||||||
|
let pubkey = XOnlyPublicKey::from_str(key).unwrap();
|
||||||
|
let profile = Nip19Profile::new(pubkey, relays);
|
||||||
|
|
||||||
|
Ok(profile.to_bech32().unwrap())
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
use crate::Nostr;
|
use crate::Nostr;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use std::time::Duration;
|
use std::{str::FromStr, time::Duration};
|
||||||
use tauri::State;
|
use tauri::State;
|
||||||
|
|
||||||
#[tauri::command(async)]
|
#[tauri::command(async)]
|
||||||
pub async fn get_metadata(npub: String, nostr: State<'_, Nostr>) -> Result<Metadata, ()> {
|
pub async fn get_metadata(id: &str, nostr: State<'_, Nostr>) -> Result<Metadata, ()> {
|
||||||
let client = &nostr.client;
|
let client = &nostr.client;
|
||||||
|
let public_key;
|
||||||
|
|
||||||
let public_key = XOnlyPublicKey::from_bech32(npub).unwrap();
|
if id.starts_with("nprofile1") {
|
||||||
|
public_key = XOnlyPublicKey::from_bech32(id).unwrap();
|
||||||
|
} else if id.starts_with("npub1") {
|
||||||
|
public_key = XOnlyPublicKey::from_bech32(id).unwrap();
|
||||||
|
} else {
|
||||||
|
public_key = XOnlyPublicKey::from_str(id).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
let filter = Filter::new()
|
let filter = Filter::new()
|
||||||
.author(public_key)
|
.author(public_key)
|
||||||
@@ -19,7 +26,7 @@ pub async fn get_metadata(npub: String, nostr: State<'_, Nostr>) -> Result<Metad
|
|||||||
.await
|
.await
|
||||||
.expect("Get metadata failed");
|
.expect("Get metadata failed");
|
||||||
|
|
||||||
let event = events.into_iter().nth(0).unwrap();
|
let event = events.first().unwrap();
|
||||||
let metadata: Metadata = Metadata::from_json(&event.content).unwrap();
|
let metadata: Metadata = Metadata::from_json(&event.content).unwrap();
|
||||||
|
|
||||||
Ok(metadata)
|
Ok(metadata)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"build": {
|
"build": {
|
||||||
"beforeBuildCommand": "pnpm run build",
|
"beforeBuildCommand": "pnpm run build",
|
||||||
"beforeDevCommand": "pnpm desktop:dev",
|
"beforeDevCommand": "pnpm desktop:dev",
|
||||||
"devUrl": "http://localhost:5173",
|
"devUrl": "http://localhost:3000",
|
||||||
"frontendDist": "../dist"
|
"frontendDist": "../dist"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
@@ -42,10 +42,7 @@
|
|||||||
"targets": "all",
|
"targets": "all",
|
||||||
"active": true,
|
"active": true,
|
||||||
"category": "SocialNetworking",
|
"category": "SocialNetworking",
|
||||||
"resources": [
|
"resources": ["resources/*", "./locales/*"],
|
||||||
"resources/*",
|
|
||||||
"./locales/*"
|
|
||||||
],
|
|
||||||
"icon": [
|
"icon": [
|
||||||
"icons/32x32.png",
|
"icons/32x32.png",
|
||||||
"icons/128x128.png",
|
"icons/128x128.png",
|
||||||
|
|||||||
Reference in New Issue
Block a user