mirror of
https://github.com/logos-messaging/logos-messaging-frontend.git
synced 2026-01-04 06:43:08 +00:00
update deps, fetching
This commit is contained in:
parent
d0b28bfbbf
commit
cc6b09e325
4046
package-lock.json
generated
4046
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -11,14 +11,12 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@waku/rln": "0.1.1-7e8cb89",
|
"@waku/rln": "0.1.1-7e8cb89",
|
||||||
"@waku/sdk": "^0.0.20",
|
|
||||||
"@waku/utils": "^0.0.12",
|
"@waku/utils": "^0.0.12",
|
||||||
"ethers": "^5.7.2",
|
"ethers": "^5.7.2",
|
||||||
"multiaddr": "^10.0.1",
|
|
||||||
"next": "13.5.6",
|
"next": "13.5.6",
|
||||||
"protobufjs": "^7.2.5",
|
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
|
"uuid": "^9.0.1",
|
||||||
"zustand": "^4.4.4"
|
"zustand": "^4.4.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -26,6 +24,7 @@
|
|||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
|
"@types/uuid": "^9.0.6",
|
||||||
"autoprefixer": "^10",
|
"autoprefixer": "^10",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "13.5.6",
|
"eslint-config-next": "13.5.6",
|
||||||
|
|||||||
@ -1,15 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Block } from "@/components/Block";
|
import { Block } from "@/components/Block";
|
||||||
import { Subtitle } from "@/components/Subtitle";
|
import { Subtitle } from "@/components/Subtitle";
|
||||||
import { Status } from "@/components/Status";
|
|
||||||
import { Button } from "@/components/Button";
|
import { Button } from "@/components/Button";
|
||||||
import { useStore, useWaku } from "@/hooks";
|
import { MessageContent, useWaku } from "@/hooks";
|
||||||
import { MessageContent } from "@/services/waku";
|
|
||||||
|
|
||||||
export const Waku: React.FunctionComponent<{}> = () => {
|
export const Waku: React.FunctionComponent<{}> = () => {
|
||||||
const { wakuStatus } = useStore();
|
|
||||||
const { onSend, messages } = useWaku();
|
const { onSend, messages } = useWaku();
|
||||||
|
|
||||||
const { nick, text, onNickChange, onMessageChange, resetText } = useMessage();
|
const { nick, text, onNickChange, onMessageChange, resetText } = useMessage();
|
||||||
|
|
||||||
const onSendClick = async () => {
|
const onSendClick = async () => {
|
||||||
@ -106,7 +102,7 @@ function renderMessage(content: MessageContent) {
|
|||||||
<p>
|
<p>
|
||||||
<span className="text-lg">{content.nick}</span>
|
<span className="text-lg">{content.nick}</span>
|
||||||
<span className="text-sm font-bold">
|
<span className="text-sm font-bold">
|
||||||
({content.proofStatus}, {content.time})
|
({content.time})
|
||||||
</span>
|
</span>
|
||||||
:
|
:
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@ -1,17 +1,5 @@
|
|||||||
import protobuf from "protobufjs";
|
|
||||||
|
|
||||||
export type ProtoChatMessageType = {
|
|
||||||
timestamp: number;
|
|
||||||
nick: string;
|
|
||||||
text: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ProtoChatMessage = new protobuf.Type("ChatMessage")
|
|
||||||
.add(new protobuf.Field("timestamp", 1, "uint64"))
|
|
||||||
.add(new protobuf.Field("nick", 2, "string"))
|
|
||||||
.add(new protobuf.Field("text", 3, "string"));
|
|
||||||
|
|
||||||
export const CONTENT_TOPIC = "/toy-chat/2/luzhou/proto";
|
export const CONTENT_TOPIC = "/toy-chat/2/luzhou/proto";
|
||||||
|
export const PUBSUB_TOPIC = "/waku/2/default-waku/proto";
|
||||||
|
|
||||||
export const SIGNATURE_MESSAGE =
|
export const SIGNATURE_MESSAGE =
|
||||||
"The signature of this message will be used to generate your RLN credentials. Anyone accessing it may send messages on your behalf, please only share with the RLN dApp";
|
"The signature of this message will be used to generate your RLN credentials. Anyone accessing it may send messages on your behalf, please only share with the RLN dApp";
|
||||||
|
|||||||
@ -3,3 +3,4 @@ export { useRLN } from "./useRLN";
|
|||||||
export { useWallet } from "./useWallet";
|
export { useWallet } from "./useWallet";
|
||||||
export { useContract } from "./useContract";
|
export { useContract } from "./useContract";
|
||||||
export { useWaku } from "./useWaku";
|
export { useWaku } from "./useWaku";
|
||||||
|
export type { MessageContent } from "./useWaku";
|
||||||
|
|||||||
@ -1,67 +1,55 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { waku, Waku, WakuEventsNames, MessageContent } from "@/services/waku";
|
import { CONTENT_TOPIC } from "@/constants";
|
||||||
import { useStore } from "./useStore";
|
import { Message, waku } from "@/services/waku";
|
||||||
import { useRLN } from "./useRLN";
|
|
||||||
|
export type MessageContent = {
|
||||||
|
nick: string;
|
||||||
|
text: string;
|
||||||
|
time: string;
|
||||||
|
};
|
||||||
|
|
||||||
export const useWaku = () => {
|
export const useWaku = () => {
|
||||||
const wakuRef = React.useRef<Waku>();
|
|
||||||
const [messages, setMessages] = React.useState<MessageContent[]>([]);
|
const [messages, setMessages] = React.useState<MessageContent[]>([]);
|
||||||
|
|
||||||
const { rln } = useRLN();
|
|
||||||
const { activeMembershipID, credentials, setWakuStatus } = useStore();
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!credentials || !activeMembershipID || !rln) {
|
const messageListener = (event: CustomEvent) => {
|
||||||
return;
|
const messages: Message[] = event.detail;
|
||||||
}
|
const parsedMessaged = messages.map((message) => {
|
||||||
|
const time = new Date(message.timestamp);
|
||||||
|
const payload = JSON.parse(atob(message.payload));
|
||||||
|
|
||||||
const statusListener = (event: CustomEvent) => {
|
return {
|
||||||
setWakuStatus(event.detail || "");
|
nick: payload?.nick || "unknown",
|
||||||
};
|
text: payload?.text || "empty",
|
||||||
waku.addEventListener(WakuEventsNames.Status, statusListener);
|
time: time.toDateString(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const messagesListener = (event: CustomEvent) => {
|
setMessages((prev) => [...prev, ...parsedMessaged]);
|
||||||
setMessages((prev) => [...prev, event.detail as MessageContent]);
|
|
||||||
};
|
|
||||||
waku.addEventListener(WakuEventsNames.Message, messagesListener);
|
|
||||||
|
|
||||||
let terminated = false;
|
|
||||||
const run = async () => {
|
|
||||||
if (terminated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
rln,
|
|
||||||
credentials,
|
|
||||||
membershipID: activeMembershipID,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!wakuRef.current) {
|
|
||||||
await waku.init(options);
|
|
||||||
wakuRef.current = waku;
|
|
||||||
} else {
|
|
||||||
wakuRef.current.initEncoder(options);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
run();
|
waku.filter.addEventListener(CONTENT_TOPIC, messageListener);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
terminated = true;
|
waku.filter.removeEventListener(CONTENT_TOPIC, messageListener);
|
||||||
waku.removeEventListener(WakuEventsNames.Status, statusListener);
|
|
||||||
waku.removeEventListener(WakuEventsNames.Message, messagesListener);
|
|
||||||
};
|
};
|
||||||
}, [activeMembershipID, credentials, rln, setWakuStatus]);
|
}, [setMessages]);
|
||||||
|
|
||||||
const onSend = React.useCallback(
|
const onSend = React.useCallback(
|
||||||
async (nick: string, text: string) => {
|
async (nick: string, text: string) => {
|
||||||
if (!wakuRef.current) {
|
await waku.lightPush.send({
|
||||||
return;
|
version: 0,
|
||||||
}
|
timestamp: Date.now(),
|
||||||
await wakuRef.current.sendMessage(nick, text);
|
contentTopic: CONTENT_TOPIC,
|
||||||
|
payload: btoa(JSON.stringify({
|
||||||
|
nick,
|
||||||
|
text
|
||||||
|
})),
|
||||||
|
});
|
||||||
},
|
},
|
||||||
[wakuRef]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { onSend, messages };
|
return { onSend, messages };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,202 +1,140 @@
|
|||||||
|
import { v4 as uuid } from "uuid";
|
||||||
import {
|
import {
|
||||||
createLightNode,
|
PUBSUB_TOPIC,
|
||||||
createEncoder,
|
|
||||||
createDecoder,
|
|
||||||
IDecodedMessage,
|
|
||||||
LightNode,
|
|
||||||
waitForRemotePeer,
|
|
||||||
} from "@waku/sdk";
|
|
||||||
import {
|
|
||||||
CONTENT_TOPIC,
|
|
||||||
ProtoChatMessage,
|
|
||||||
ProtoChatMessageType,
|
|
||||||
} from "@/constants";
|
} from "@/constants";
|
||||||
import {
|
import { http } from "@/utils/http";
|
||||||
RLNDecoder,
|
|
||||||
RLNEncoder,
|
|
||||||
IdentityCredential,
|
|
||||||
RLNInstance,
|
|
||||||
RLNContract,
|
|
||||||
} from "@waku/rln";
|
|
||||||
import { RLN } from "@/services/rln";
|
|
||||||
|
|
||||||
type InitOptions = {
|
export type Message = {
|
||||||
membershipID: number;
|
payload: string,
|
||||||
credentials: IdentityCredential;
|
contentTopic: string,
|
||||||
rln: RLN;
|
version: number,
|
||||||
|
timestamp: number
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MessageContent = {
|
|
||||||
nick: string;
|
|
||||||
text: string;
|
|
||||||
time: string;
|
|
||||||
proofStatus: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type SubscribeOptions = {
|
|
||||||
rlnContract: RLNContract;
|
|
||||||
node: LightNode;
|
|
||||||
decoder: RLNDecoder<IDecodedMessage>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export enum WakuEventsNames {
|
|
||||||
Status = "status",
|
|
||||||
Message = "message",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum WakuStatusEventPayload {
|
|
||||||
INITIALIZING = "Initializing",
|
|
||||||
WAITING_FOR_PEERS = "Waiting for peers",
|
|
||||||
STARTING = "Starting the node",
|
|
||||||
READY = "Ready",
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListener = (event: CustomEvent) => void;
|
type EventListener = (event: CustomEvent) => void;
|
||||||
|
|
||||||
interface IWaku {
|
const SECOND = 1000;
|
||||||
init: (options: InitOptions) => void;
|
const LOCAL_NODE = "http://127.0.0.1:8645/";
|
||||||
initEncoder: (options: InitOptions) => void;
|
const FILTER_URL = "/filter/v2/";
|
||||||
addEventListener: (name: WakuEventsNames, fn: EventListener) => void;
|
const LIGHT_PUSH = "/lightpush/v1/";
|
||||||
removeEventListener: (name: WakuEventsNames, fn: EventListener) => void;
|
|
||||||
|
class Filter {
|
||||||
|
private readonly internalEmitter = new EventTarget();
|
||||||
|
private readonly subscriptionsEmitter = new EventTarget();
|
||||||
|
|
||||||
|
private contentTopicToRequestID: Map<string, string> = new Map();
|
||||||
|
private contentTopicListeners: Map<string, number> = new Map();
|
||||||
|
|
||||||
|
// only one content topic subscriptions is possible now
|
||||||
|
private subscriptionRoutine: undefined | number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.internalEmitter.addEventListener("subscribed", this.handleSubscribed.bind(this));
|
||||||
|
this.internalEmitter.addEventListener("unsubscribed", this.handleUnsubscribed.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleSubscribed(_e: Event) {
|
||||||
|
const event = _e as CustomEvent;
|
||||||
|
const contentTopic = event.detail;
|
||||||
|
const numberOfListeners = this.contentTopicListeners.get(contentTopic);
|
||||||
|
|
||||||
|
// if nwaku node already subscribed to this content topic
|
||||||
|
if (numberOfListeners) {
|
||||||
|
this.contentTopicListeners.set(contentTopic, numberOfListeners + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestId = uuid();
|
||||||
|
await http.post(`${LOCAL_NODE}/${FILTER_URL}/subscriptions`, {
|
||||||
|
requestId,
|
||||||
|
contentFilters: [contentTopic],
|
||||||
|
pubsubTopic: PUBSUB_TOPIC
|
||||||
|
});
|
||||||
|
|
||||||
|
this.subscriptionRoutine = window.setInterval(async () => {
|
||||||
|
await this.fetchMessages();
|
||||||
|
}, SECOND);
|
||||||
|
|
||||||
|
this.contentTopicToRequestID.set(contentTopic, requestId);
|
||||||
|
this.contentTopicListeners.set(contentTopic, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleUnsubscribed(_e: Event) {
|
||||||
|
const event = _e as CustomEvent;
|
||||||
|
const contentTopic = event.detail;
|
||||||
|
const requestId = this.contentTopicToRequestID.get(contentTopic);
|
||||||
|
const numberOfListeners = this.contentTopicListeners.get(contentTopic);
|
||||||
|
|
||||||
|
if (!numberOfListeners || !requestId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numberOfListeners - 1 > 0) {
|
||||||
|
this.contentTopicListeners.set(contentTopic, numberOfListeners - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await http.delete(`${LOCAL_NODE}/${FILTER_URL}/subscriptions`, {
|
||||||
|
requestId,
|
||||||
|
contentFilters: [contentTopic],
|
||||||
|
pubsubTopic: PUBSUB_TOPIC
|
||||||
|
});
|
||||||
|
|
||||||
|
clearInterval(this.subscriptionRoutine);
|
||||||
|
this.contentTopicListeners.delete(contentTopic);
|
||||||
|
this.contentTopicToRequestID.delete(contentTopic);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchMessages(): Promise<void> {
|
||||||
|
const contentTopic = Object.keys(this.contentTopicListeners)[0];
|
||||||
|
|
||||||
|
if (!contentTopic) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await http.get(`${LOCAL_NODE}/${FILTER_URL}/${encodeURIComponent(contentTopic)}`);
|
||||||
|
const body: Message[] = await response.json();
|
||||||
|
|
||||||
|
if (!body || !body.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.subscriptionsEmitter.dispatchEvent(
|
||||||
|
new CustomEvent(contentTopic, { detail: body })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public addEventListener(contentTopic: string, fn: EventListener) {
|
||||||
|
this.emitSubscribedEvent(contentTopic);
|
||||||
|
return this.subscriptionsEmitter.addEventListener(contentTopic, fn as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeEventListener(contentTopic: string, fn: EventListener) {
|
||||||
|
this.emitUnsubscribedEvent(contentTopic);
|
||||||
|
return this.subscriptionsEmitter.removeEventListener(contentTopic, fn as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
private emitSubscribedEvent(contentTopic: string) {
|
||||||
|
this.internalEmitter.dispatchEvent(new CustomEvent("subscribed", { detail: contentTopic }));
|
||||||
|
}
|
||||||
|
|
||||||
|
private emitUnsubscribedEvent(contentTopic: string) {
|
||||||
|
this.internalEmitter.dispatchEvent(new CustomEvent("unsubscribed", { detail: contentTopic }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Waku implements IWaku {
|
class LightPush {
|
||||||
private contentTopic = CONTENT_TOPIC;
|
|
||||||
private readonly emitter = new EventTarget();
|
|
||||||
|
|
||||||
public node: undefined | LightNode;
|
|
||||||
|
|
||||||
private encoder: undefined | RLNEncoder;
|
|
||||||
private decoder: undefined | RLNDecoder<IDecodedMessage>;
|
|
||||||
|
|
||||||
private initialized = false;
|
|
||||||
private initializing = false;
|
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
public async init(options: InitOptions) {
|
public async send(message: Message): Promise<void> {
|
||||||
if (this.initialized || this.initializing || !options.rln.rlnInstance) {
|
await http.post(`${LOCAL_NODE}/${LIGHT_PUSH}/message`, {
|
||||||
return;
|
pubsubTopic: PUBSUB_TOPIC,
|
||||||
}
|
message,
|
||||||
|
|
||||||
this.initializing = true;
|
|
||||||
|
|
||||||
this.initEncoder(options);
|
|
||||||
this.decoder = new RLNDecoder(
|
|
||||||
options.rln.rlnInstance,
|
|
||||||
createDecoder(this.contentTopic)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!this.node) {
|
|
||||||
this.emitStatusEvent(WakuStatusEventPayload.INITIALIZING);
|
|
||||||
this.node = await createLightNode({ defaultBootstrap: true });
|
|
||||||
this.emitStatusEvent(WakuStatusEventPayload.STARTING);
|
|
||||||
await this.node.start();
|
|
||||||
this.emitStatusEvent(WakuStatusEventPayload.WAITING_FOR_PEERS);
|
|
||||||
await waitForRemotePeer(this.node);
|
|
||||||
this.emitStatusEvent(WakuStatusEventPayload.READY);
|
|
||||||
|
|
||||||
if (options.rln.rlnContract) {
|
|
||||||
await this.subscribeToMessages({
|
|
||||||
node: this.node,
|
|
||||||
decoder: this.decoder,
|
|
||||||
rlnContract: options.rln.rlnContract,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.initialized = true;
|
|
||||||
this.initializing = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public initEncoder(options: InitOptions) {
|
|
||||||
const { rln, membershipID, credentials } = options;
|
|
||||||
if (!rln.rlnInstance) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.encoder = new RLNEncoder(
|
|
||||||
createEncoder({
|
|
||||||
ephemeral: false,
|
|
||||||
contentTopic: this.contentTopic,
|
|
||||||
}),
|
|
||||||
rln.rlnInstance,
|
|
||||||
membershipID,
|
|
||||||
credentials
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async sendMessage(nick: string, text: string): Promise<void> {
|
|
||||||
if (!this.node || !this.encoder) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const timestamp = new Date();
|
|
||||||
const msg = ProtoChatMessage.create({
|
|
||||||
text,
|
|
||||||
nick,
|
|
||||||
timestamp: Math.floor(timestamp.valueOf() / 1000),
|
|
||||||
});
|
});
|
||||||
const payload = ProtoChatMessage.encode(msg).finish();
|
|
||||||
console.log("Sending message with proof...");
|
|
||||||
|
|
||||||
await this.node.lightPush.send(this.encoder, { payload, timestamp });
|
|
||||||
console.log("Message sent!");
|
|
||||||
}
|
|
||||||
|
|
||||||
private async subscribeToMessages(options: SubscribeOptions) {
|
|
||||||
await options.node.filter.subscribe(options.decoder, (message) => {
|
|
||||||
try {
|
|
||||||
const { timestamp, nick, text } = ProtoChatMessage.decode(
|
|
||||||
message.payload
|
|
||||||
) as unknown as ProtoChatMessageType;
|
|
||||||
|
|
||||||
let proofStatus = "no proof";
|
|
||||||
if (message.rateLimitProof) {
|
|
||||||
console.log("Proof received: ", message.rateLimitProof);
|
|
||||||
|
|
||||||
try {
|
|
||||||
console.time("Proof verification took:");
|
|
||||||
const res = message.verify(options.rlnContract.roots());
|
|
||||||
console.timeEnd("Proof verification took:");
|
|
||||||
proofStatus = res ? "verified" : "not verified";
|
|
||||||
} catch (error) {
|
|
||||||
proofStatus = "invalid";
|
|
||||||
console.error("Failed to verify proof: ", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emitMessageEvent({
|
|
||||||
nick,
|
|
||||||
text,
|
|
||||||
proofStatus,
|
|
||||||
time: new Date(timestamp).toDateString(),
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed in subscription listener: ", error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public addEventListener(name: WakuEventsNames, fn: EventListener) {
|
|
||||||
return this.emitter.addEventListener(name, fn as any);
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeEventListener(name: WakuEventsNames, fn: EventListener) {
|
|
||||||
return this.emitter.removeEventListener(name, fn as any);
|
|
||||||
}
|
|
||||||
|
|
||||||
private emitStatusEvent(payload: WakuStatusEventPayload) {
|
|
||||||
this.emitter.dispatchEvent(
|
|
||||||
new CustomEvent(WakuEventsNames.Status, { detail: payload })
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private emitMessageEvent(payload: MessageContent) {
|
|
||||||
this.emitter.dispatchEvent(
|
|
||||||
new CustomEvent(WakuEventsNames.Message, { detail: payload })
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const waku = new Waku();
|
export const waku = {
|
||||||
|
filter: new Filter(),
|
||||||
|
lightPush: new LightPush(),
|
||||||
|
};
|
||||||
31
src/utils/http.ts
Normal file
31
src/utils/http.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
export const http = {
|
||||||
|
post(url: string, body: any) {
|
||||||
|
return fetch(url, {
|
||||||
|
method: "POST",
|
||||||
|
mode: "no-cors",
|
||||||
|
referrerPolicy: "no-referrer",
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
delete(url: string, body: any) {
|
||||||
|
return fetch(url, {
|
||||||
|
method: "DELETE",
|
||||||
|
mode: "no-cors",
|
||||||
|
referrerPolicy: "no-referrer",
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
get(url: string) {
|
||||||
|
return fetch(url);
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user