feat!: add basic @waku/react hooks (#1)
* add react and typecript * add react, rollup and ts * add waku dependencies * add create hooks, providers and update typings path * extend create hooks and provider with error/loading state * rename to isLoading * create useContentPair hook * add protocols property and bootstrap with remote peers * add useFilterSubscribe * add eslint & fix issues * add prettier & fix * add jest * add husky * add bundlewatch
This commit is contained in:
parent
84b46a76a8
commit
4b219df40c
|
@ -0,0 +1,4 @@
|
|||
/node_modules
|
||||
/dist
|
||||
/coverage
|
||||
!.*.js
|
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint", "react-hooks", "simple-import-sort"],
|
||||
"extends": [
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"curly": "error",
|
||||
"no-extra-boolean-cast": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "warn",
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-object-literal-type-assertion": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{ "ignoreRestSiblings": true }
|
||||
],
|
||||
"cypress/no-unnecessary-waiting": "off",
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"react-hooks/exhaustive-deps": "error",
|
||||
"react/display-name": "warn",
|
||||
"react/prop-types": "off",
|
||||
"no-console": ["error"],
|
||||
"simple-import-sort/imports": [
|
||||
"error",
|
||||
{
|
||||
"groups": [
|
||||
// Side effect imports.
|
||||
["^\\u0000"],
|
||||
// Packages. `react` related packages come first.
|
||||
["^react", "^@?\\w"],
|
||||
// Parent imports. Put `..` last.
|
||||
["^\\.\\.(?!/?$)", "^\\.\\./?$"],
|
||||
// Other relative imports. Put same-folder imports and `.` last.
|
||||
["^\\./(?=.*/)(?!/?$)", "^\\.(?!/?$)", "^\\./?$"]
|
||||
]
|
||||
}
|
||||
],
|
||||
"simple-import-sort/exports": "error"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.test.ts", "*.test.tsx"],
|
||||
"rules": {
|
||||
// Allow testing runtime errors to suppress TS errors
|
||||
"@typescript-eslint/ban-ts-comment": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"react": {
|
||||
"pragma": "React",
|
||||
"version": "detect"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
.idea/*
|
||||
.angular
|
||||
build
|
||||
bundle
|
||||
dist
|
||||
node_modules
|
||||
src/**.js
|
||||
coverage
|
||||
*.log
|
||||
*.tsbuildinfo
|
||||
docs
|
||||
.DS_Store
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npm run fix
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"singleQuote": false,
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "all"
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
export default {
|
||||
collectCoverageFrom: [
|
||||
"**/**/*.{ts,tsx}",
|
||||
"!**/**/*.test.{ts,tsx}",
|
||||
"!**/src/types/**",
|
||||
"!**/node_modules/**",
|
||||
"!**/dist/**",
|
||||
"!**/__tests__/**",
|
||||
],
|
||||
projects: [
|
||||
{
|
||||
clearMocks: true,
|
||||
resetMocks: true,
|
||||
restoreMocks: true,
|
||||
rootDir: ".",
|
||||
roots: ["<rootDir>/src"],
|
||||
transformIgnorePatterns: ["[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$"],
|
||||
displayName: {
|
||||
name: "@waku/react",
|
||||
color: "cyan",
|
||||
},
|
||||
testMatch: ["**/__tests__/**/*.(spec|test).ts?(x)"],
|
||||
transform: {
|
||||
"^.+\\.tsx?$": "@swc/jest",
|
||||
},
|
||||
testEnvironment: "jsdom",
|
||||
},
|
||||
],
|
||||
watchPlugins: [
|
||||
"jest-watch-typeahead/filename",
|
||||
"jest-watch-typeahead/testname",
|
||||
],
|
||||
};
|
File diff suppressed because it is too large
Load Diff
103
package.json
103
package.json
|
@ -2,15 +2,27 @@
|
|||
"name": "@waku/react",
|
||||
"version": "0.0.1",
|
||||
"description": "React hooks and components to use js-waku",
|
||||
"types": "./dist/index.d.ts",
|
||||
"module": "./dist/index.js",
|
||||
"type": "module",
|
||||
"main": "dist/index.cjs.js",
|
||||
"module": "dist/index.esm.mjs",
|
||||
"umd:main": "dist/index.umd.js",
|
||||
"unpkg": "dist/index.umd.js",
|
||||
"source": "src/index.ts",
|
||||
"types": "dist/src/index.d.ts",
|
||||
"sideEffects": false,
|
||||
"files": [
|
||||
"dist",
|
||||
"CHANGELOG.md",
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
"types": "./dist/src/index.d.ts",
|
||||
"import": "./dist/index.esm.mjs",
|
||||
"require": "./dist/index.cjs.js"
|
||||
}
|
||||
},
|
||||
"type": "module",
|
||||
"homepage": "https://github.com/waku-org/waku-ui",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -30,24 +42,73 @@
|
|||
"react"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "echo 0;",
|
||||
"fix": "echo 0;",
|
||||
"lint": "echo 0;",
|
||||
"test": "echo 0;",
|
||||
"prepublish": "npm run build"
|
||||
"prebuild": "rimraf dist",
|
||||
"build": "rollup -c ./rollup.config.js",
|
||||
"fix": "npm run lint:fix && npm run prettier:fix",
|
||||
"lint": "eslint '**/*.{js,ts,tsx}'",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"prettier:fix": "prettier --config .prettierrc --write \"**/*.{js,ts,tsx}\"",
|
||||
"type": "tsc --noEmit",
|
||||
"test": "jest --config ./jest.config.js",
|
||||
"test:coverage": "npm run test -- --coverage",
|
||||
"bundlewatch": "npm run build && bundlewatch",
|
||||
"prepublish": "npm run fix && npm run type && npm run test && npm run build"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {},
|
||||
"files": [
|
||||
"dist",
|
||||
"src/*.ts",
|
||||
"!**/*.spec.*",
|
||||
"!**/*.json",
|
||||
"CHANGELOG.md",
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
]
|
||||
"dependencies": {
|
||||
"@waku/core": "^0.0.10",
|
||||
"@waku/create": "^0.0.6",
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^24.0.1",
|
||||
"@swc/jest": "^0.2.24",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/testing-library__jest-dom": "^5.14.5",
|
||||
"@typescript-eslint/eslint-plugin": "^5.52.0",
|
||||
"@waku/interfaces": "^0.0.7",
|
||||
"bundlewatch": "^0.3.3",
|
||||
"eslint": "^8.34.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||
"husky": "^8.0.3",
|
||||
"jest": "^29.4.3",
|
||||
"jest-environment-jsdom": "^29.4.3",
|
||||
"jest-watch-typeahead": "^2.2.2",
|
||||
"prettier": "^2.8.4",
|
||||
"rimraf": "^4.1.2",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.4",
|
||||
"rollup-plugin-sourcemaps": "^0.6.3",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"rollup-plugin-typescript2": "^0.34.1",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"bundlewatch": {
|
||||
"files": [
|
||||
{
|
||||
"path": "./dist/index.cjs.js",
|
||||
"maxSize": "4 kB"
|
||||
}
|
||||
]
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,ts,tsx}": [
|
||||
"npm run fix"
|
||||
],
|
||||
"*.{md,json,yml}": [
|
||||
"prettier --write"
|
||||
]
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import commonjs from "@rollup/plugin-commonjs";
|
||||
import external from "rollup-plugin-peer-deps-external";
|
||||
import sourcemaps from "rollup-plugin-sourcemaps";
|
||||
import { terser } from "rollup-plugin-terser";
|
||||
import typescript from "rollup-plugin-typescript2";
|
||||
|
||||
function createRollupConfig(options) {
|
||||
const name = options.name;
|
||||
// A file with the extension ".mjs" will always be treated as ESM, even when pkg.type is "commonjs" (the default)
|
||||
// https://nodejs.org/docs/latest/api/packages.html#packages_determining_module_system
|
||||
const extName = options.format === "esm" ? "mjs" : "js";
|
||||
const outputName = "dist/" + [name, options.format, extName].join(".");
|
||||
|
||||
const config = {
|
||||
input: "src/index.ts",
|
||||
output: {
|
||||
file: outputName,
|
||||
format: options.format,
|
||||
name: "@waku/react",
|
||||
sourcemap: true,
|
||||
globals: { react: "React" },
|
||||
exports: "named",
|
||||
},
|
||||
plugins: [
|
||||
external(),
|
||||
typescript({
|
||||
tsconfig: options.tsconfig,
|
||||
clean: true,
|
||||
exclude: ["**/__tests__", "**/*.test.ts"],
|
||||
}),
|
||||
options.format === "umd" &&
|
||||
commonjs({
|
||||
include: /\/node_modules\//,
|
||||
}),
|
||||
sourcemaps(),
|
||||
options.format !== "esm" &&
|
||||
terser({
|
||||
output: { comments: false },
|
||||
compress: {
|
||||
drop_console: true,
|
||||
},
|
||||
}),
|
||||
].filter(Boolean),
|
||||
};
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
const name = "index";
|
||||
const source = "src/index.ts";
|
||||
|
||||
const options = [
|
||||
{
|
||||
name,
|
||||
format: "cjs",
|
||||
input: source,
|
||||
},
|
||||
{ name, format: "esm", input: source },
|
||||
{
|
||||
name,
|
||||
format: "umd",
|
||||
input: source,
|
||||
},
|
||||
];
|
||||
|
||||
export default options.map((option) => createRollupConfig(option));
|
|
@ -0,0 +1,134 @@
|
|||
import React from "react";
|
||||
import type { Waku } from "@waku/interfaces";
|
||||
|
||||
import type {
|
||||
BootstrapNodeOptions,
|
||||
CrateWakuHook,
|
||||
FullNodeOptions,
|
||||
LightNodeOptions,
|
||||
RelayNodeOptions,
|
||||
} from "./types";
|
||||
import {
|
||||
useCreateFullNode,
|
||||
useCreateLightNode,
|
||||
useCreateRelayNode,
|
||||
} from "./useCreateWaku";
|
||||
|
||||
type WakuContextType<T extends Waku> = CrateWakuHook<T>;
|
||||
|
||||
export const WakuContext = React.createContext<WakuContextType<Waku>>({
|
||||
node: null,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
});
|
||||
|
||||
/**
|
||||
* Hook to retrieve Waku node from Context. By default generic Waku type will be used.
|
||||
* @example
|
||||
* const { node, isLoading, error } = useWaku<LightNode>();
|
||||
* @example
|
||||
* const { node, isLoading, error } = useWaku<RelayNode>();
|
||||
* @example
|
||||
* const { node, isLoading, error } = useWaku<FullNode>();
|
||||
* @example
|
||||
* const { node, isLoading, error } = useWaku();
|
||||
* @returns WakuContext
|
||||
*/
|
||||
export const useWaku = <T extends Waku>(): WakuContextType<T> =>
|
||||
React.useContext(WakuContext) as WakuContextType<T>;
|
||||
|
||||
type ReactChildrenProps = {
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type ProviderProps<T> = ReactChildrenProps & BootstrapNodeOptions<T>;
|
||||
|
||||
/**
|
||||
* Provider for creating Light Node based on options passed.
|
||||
* @example
|
||||
* const App = (props) => (
|
||||
* <LightNodeProvider options={{...}}>
|
||||
* <Component />
|
||||
* </LightNodeProvider>
|
||||
* );
|
||||
* const Component = (props) => {
|
||||
* const { node, isLoading, error } = useWaku<LightNode>();
|
||||
* ...
|
||||
* };
|
||||
* @param {Object} props - options to create a node and other React props
|
||||
* @param {LightNodeOptions} 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<LightNodeOptions>
|
||||
> = (props) => {
|
||||
const result = useCreateLightNode({
|
||||
options: props.options,
|
||||
protocols: props.protocols,
|
||||
});
|
||||
|
||||
return (
|
||||
<WakuContext.Provider value={result}>{props.children}</WakuContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Provider for creating Relay Node based on options passed.
|
||||
* @example
|
||||
* const App = (props) => (
|
||||
* <RelayNodeProvider options={{...}}>
|
||||
* <Component />
|
||||
* </RelayNodeProvider>
|
||||
* );
|
||||
* const Component = (props) => {
|
||||
* const { node, isLoading, error } = useWaku<RelayNode>();
|
||||
* ...
|
||||
* };
|
||||
* @param {Object} props - options to create a node and other React props
|
||||
* @param {RelayNodeOptions} props.options - optional options for creating Relay Node
|
||||
* @param {Protocols} props.protocols - optional protocols list to initiate node with
|
||||
* @returns React Relay Node provider component
|
||||
*/
|
||||
export const RelayNodeProvider: React.FunctionComponent<
|
||||
ProviderProps<RelayNodeOptions>
|
||||
> = (props) => {
|
||||
const result = useCreateRelayNode({
|
||||
options: props.options,
|
||||
protocols: props.protocols,
|
||||
});
|
||||
|
||||
return (
|
||||
<WakuContext.Provider value={result}>{props.children}</WakuContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Provider for creating Full Node based on options passed.
|
||||
* @example
|
||||
* const App = (props) => (
|
||||
* <FullNodeProvider options={{...}}>
|
||||
* <Component />
|
||||
* </FullNodeProvider>
|
||||
* );
|
||||
* const Component = (props) => {
|
||||
* const { node, isLoading, error } = useWaku<FullNode>();
|
||||
* ...
|
||||
* };
|
||||
* @param {Object} props - options to create a node and other React props
|
||||
* @param {FullNodeOptions} props.options - optional options for creating Full Node
|
||||
* @param {Protocols} props.protocols - optional protocols list to initiate node with
|
||||
* @returns React Full Node provider component
|
||||
*/
|
||||
export const FullNodeProvider: React.FunctionComponent<
|
||||
ProviderProps<FullNodeOptions>
|
||||
> = (props) => {
|
||||
const result = useCreateFullNode({
|
||||
options: props.options,
|
||||
protocols: props.protocols,
|
||||
});
|
||||
|
||||
return (
|
||||
<WakuContext.Provider value={result}>{props.children}</WakuContext.Provider>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,15 @@
|
|||
export { FullNodeOptions, LightNodeOptions, RelayNodeOptions } from "./types";
|
||||
export { useContentPair } from "./useContentPair";
|
||||
export {
|
||||
useCreateFullNode,
|
||||
useCreateLightNode,
|
||||
useCreateRelayNode,
|
||||
} from "./useCreateWaku";
|
||||
export { useFilterSubscribe } from "./useFilterSubscribe";
|
||||
export {
|
||||
FullNodeProvider,
|
||||
LightNodeProvider,
|
||||
RelayNodeProvider,
|
||||
useWaku,
|
||||
WakuContext,
|
||||
} from "./WakuProvider";
|
|
@ -0,0 +1,25 @@
|
|||
import { RelayCreateOptions, WakuOptions } from "@waku/core";
|
||||
import type { CreateOptions } from "@waku/create";
|
||||
import type { Protocols, Waku } from "@waku/interfaces";
|
||||
|
||||
export type HookState = {
|
||||
isLoading: boolean;
|
||||
error: null | string;
|
||||
};
|
||||
|
||||
export type CrateWakuHook<T extends Waku> = HookState & {
|
||||
node: null | T;
|
||||
};
|
||||
|
||||
export type BootstrapNodeOptions<T = {}> = {
|
||||
options?: T;
|
||||
protocols?: Protocols[];
|
||||
};
|
||||
|
||||
export type LightNodeOptions = CreateOptions & WakuOptions;
|
||||
export type RelayNodeOptions = CreateOptions &
|
||||
WakuOptions &
|
||||
Partial<RelayCreateOptions>;
|
||||
export type FullNodeOptions = CreateOptions &
|
||||
WakuOptions &
|
||||
Partial<RelayCreateOptions>;
|
|
@ -0,0 +1,32 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { createDecoder, createEncoder } from "@waku/core";
|
||||
import type { Decoder, Encoder } from "@waku/core/dist/lib/message/version_0";
|
||||
|
||||
type ContentPair = {
|
||||
encoder: null | Encoder;
|
||||
decoder: null | Decoder;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates Encoder / Decoder pair for a given contentTopic.
|
||||
* @param {string} contentTopic - topic to orient to
|
||||
* @param {boolean} ephemeral - optional, makes messages ephemeral
|
||||
* @returns {Object} Encoder / Decoder pair
|
||||
*/
|
||||
export const useContentPair = (
|
||||
contentTopic: string,
|
||||
ephemeral?: boolean,
|
||||
): ContentPair => {
|
||||
const [encoder, setEncoder] = useState<null | Encoder>(null);
|
||||
const [decoder, setDecoder] = useState<null | Decoder>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setEncoder(createEncoder(contentTopic, ephemeral));
|
||||
setDecoder(createDecoder(contentTopic));
|
||||
}, [contentTopic, ephemeral]);
|
||||
|
||||
return {
|
||||
encoder,
|
||||
decoder,
|
||||
};
|
||||
};
|
|
@ -0,0 +1,102 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { waitForRemotePeer } from "@waku/core";
|
||||
import { createFullNode, createLightNode, createRelayNode } from "@waku/create";
|
||||
import type { FullNode, LightNode, RelayNode, Waku } from "@waku/interfaces";
|
||||
|
||||
import type {
|
||||
BootstrapNodeOptions,
|
||||
CrateWakuHook,
|
||||
FullNodeOptions,
|
||||
LightNodeOptions,
|
||||
RelayNodeOptions,
|
||||
} from "./types";
|
||||
|
||||
type NodeFactory<N, T = {}> = (options?: T) => Promise<N>;
|
||||
|
||||
type CreateNodeParams<N extends Waku, T = {}> = BootstrapNodeOptions<T> & {
|
||||
factory: NodeFactory<N, T>;
|
||||
};
|
||||
|
||||
const useCreateNode = <N extends Waku, T = {}>(
|
||||
params: CreateNodeParams<N, T>,
|
||||
): CrateWakuHook<N> => {
|
||||
const { factory, options, protocols = [] } = params;
|
||||
|
||||
const [node, setNode] = useState<N | null>(null);
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const [error, setError] = useState<null | string>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
setLoading(true);
|
||||
|
||||
factory(options)
|
||||
.then(async (node) => {
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
await node.start();
|
||||
await waitForRemotePeer(node, protocols);
|
||||
|
||||
setNode(node);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
setLoading(false);
|
||||
setError(`Failed at creating node: ${err?.message || "no message"}`);
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [factory, options, protocols, setNode, setLoading, setError]);
|
||||
|
||||
return {
|
||||
node,
|
||||
error,
|
||||
isLoading,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Light Node helper hook.
|
||||
* @param {Object} params - optional params to configure & bootstrap node
|
||||
* @returns {CrateWakuHook} node, loading state and error
|
||||
*/
|
||||
export const useCreateLightNode = (
|
||||
params?: BootstrapNodeOptions<LightNodeOptions>,
|
||||
) => {
|
||||
return useCreateNode<LightNode, LightNodeOptions>({
|
||||
...params,
|
||||
factory: createLightNode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Relay Node helper hook.
|
||||
* @param {Object} params - optional params to configure & bootstrap node
|
||||
* @returns {CrateWakuHook} node, loading state and error
|
||||
*/
|
||||
export const useCreateRelayNode = (
|
||||
params?: BootstrapNodeOptions<RelayNodeOptions>,
|
||||
) => {
|
||||
return useCreateNode<RelayNode, RelayNodeOptions>({
|
||||
...params,
|
||||
factory: createRelayNode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Full Node helper hook.
|
||||
* @param {Object} params - optional params to configure & bootstrap node
|
||||
* @returns {CrateWakuHook} node, loading state and error
|
||||
*/
|
||||
export const useCreateFullNode = (
|
||||
params?: BootstrapNodeOptions<FullNodeOptions>,
|
||||
) => {
|
||||
return useCreateNode<FullNode, FullNodeOptions>({
|
||||
...params,
|
||||
factory: createFullNode,
|
||||
});
|
||||
};
|
|
@ -0,0 +1,58 @@
|
|||
import { useCallback, useEffect, useState } from "react";
|
||||
import type { IDecodedMessage, IDecoder, Waku } from "@waku/interfaces";
|
||||
|
||||
import type { HookState } from "./types";
|
||||
|
||||
type UseFilterSubscribeParams = {
|
||||
waku: Waku;
|
||||
decoder: IDecoder<IDecodedMessage>;
|
||||
};
|
||||
|
||||
type UseFilterSubscribeResult = HookState & {
|
||||
messages: IDecodedMessage[];
|
||||
};
|
||||
|
||||
export const useFilterSubscribe = (
|
||||
params: UseFilterSubscribeParams,
|
||||
): UseFilterSubscribeResult => {
|
||||
const { waku, decoder } = params;
|
||||
|
||||
const [error, setError] = useState<null | string>(null);
|
||||
const [isLoading, setLoading] = useState<boolean>(false);
|
||||
const [messages, setMessage] = useState<IDecodedMessage[]>([]);
|
||||
|
||||
const pushMessage = useCallback(
|
||||
(message: IDecodedMessage): void => {
|
||||
setMessage((prev) => [...prev, message]);
|
||||
},
|
||||
[setMessage],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let unsubscribe: null | (() => Promise<void>) = null;
|
||||
setLoading(true);
|
||||
|
||||
waku?.filter
|
||||
?.subscribe([decoder], pushMessage)
|
||||
.then((unsubscribeFn) => {
|
||||
setLoading(false);
|
||||
unsubscribe = unsubscribeFn;
|
||||
})
|
||||
.catch((err) => {
|
||||
setLoading(false);
|
||||
setError(
|
||||
`Failed to subscribe to filer: ${err?.message || "no message"}`,
|
||||
);
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubscribe?.();
|
||||
};
|
||||
}, [waku, decoder, pushMessage, setError, setLoading]);
|
||||
|
||||
return {
|
||||
error,
|
||||
messages,
|
||||
isLoading,
|
||||
};
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"sourceMap": true,
|
||||
"module": "es2015",
|
||||
"target": "es2018",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./dist",
|
||||
"jsx": "react",
|
||||
"skipLibCheck": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"examples",
|
||||
"src/*.test.ts",
|
||||
"src/*.test.tsx",
|
||||
"src/__mocks__"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue