mirror of
https://github.com/logos-messaging/js-waku.git
synced 2026-01-08 00:33:12 +00:00
remove not needed logic from waku/react package
This commit is contained in:
parent
8e9577fb25
commit
bfbe6379ba
2
package-lock.json
generated
2
package-lock.json
generated
@ -37553,7 +37553,7 @@
|
||||
"node": ">=22"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17 || ^18"
|
||||
"react": "^16.8.0 || ^17 || ^18 || ^19"
|
||||
}
|
||||
},
|
||||
"packages/react/node_modules/@typescript-eslint/eslint-plugin": {
|
||||
|
||||
@ -86,7 +86,7 @@
|
||||
"rollup-plugin-typescript2": "^0.36.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17 || ^18"
|
||||
"react": "^16.8.0 || ^17 || ^18 || ^19"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@ -1,53 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import type { ContentPair, ReactChildrenProps } from "./types.js";
|
||||
import { useCreateContentPair } from "./useCreateContentPair.js";
|
||||
|
||||
type ContentPairContextType = Partial<ContentPair>;
|
||||
|
||||
const ContentPairContext = React.createContext<ContentPairContextType>({
|
||||
decoder: undefined,
|
||||
encoder: undefined
|
||||
});
|
||||
|
||||
/**
|
||||
* Hook to retrieve Encoder/Decoder pair from Context.
|
||||
* @example
|
||||
* const { encoder, decoder } = useContentPair();
|
||||
* @returns {Object} { encoder, decoder }
|
||||
*/
|
||||
export const useContentPair = (): ContentPairContextType =>
|
||||
React.useContext(ContentPairContext);
|
||||
|
||||
type ContentPairProviderProps = ReactChildrenProps & {
|
||||
contentTopic: string;
|
||||
ephemeral?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provider for creating Encoder/Decoder pair based on contentTopic
|
||||
* @example
|
||||
* const App = (props) => (
|
||||
* <ContentPairProvider contentTopic="/toy-chat/2/huilong/proto">
|
||||
* <Component />
|
||||
* </ContentPairProvider>
|
||||
* );
|
||||
* const Component = (props) => {
|
||||
* const { encoder, decoder } = useContentPair();
|
||||
* ...
|
||||
* };
|
||||
* @param {string} contentTopic - content topic for configuring the pair
|
||||
* @param {boolean} ephemeral - flag to set messages ephemeral according to RFC https://rfc.vac.dev/spec/14/
|
||||
* @returns React ContentPair Provider component
|
||||
*/
|
||||
export const ContentPairProvider: React.FunctionComponent<
|
||||
ContentPairProviderProps
|
||||
> = (props) => {
|
||||
const result = useCreateContentPair(props.contentTopic, props.ephemeral);
|
||||
|
||||
return (
|
||||
<ContentPairContext.Provider value={result}>
|
||||
{props.children}
|
||||
</ContentPairContext.Provider>
|
||||
);
|
||||
};
|
||||
@ -1,11 +1,7 @@
|
||||
import type { CreateNodeOptions, IWaku } from "@waku/interfaces";
|
||||
import type { CreateNodeOptions, IWaku, LightNode } from "@waku/interfaces";
|
||||
import React from "react";
|
||||
|
||||
import type {
|
||||
BootstrapNodeOptions,
|
||||
CreateNodeResult,
|
||||
ReactChildrenProps
|
||||
} from "./types.js";
|
||||
import type { CreateNodeResult, ReactChildrenProps } from "./types.js";
|
||||
import { useCreateLightNode } from "./useCreateWaku.js";
|
||||
|
||||
type WakuContextType<T extends IWaku> = CreateNodeResult<T>;
|
||||
@ -28,35 +24,31 @@ const WakuContext = React.createContext<WakuContextType<IWaku>>({
|
||||
* const { node, isLoading, error } = useWaku();
|
||||
* @returns WakuContext
|
||||
*/
|
||||
export const useWaku = <T extends IWaku>(): WakuContextType<T> =>
|
||||
React.useContext(WakuContext) as WakuContextType<T>;
|
||||
export const useWaku = (): WakuContextType<LightNode> =>
|
||||
React.useContext(WakuContext) as WakuContextType<LightNode>;
|
||||
|
||||
type ProviderProps<T> = ReactChildrenProps & BootstrapNodeOptions<T>;
|
||||
type ProviderProps<T> = ReactChildrenProps & { options: T };
|
||||
|
||||
/**
|
||||
* Provider for creating Light Node based on options passed.
|
||||
* Provider for creating Waku node based on options passed.
|
||||
* @example
|
||||
* const App = (props) => (
|
||||
* <LightNodeProvider options={{...}}>
|
||||
* <WakuProvider options={{...}}>
|
||||
* <Component />
|
||||
* </LightNodeProvider>
|
||||
* </WakuProvider>
|
||||
* );
|
||||
* const Component = (props) => {
|
||||
* const { node, isLoading, error } = useWaku<LightNode>();
|
||||
* const { node, isLoading, error } = useWaku();
|
||||
* ...
|
||||
* };
|
||||
* @param {Object} props - options to create a node and other React props
|
||||
* @param {CreateNodeOptions} props.options - optional options for creating Light Node
|
||||
* @param {Protocols} props.protocols - optional protocols list to initiate node with
|
||||
* @returns React Light Node provider component
|
||||
*/
|
||||
export const LightNodeProvider: React.FunctionComponent<
|
||||
ProviderProps<CreateNodeOptions>
|
||||
> = (props) => {
|
||||
const result = useCreateLightNode({
|
||||
options: props.options,
|
||||
protocols: props.protocols
|
||||
});
|
||||
export const WakuProvider = (
|
||||
props: ProviderProps<CreateNodeOptions>
|
||||
): React.ReactElement => {
|
||||
const result = useCreateLightNode(props.options);
|
||||
|
||||
return (
|
||||
<WakuContext.Provider value={result}>{props.children}</WakuContext.Provider>
|
||||
|
||||
@ -1,8 +1,2 @@
|
||||
export { ContentPairProvider, useContentPair } from "./ContentPairProvider.js";
|
||||
export { CreateNodeOptions } from "./types.js";
|
||||
export { useCreateContentPair } from "./useCreateContentPair.js";
|
||||
export { useCreateLightNode } from "./useCreateWaku.js";
|
||||
export { useFilterMessages } from "./useFilterMessages.js";
|
||||
export { useLightPush } from "./useLightPush.js";
|
||||
export { useStoreMessages } from "./useStoreMessages.js";
|
||||
export { LightNodeProvider, useWaku } from "./WakuProvider.js";
|
||||
export type { CreateNodeOptions } from "./types.js";
|
||||
export { WakuProvider, useWaku } from "./WakuProvider.js";
|
||||
|
||||
@ -1,13 +1,8 @@
|
||||
import type {
|
||||
IDecodedMessage,
|
||||
IDecoder,
|
||||
IEncoder,
|
||||
IWaku,
|
||||
Protocols
|
||||
} from "@waku/interfaces";
|
||||
import type { IWaku } from "@waku/interfaces";
|
||||
import type React from "react";
|
||||
export type { CreateNodeOptions, AutoSharding } from "@waku/interfaces";
|
||||
|
||||
export type HookState = {
|
||||
type HookState = {
|
||||
isLoading: boolean;
|
||||
error: undefined | string;
|
||||
};
|
||||
@ -16,16 +11,6 @@ export type CreateNodeResult<T extends IWaku> = HookState & {
|
||||
node: undefined | T;
|
||||
};
|
||||
|
||||
export type BootstrapNodeOptions<T = Record<string, never>> = {
|
||||
options?: T;
|
||||
protocols?: Protocols[];
|
||||
};
|
||||
|
||||
export type ContentPair = {
|
||||
encoder: IEncoder;
|
||||
decoder: IDecoder<IDecodedMessage>;
|
||||
};
|
||||
|
||||
export type ReactChildrenProps = {
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
@ -1,59 +0,0 @@
|
||||
import type {
|
||||
AutoSharding,
|
||||
IDecodedMessage,
|
||||
IDecoder,
|
||||
IEncoder
|
||||
} from "@waku/interfaces";
|
||||
import { createDecoder, createEncoder } from "@waku/sdk";
|
||||
import { createRoutingInfo } from "@waku/utils";
|
||||
import React from "react";
|
||||
|
||||
import type { ContentPair } from "./types.js";
|
||||
|
||||
const defaultNetworkConfig: AutoSharding = {
|
||||
clusterId: 0,
|
||||
numShardsInCluster: 8
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates Encoder / Decoder pair for a given contentTopic.
|
||||
* @param {string} contentTopic - topic to orient to
|
||||
* @param {boolean} ephemeral - makes messages ephemeral, default to false
|
||||
* @param {AutoSharding} networkConfig - optional network config, defaults to cluster 0 with 8 shards
|
||||
* @returns {Object} Encoder / Decoder pair
|
||||
*/
|
||||
export const useCreateContentPair = (
|
||||
contentTopic: string,
|
||||
ephemeral = false,
|
||||
networkConfig: AutoSharding = defaultNetworkConfig
|
||||
): ContentPair => {
|
||||
const routingInfo = React.useMemo(
|
||||
() => createRoutingInfo(networkConfig, { contentTopic }),
|
||||
[contentTopic, networkConfig.clusterId, networkConfig.numShardsInCluster]
|
||||
);
|
||||
|
||||
const [encoder, setEncoder] = React.useState<IEncoder>(
|
||||
createEncoder({ contentTopic, ephemeral, routingInfo })
|
||||
);
|
||||
const [decoder, setDecoder] = React.useState<IDecoder<IDecodedMessage>>(
|
||||
createDecoder(contentTopic, routingInfo)
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
const newRoutingInfo = createRoutingInfo(networkConfig, { contentTopic });
|
||||
setEncoder(
|
||||
createEncoder({ contentTopic, ephemeral, routingInfo: newRoutingInfo })
|
||||
);
|
||||
setDecoder(createDecoder(contentTopic, newRoutingInfo));
|
||||
}, [
|
||||
contentTopic,
|
||||
ephemeral,
|
||||
networkConfig.clusterId,
|
||||
networkConfig.numShardsInCluster
|
||||
]);
|
||||
|
||||
return {
|
||||
encoder,
|
||||
decoder
|
||||
};
|
||||
};
|
||||
@ -1,22 +1,19 @@
|
||||
import type { CreateNodeOptions, IWaku, LightNode } from "@waku/interfaces";
|
||||
import { createLightNode, waitForRemotePeer } from "@waku/sdk";
|
||||
import { createLightNode } from "@waku/sdk";
|
||||
import React from "react";
|
||||
|
||||
import type { BootstrapNodeOptions, CreateNodeResult } from "./types.js";
|
||||
import type { CreateNodeResult } from "./types.js";
|
||||
|
||||
type NodeFactory<N, T = Record<string, never>> = (options?: T) => Promise<N>;
|
||||
|
||||
type CreateNodeParams<
|
||||
N extends IWaku,
|
||||
T = Record<string, never>
|
||||
> = BootstrapNodeOptions<T> & {
|
||||
type CreateNodeParams<N extends IWaku, T = Record<string, never>> = T & {
|
||||
factory: NodeFactory<N, T>;
|
||||
};
|
||||
|
||||
const useCreateNode = <N extends IWaku, T = Record<string, never>>(
|
||||
params: CreateNodeParams<N, T>
|
||||
): CreateNodeResult<N> => {
|
||||
const { factory, options, protocols = [] } = params;
|
||||
const { factory, ...options } = params;
|
||||
|
||||
const [node, setNode] = React.useState<N | undefined>(undefined);
|
||||
const [isLoading, setLoading] = React.useState<boolean>(true);
|
||||
@ -26,14 +23,14 @@ const useCreateNode = <N extends IWaku, T = Record<string, never>>(
|
||||
let cancelled = false;
|
||||
setLoading(true);
|
||||
|
||||
factory(options)
|
||||
factory(options as T)
|
||||
.then(async (node) => {
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
await node.start();
|
||||
await waitForRemotePeer(node, protocols);
|
||||
await node.waitForPeers();
|
||||
|
||||
setNode(node);
|
||||
setLoading(false);
|
||||
@ -56,7 +53,7 @@ const useCreateNode = <N extends IWaku, T = Record<string, never>>(
|
||||
};
|
||||
|
||||
export const useCreateLightNode = (
|
||||
params?: BootstrapNodeOptions<CreateNodeOptions>
|
||||
params?: CreateNodeOptions
|
||||
): CreateNodeResult<LightNode> => {
|
||||
return useCreateNode<LightNode, CreateNodeOptions>({
|
||||
...params,
|
||||
|
||||
@ -1,89 +0,0 @@
|
||||
import type {
|
||||
IDecodedMessage,
|
||||
IDecoder,
|
||||
IFilter,
|
||||
IWaku
|
||||
} from "@waku/interfaces";
|
||||
import { Logger } from "@waku/utils";
|
||||
import React from "react";
|
||||
|
||||
import type { HookState } from "./types.js";
|
||||
|
||||
const log = new Logger("react:useFilterMessages");
|
||||
|
||||
type AbstractFilterNode = IWaku & {
|
||||
filter: IFilter;
|
||||
};
|
||||
|
||||
type UseFilterMessagesParams = {
|
||||
node: undefined | AbstractFilterNode;
|
||||
decoder: undefined | IDecoder<IDecodedMessage>;
|
||||
};
|
||||
|
||||
type UseFilterMessagesResult = HookState & {
|
||||
messages: IDecodedMessage[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns messages from Filter subscription and keeps them up to date
|
||||
* @example
|
||||
* const { isLoading, error, message } = useFilterMessages({node, decoder});
|
||||
* @param {Object} node - node that implements Filter, hook does nothing if undefined
|
||||
* @param {Object} decoder - decoder to use for subscribing, hook does nothing if undefined
|
||||
* @returns {Object} hook state (isLoading, error) and messages array
|
||||
*/
|
||||
export const useFilterMessages = (
|
||||
params: UseFilterMessagesParams
|
||||
): UseFilterMessagesResult => {
|
||||
const { node, decoder } = params;
|
||||
|
||||
const [error, setError] = React.useState<undefined | string>(undefined);
|
||||
const [isLoading, setLoading] = React.useState<boolean>(false);
|
||||
const [messages, setMessage] = React.useState<IDecodedMessage[]>([]);
|
||||
|
||||
const pushMessage = React.useCallback(
|
||||
(message: IDecodedMessage): void => {
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
||||
setMessage((prev) => [...prev, message]);
|
||||
},
|
||||
[setMessage]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!node || !decoder) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
node.filter
|
||||
.subscribe([decoder], pushMessage)
|
||||
.then((success) => {
|
||||
setLoading(false);
|
||||
if (!success) {
|
||||
setError("Failed to subscribe to filter");
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
setLoading(false);
|
||||
setError(
|
||||
`Failed to subscribe to filter: ${err?.message || "no message"}`
|
||||
);
|
||||
});
|
||||
|
||||
return () => {
|
||||
node.filter.unsubscribe([decoder]).catch((err) => {
|
||||
log.error("Failed to unsubscribe:", err);
|
||||
});
|
||||
};
|
||||
}, [node, decoder, pushMessage, setError, setLoading]);
|
||||
|
||||
return {
|
||||
error,
|
||||
messages,
|
||||
isLoading
|
||||
};
|
||||
};
|
||||
@ -1,44 +0,0 @@
|
||||
import type {
|
||||
IEncoder,
|
||||
ILightPush,
|
||||
IMessage,
|
||||
IWaku,
|
||||
LightPushSDKResult
|
||||
} from "@waku/interfaces";
|
||||
import React from "react";
|
||||
|
||||
type AbstractLightPushNode = IWaku & {
|
||||
lightPush: ILightPush;
|
||||
};
|
||||
|
||||
type UseLightPushParams = {
|
||||
encoder: undefined | IEncoder;
|
||||
node: undefined | AbstractLightPushNode;
|
||||
};
|
||||
|
||||
type PushFn = (message: IMessage) => Promise<LightPushSDKResult>;
|
||||
|
||||
type UseLightPushResult = {
|
||||
push?: undefined | PushFn;
|
||||
};
|
||||
|
||||
export const useLightPush = (
|
||||
params: UseLightPushParams
|
||||
): UseLightPushResult => {
|
||||
const { node, encoder } = params;
|
||||
|
||||
const push = React.useCallback<PushFn>(
|
||||
(message) => {
|
||||
return node!.lightPush.send(encoder as IEncoder, message);
|
||||
},
|
||||
[node, encoder]
|
||||
);
|
||||
|
||||
if (!node && !encoder) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
push
|
||||
};
|
||||
};
|
||||
@ -1,101 +0,0 @@
|
||||
import type {
|
||||
IDecodedMessage,
|
||||
IDecoder,
|
||||
IStore,
|
||||
IWaku,
|
||||
QueryRequestParams
|
||||
} from "@waku/interfaces";
|
||||
import React from "react";
|
||||
|
||||
import type { HookState } from "./types.js";
|
||||
|
||||
type AbstractStoreNode = IWaku & {
|
||||
store: IStore;
|
||||
};
|
||||
|
||||
type UseStoreMessagesParams = {
|
||||
node: undefined | AbstractStoreNode;
|
||||
decoder: undefined | IDecoder<IDecodedMessage>;
|
||||
options: QueryRequestParams;
|
||||
};
|
||||
|
||||
type UseStoreMessagesResult = HookState & {
|
||||
messages: IDecodedMessage[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook for retrieving messages from Store protocol based on options
|
||||
* @example
|
||||
* const { isLoading, error, messages } = useStoreMessages({node, decoder, options});
|
||||
* @param {Object} node - node that implement Store, hook does nothing if undefined
|
||||
* @param {Object} decoder - decoder to use for getting messages, hook does nothing if undefined
|
||||
* @param {QueryRequestParams} options - options to initiate query to get messages
|
||||
* @returns {Object} hook state (isLoading, error) and messages array
|
||||
*/
|
||||
export const useStoreMessages = (
|
||||
params: UseStoreMessagesParams
|
||||
): UseStoreMessagesResult => {
|
||||
const { node, decoder, options } = params;
|
||||
|
||||
const [error, setError] = React.useState<undefined | string>(undefined);
|
||||
const [isLoading, setLoading] = React.useState<boolean>(false);
|
||||
const [messages, setMessage] = React.useState<IDecodedMessage[]>([]);
|
||||
|
||||
const pushMessage = React.useCallback(
|
||||
(newMessages: IDecodedMessage[]): void => {
|
||||
if (!newMessages || !newMessages.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
setMessage((prev) => [...prev, ...newMessages]);
|
||||
},
|
||||
[setMessage]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!node || !decoder) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cancelled = false;
|
||||
setLoading(true);
|
||||
|
||||
Promise.resolve()
|
||||
.then(async () => {
|
||||
for await (const promises of node.store.queryGenerator(
|
||||
[decoder],
|
||||
options
|
||||
)) {
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const messagesRaw = await Promise.all(promises);
|
||||
const filteredMessages = messagesRaw.filter(
|
||||
(v): v is IDecodedMessage => !!v
|
||||
);
|
||||
|
||||
pushMessage(filteredMessages);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
setLoading(false);
|
||||
setError(
|
||||
`Failed to query messages from store: ${err?.message || "no message"}`
|
||||
);
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
// TODO: missing dependency on options, it will prevent consecutive update if options change
|
||||
}, [node, decoder, pushMessage, setError, setLoading]);
|
||||
|
||||
return {
|
||||
error,
|
||||
isLoading,
|
||||
messages
|
||||
};
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user