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/react-codemirror": "^4.23.0",
"@webscopeio/react-textarea-autocomplete": "^4.9.2",
"applesauce-channel": "^0.5.0",
"applesauce-core": "^0.5.0",
"applesauce-signer": "^0.5.0",
"applesauce-channel": "^0.6.0",
"applesauce-core": "^0.6.0",
"applesauce-react": "^0.6.0",
"applesauce-signer": "^0.6.0",
"bech32": "^2.0.0",
"blossom-client-sdk": "^0.7.0",
"blossom-drive-sdk": "^0.4.0",

50
pnpm-lock.yaml generated
View File

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

View File

@ -1,22 +1,3 @@
import { useState } from "react";
import { isStateful } from "applesauce-core/observable";
import { useIsomorphicLayoutEffect } from "react-use";
import Observable from "zen-observable";
import { useForceUpdate } from "@chakra-ui/react";
import { useObservable } from "applesauce-react";
export function useObservable<T>(observable?: Observable<T>): T | undefined {
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;
}
export { useObservable };

View File

@ -1,9 +1,9 @@
import { useMemo } from "react";
import { useObservable, useQueryStore } from "applesauce-react";
import { useReadRelays } from "./use-client-relays";
import replaceableEventsService, { RequestOptions } from "../services/replaceable-events";
import { CustomAddressPointer, parseCoordinate } from "../helpers/nostr/event";
import useSubject from "./use-subject";
export default function useReplaceableEvent(
cord: string | CustomAddressPointer | undefined,
@ -11,17 +11,22 @@ export default function useReplaceableEvent(
opts: RequestOptions = {},
) {
const readRelays = useReadRelays(additionalRelays);
const sub = useMemo(() => {
const store = useQueryStore();
const observable = useMemo(() => {
const parsed = typeof cord === "string" ? parseCoordinate(cord) : cord;
if (!parsed) return;
return replaceableEventsService.requestEvent(
replaceableEventsService.requestEvent(
parsed.relays ? [...readRelays, ...parsed.relays] : readRelays,
parsed.kind,
parsed.pubkey,
parsed.identifier,
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 { useObservable, useQueryStore } from "applesauce-react";
import { useReadRelays } from "./use-client-relays";
import replaceableEventsService, { RequestOptions } from "../services/replaceable-events";
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(
coordinates: string[] | CustomAddressPointer[] | undefined,
@ -13,24 +11,29 @@ export default function useReplaceableEvents(
opts: RequestOptions = {},
) {
const readRelays = useReadRelays(additionalRelays);
const subs = useMemo(() => {
const store = useQueryStore();
const observable = useMemo(() => {
if (!coordinates) return undefined;
const subs: Subject<NostrEvent>[] = [];
const pointers: CustomAddressPointer[] = [];
for (const cord of coordinates) {
const parsed = typeof cord === "string" ? parseCoordinate(cord) : cord;
if (!parsed) return;
subs.push(
replaceableEventsService.requestEvent(
parsed.relays ? [...readRelays, ...parsed.relays] : readRelays,
parsed.kind,
parsed.pubkey,
parsed.identifier,
opts,
),
pointers.push(parsed);
replaceableEventsService.requestEvent(
parsed.relays ? [...readRelays, ...parsed.relays] : readRelays,
parsed.kind,
parsed.pubkey,
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 { useReadRelays } from "./use-client-relays";
import { queryStore } from "../services/event-store";
import { useObservable } from "./use-observable";
import { useStoreQuery } from "applesauce-react";
import { Queries } from "applesauce-core";
export default function useSingleEvent(id?: string, additionalRelays?: Iterable<string>) {
const readRelays = useReadRelays(additionalRelays);
@ -12,6 +12,5 @@ export default function useSingleEvent(id?: string, additionalRelays?: Iterable<
if (id) singleEventService.requestEvent(id, readRelays);
}, [id, readRelays.urls.join("|")]);
const observable = id ? queryStore.event(id) : undefined;
return useObservable(observable);
return useStoreQuery(Queries.SingleEventQuery, id ? [id] : undefined);
}

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 { 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>) {
const readRelays = useReadRelays(additionalRelays);
@ -15,6 +15,5 @@ export default function useSingleEvents(ids?: string[], additionalRelays?: Itera
}
}, [ids, readRelays.urls.join("|")]);
const observable = useMemo(() => (ids ? eventStore.timeline([{ ids }]) : undefined), [ids?.join("|")]);
return useObservable(observable) ?? [];
return useStoreQuery(Queries.TimelineQuery, ids ? [{ ids }] : undefined) ?? [];
}

View File

@ -1,16 +1,3 @@
import { useMemo } from "react";
import { QueryConstructor } from "applesauce-core";
import { useStoreQuery } from "applesauce-react";
import { queryStore } from "../services/event-store";
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);
}
export { useStoreQuery };

View File

@ -1,5 +1,6 @@
import React, { useMemo } from "react";
import { ChakraProvider, localStorageManager } from "@chakra-ui/react";
import { QueryStoreProvider } from "applesauce-react";
import { SigningProvider } from "./signing-provider";
import buildTheme from "../../theme";
@ -11,6 +12,7 @@ import BreakpointProvider from "./breakpoint-provider";
import DMTimelineProvider from "./dms-provider";
import PublishProvider from "./publish-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
export const GlobalProviders = ({ children }: { children: React.ReactNode }) => {
@ -23,21 +25,23 @@ export const GlobalProviders = ({ children }: { children: React.ReactNode }) =>
return (
<ChakraProvider theme={theme} colorModeManager={localStorageManager}>
<BreakpointProvider>
<SigningProvider>
<PublishProvider>
<NotificationsProvider>
<DMTimelineProvider>
<DefaultEmojiProvider>
<UserEmojiProvider>
<AllUserSearchDirectoryProvider>
<WebOfTrustProvider>{children}</WebOfTrustProvider>
</AllUserSearchDirectoryProvider>
</UserEmojiProvider>
</DefaultEmojiProvider>
</DMTimelineProvider>
</NotificationsProvider>
</PublishProvider>
</SigningProvider>
<QueryStoreProvider store={queryStore}>
<SigningProvider>
<PublishProvider>
<NotificationsProvider>
<DMTimelineProvider>
<DefaultEmojiProvider>
<UserEmojiProvider>
<AllUserSearchDirectoryProvider>
<WebOfTrustProvider>{children}</WebOfTrustProvider>
</AllUserSearchDirectoryProvider>
</UserEmojiProvider>
</DefaultEmojiProvider>
</DMTimelineProvider>
</NotificationsProvider>
</PublishProvider>
</SigningProvider>
</QueryStoreProvider>
</BreakpointProvider>
</ChakraProvider>
);