use applesauce-react

This commit is contained in:
hzrd149
2024-10-03 14:20:07 -05:00
parent e0e2ed9724
commit 8c6ecb8f19
9 changed files with 96 additions and 101 deletions

View File

@@ -42,9 +42,10 @@
"@uiw/codemirror-theme-github": "^4.23.0", "@uiw/codemirror-theme-github": "^4.23.0",
"@uiw/react-codemirror": "^4.23.0", "@uiw/react-codemirror": "^4.23.0",
"@webscopeio/react-textarea-autocomplete": "^4.9.2", "@webscopeio/react-textarea-autocomplete": "^4.9.2",
"applesauce-channel": "^0.5.0", "applesauce-channel": "^0.6.0",
"applesauce-core": "^0.5.0", "applesauce-core": "^0.6.0",
"applesauce-signer": "^0.5.0", "applesauce-react": "^0.6.0",
"applesauce-signer": "^0.6.0",
"bech32": "^2.0.0", "bech32": "^2.0.0",
"blossom-client-sdk": "^0.7.0", "blossom-client-sdk": "^0.7.0",
"blossom-drive-sdk": "^0.4.0", "blossom-drive-sdk": "^0.4.0",

50
pnpm-lock.yaml generated
View File

@@ -91,14 +91,17 @@ importers:
specifier: ^4.9.2 specifier: ^4.9.2
version: 4.9.2(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 4.9.2(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
applesauce-channel: applesauce-channel:
specifier: ^0.5.0 specifier: ^0.6.0
version: 0.5.0(typescript@5.6.2) version: 0.6.0(typescript@5.6.2)
applesauce-core: applesauce-core:
specifier: ^0.5.0 specifier: ^0.6.0
version: 0.5.0(typescript@5.6.2) version: 0.6.0(typescript@5.6.2)
applesauce-react:
specifier: ^0.6.0
version: 0.6.0(typescript@5.6.2)
applesauce-signer: applesauce-signer:
specifier: ^0.5.0 specifier: ^0.6.0
version: 0.5.0(typescript@5.6.2) version: 0.6.0(typescript@5.6.2)
bech32: bech32:
specifier: ^2.0.0 specifier: ^2.0.0
version: 2.0.0 version: 2.0.0
@@ -2283,14 +2286,17 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'} engines: {node: '>=8'}
applesauce-channel@0.5.0: applesauce-channel@0.6.0:
resolution: {integrity: sha512-0B4ldPKzO7RFfWpOyQnqf1JIAk2JKTx88atSGPtbZGYWM9kfG2FzBIEaaamKbQ12dfZqNzZRWvCFMww+5jX1Eg==} resolution: {integrity: sha512-tHKHzTIBWdNoiAAet4oBg60yucLy+cmvev8dBvd6iNCr/BrxzciMj7m7YszQti7XxcGVd9GBQ23UtrT17peTXQ==}
applesauce-core@0.5.0: applesauce-core@0.6.0:
resolution: {integrity: sha512-PqjiTsxBWnrlyBe9mP5KNJs9L7AQjrqWJoj/F52IqxdYgGjli3FubfV/lwjq+UQzwK22CMiwPoxTG3jLDlfpaw==} resolution: {integrity: sha512-23W/7P0hzjVGIp51Yp4ppJgbDFNtrJrF3HO3/M36/z+Msdb3HKiSXmt3bMxEVMY6nJTT+zWneq7mAd7VvwhWaA==}
applesauce-signer@0.5.0: applesauce-react@0.6.0:
resolution: {integrity: sha512-MF1I0KQ0nm3vq/Z/lXL0279KqTJcu0BctvKSORNUBeV0GTlDsDdvrsYyKmsjJVVJunr8xhuOrsPvAew5dT54Lw==} resolution: {integrity: sha512-T8fd7ImkrSe0o+FjC5AoLsYeqlLWq5bE5evwavR2+NTLC9CW185qKPPIzbTDrakq4hPADV8by3AOCmD+MY1Riw==}
applesauce-signer@0.6.0:
resolution: {integrity: sha512-BunnObvSqIBJ04MMQnpXIflfYEAwqWROCJqQrFZXHy+yXmZjHzPVMkXQLcJ7oXoNVc4CaxgJwp7w8eSmohJKFg==}
argparse@1.0.10: argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
@@ -7214,15 +7220,15 @@ snapshots:
dependencies: dependencies:
color-convert: 2.0.1 color-convert: 2.0.1
applesauce-channel@0.5.0(typescript@5.6.2): applesauce-channel@0.6.0(typescript@5.6.2):
dependencies: dependencies:
applesauce-core: 0.5.0(typescript@5.6.2) applesauce-core: 0.6.0(typescript@5.6.2)
nostr-tools: 2.7.2(typescript@5.6.2) nostr-tools: 2.7.2(typescript@5.6.2)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
- typescript - typescript
applesauce-core@0.5.0(typescript@5.6.2): applesauce-core@0.6.0(typescript@5.6.2):
dependencies: dependencies:
debug: 4.3.7 debug: 4.3.7
json-stringify-deterministic: 1.0.12 json-stringify-deterministic: 1.0.12
@@ -7234,13 +7240,23 @@ snapshots:
- supports-color - supports-color
- typescript - typescript
applesauce-signer@0.5.0(typescript@5.6.2): applesauce-react@0.6.0(typescript@5.6.2):
dependencies:
applesauce-core: 0.6.0(typescript@5.6.2)
nostr-tools: 2.7.2(typescript@5.6.2)
react: 18.3.1
zen-observable: 0.10.0
transitivePeerDependencies:
- supports-color
- typescript
applesauce-signer@0.6.0(typescript@5.6.2):
dependencies: dependencies:
'@noble/hashes': 1.5.0 '@noble/hashes': 1.5.0
'@noble/secp256k1': 1.7.1 '@noble/secp256k1': 1.7.1
'@scure/base': 1.1.9 '@scure/base': 1.1.9
'@types/dom-serial': 1.0.6 '@types/dom-serial': 1.0.6
applesauce-core: 0.5.0(typescript@5.6.2) applesauce-core: 0.6.0(typescript@5.6.2)
debug: 4.3.7 debug: 4.3.7
nostr-tools: 2.7.2(typescript@5.6.2) nostr-tools: 2.7.2(typescript@5.6.2)
transitivePeerDependencies: transitivePeerDependencies:

View File

@@ -1,22 +1,3 @@
import { useState } from "react"; import { useObservable } from "applesauce-react";
import { isStateful } from "applesauce-core/observable";
import { useIsomorphicLayoutEffect } from "react-use";
import Observable from "zen-observable";
import { useForceUpdate } from "@chakra-ui/react";
export function useObservable<T>(observable?: Observable<T>): T | undefined { export { useObservable };
const forceUpdate = useForceUpdate();
const [value, update] = useState<T | undefined>(observable && isStateful(observable) ? observable.value : undefined);
useIsomorphicLayoutEffect(() => {
if (!observable) return;
const s = observable.subscribe((v) => {
update(v);
forceUpdate();
});
return () => s.unsubscribe();
}, [observable]);
return value;
}

View File

@@ -1,9 +1,9 @@
import { useMemo } from "react"; import { useMemo } from "react";
import { useObservable, useQueryStore } from "applesauce-react";
import { useReadRelays } from "./use-client-relays"; import { useReadRelays } from "./use-client-relays";
import replaceableEventsService, { RequestOptions } from "../services/replaceable-events"; import replaceableEventsService, { RequestOptions } from "../services/replaceable-events";
import { CustomAddressPointer, parseCoordinate } from "../helpers/nostr/event"; import { CustomAddressPointer, parseCoordinate } from "../helpers/nostr/event";
import useSubject from "./use-subject";
export default function useReplaceableEvent( export default function useReplaceableEvent(
cord: string | CustomAddressPointer | undefined, cord: string | CustomAddressPointer | undefined,
@@ -11,17 +11,22 @@ export default function useReplaceableEvent(
opts: RequestOptions = {}, opts: RequestOptions = {},
) { ) {
const readRelays = useReadRelays(additionalRelays); const readRelays = useReadRelays(additionalRelays);
const sub = useMemo(() => { const store = useQueryStore();
const observable = useMemo(() => {
const parsed = typeof cord === "string" ? parseCoordinate(cord) : cord; const parsed = typeof cord === "string" ? parseCoordinate(cord) : cord;
if (!parsed) return; if (!parsed) return;
return replaceableEventsService.requestEvent(
replaceableEventsService.requestEvent(
parsed.relays ? [...readRelays, ...parsed.relays] : readRelays, parsed.relays ? [...readRelays, ...parsed.relays] : readRelays,
parsed.kind, parsed.kind,
parsed.pubkey, parsed.pubkey,
parsed.identifier, parsed.identifier,
opts, opts,
); );
}, [cord, readRelays.urls.join("|"), opts?.alwaysRequest, opts?.ignoreCache]);
return useSubject(sub); return store.replaceable(parsed.kind, parsed.pubkey, parsed.identifier);
}, [cord, readRelays.urls.join("|"), opts?.alwaysRequest, opts?.ignoreCache, store]);
return useObservable(observable);
} }

View File

@@ -1,11 +1,9 @@
import { useMemo } from "react"; import { useMemo } from "react";
import { useObservable, useQueryStore } from "applesauce-react";
import { useReadRelays } from "./use-client-relays"; import { useReadRelays } from "./use-client-relays";
import replaceableEventsService, { RequestOptions } from "../services/replaceable-events"; import replaceableEventsService, { RequestOptions } from "../services/replaceable-events";
import { CustomAddressPointer, parseCoordinate } from "../helpers/nostr/event"; import { CustomAddressPointer, parseCoordinate } from "../helpers/nostr/event";
import Subject from "../classes/subject";
import { NostrEvent } from "../types/nostr-event";
import useSubjects from "./use-subjects";
export default function useReplaceableEvents( export default function useReplaceableEvents(
coordinates: string[] | CustomAddressPointer[] | undefined, coordinates: string[] | CustomAddressPointer[] | undefined,
@@ -13,24 +11,29 @@ export default function useReplaceableEvents(
opts: RequestOptions = {}, opts: RequestOptions = {},
) { ) {
const readRelays = useReadRelays(additionalRelays); const readRelays = useReadRelays(additionalRelays);
const subs = useMemo(() => { const store = useQueryStore();
const observable = useMemo(() => {
if (!coordinates) return undefined; if (!coordinates) return undefined;
const subs: Subject<NostrEvent>[] = []; const pointers: CustomAddressPointer[] = [];
for (const cord of coordinates) { for (const cord of coordinates) {
const parsed = typeof cord === "string" ? parseCoordinate(cord) : cord; const parsed = typeof cord === "string" ? parseCoordinate(cord) : cord;
if (!parsed) return; if (!parsed) return;
subs.push(
replaceableEventsService.requestEvent( pointers.push(parsed);
parsed.relays ? [...readRelays, ...parsed.relays] : readRelays, replaceableEventsService.requestEvent(
parsed.kind, parsed.relays ? [...readRelays, ...parsed.relays] : readRelays,
parsed.pubkey, parsed.kind,
parsed.identifier, parsed.pubkey,
opts, parsed.identifier,
), opts,
); );
} }
return subs;
}, [coordinates, readRelays.urls.join("|")]);
return useSubjects(subs); return store.replaceableSet(pointers);
}, [coordinates, readRelays.urls.join("|"), store]);
const map = useObservable(observable);
return Array.from(map?.values() ?? []);
} }

View File

@@ -2,8 +2,8 @@ import { useEffect } from "react";
import singleEventService from "../services/single-event"; import singleEventService from "../services/single-event";
import { useReadRelays } from "./use-client-relays"; import { useReadRelays } from "./use-client-relays";
import { queryStore } from "../services/event-store"; import { useStoreQuery } from "applesauce-react";
import { useObservable } from "./use-observable"; import { Queries } from "applesauce-core";
export default function useSingleEvent(id?: string, additionalRelays?: Iterable<string>) { export default function useSingleEvent(id?: string, additionalRelays?: Iterable<string>) {
const readRelays = useReadRelays(additionalRelays); const readRelays = useReadRelays(additionalRelays);
@@ -12,6 +12,5 @@ export default function useSingleEvent(id?: string, additionalRelays?: Iterable<
if (id) singleEventService.requestEvent(id, readRelays); if (id) singleEventService.requestEvent(id, readRelays);
}, [id, readRelays.urls.join("|")]); }, [id, readRelays.urls.join("|")]);
const observable = id ? queryStore.event(id) : undefined; return useStoreQuery(Queries.SingleEventQuery, id ? [id] : undefined);
return useObservable(observable);
} }

View File

@@ -1,9 +1,9 @@
import { useEffect, useMemo } from "react"; import { useEffect } from "react";
import { Queries } from "applesauce-core";
import { useStoreQuery } from "applesauce-react";
import singleEventService from "../services/single-event"; import singleEventService from "../services/single-event";
import { useReadRelays } from "./use-client-relays"; import { useReadRelays } from "./use-client-relays";
import { eventStore } from "../services/event-store";
import { useObservable } from "./use-observable";
export default function useSingleEvents(ids?: string[], additionalRelays?: Iterable<string>) { export default function useSingleEvents(ids?: string[], additionalRelays?: Iterable<string>) {
const readRelays = useReadRelays(additionalRelays); const readRelays = useReadRelays(additionalRelays);
@@ -15,6 +15,5 @@ export default function useSingleEvents(ids?: string[], additionalRelays?: Itera
} }
}, [ids, readRelays.urls.join("|")]); }, [ids, readRelays.urls.join("|")]);
const observable = useMemo(() => (ids ? eventStore.timeline([{ ids }]) : undefined), [ids?.join("|")]); return useStoreQuery(Queries.TimelineQuery, ids ? [{ ids }] : undefined) ?? [];
return useObservable(observable) ?? [];
} }

View File

@@ -1,16 +1,3 @@
import { useMemo } from "react"; import { useStoreQuery } from "applesauce-react";
import { QueryConstructor } from "applesauce-core";
import { queryStore } from "../services/event-store"; export { useStoreQuery };
import { useObservable } from "./use-observable";
export function useStoreQuery<T extends unknown, Args extends Array<any>>(
queryConstructor: QueryConstructor<T, Args>,
args?: Args | null,
) {
const observable = useMemo(() => {
if (args) return queryStore.runQuery(queryConstructor)(...args);
}, [args]);
return useObservable(observable);
}

View File

@@ -1,5 +1,6 @@
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import { ChakraProvider, localStorageManager } from "@chakra-ui/react"; import { ChakraProvider, localStorageManager } from "@chakra-ui/react";
import { QueryStoreProvider } from "applesauce-react";
import { SigningProvider } from "./signing-provider"; import { SigningProvider } from "./signing-provider";
import buildTheme from "../../theme"; import buildTheme from "../../theme";
@@ -11,6 +12,7 @@ import BreakpointProvider from "./breakpoint-provider";
import DMTimelineProvider from "./dms-provider"; import DMTimelineProvider from "./dms-provider";
import PublishProvider from "./publish-provider"; import PublishProvider from "./publish-provider";
import WebOfTrustProvider from "./web-of-trust-provider"; import WebOfTrustProvider from "./web-of-trust-provider";
import { queryStore } from "../../services/event-store";
// Top level providers, should be render as close to the root as possible // Top level providers, should be render as close to the root as possible
export const GlobalProviders = ({ children }: { children: React.ReactNode }) => { export const GlobalProviders = ({ children }: { children: React.ReactNode }) => {
@@ -23,21 +25,23 @@ export const GlobalProviders = ({ children }: { children: React.ReactNode }) =>
return ( return (
<ChakraProvider theme={theme} colorModeManager={localStorageManager}> <ChakraProvider theme={theme} colorModeManager={localStorageManager}>
<BreakpointProvider> <BreakpointProvider>
<SigningProvider> <QueryStoreProvider store={queryStore}>
<PublishProvider> <SigningProvider>
<NotificationsProvider> <PublishProvider>
<DMTimelineProvider> <NotificationsProvider>
<DefaultEmojiProvider> <DMTimelineProvider>
<UserEmojiProvider> <DefaultEmojiProvider>
<AllUserSearchDirectoryProvider> <UserEmojiProvider>
<WebOfTrustProvider>{children}</WebOfTrustProvider> <AllUserSearchDirectoryProvider>
</AllUserSearchDirectoryProvider> <WebOfTrustProvider>{children}</WebOfTrustProvider>
</UserEmojiProvider> </AllUserSearchDirectoryProvider>
</DefaultEmojiProvider> </UserEmojiProvider>
</DMTimelineProvider> </DefaultEmojiProvider>
</NotificationsProvider> </DMTimelineProvider>
</PublishProvider> </NotificationsProvider>
</SigningProvider> </PublishProvider>
</SigningProvider>
</QueryStoreProvider>
</BreakpointProvider> </BreakpointProvider>
</ChakraProvider> </ChakraProvider>
); );