feat: move to nextjs

This commit is contained in:
apoorvlathey
2024-05-07 00:18:18 +10:00
parent 602ae4389e
commit 032785a316
49 changed files with 9867 additions and 8425 deletions

120
helpers/communicator.ts Normal file
View File

@@ -0,0 +1,120 @@
import { MutableRefObject, useEffect, useState } from "react";
import { MessageFormatter } from "./messageFormatter";
import {
SDKMessageEvent,
MethodToResponse,
Methods,
ErrorResponse,
RequestId,
} from "../types";
import { getSDKVersion } from "./utils";
type MessageHandler = (
msg: SDKMessageEvent
) =>
| void
| MethodToResponse[Methods]
| ErrorResponse
| Promise<MethodToResponse[Methods] | ErrorResponse | void>;
export enum LegacyMethods {
getEnvInfo = "getEnvInfo",
}
type SDKMethods = Methods | LegacyMethods;
class AppCommunicator {
private iframeRef: MutableRefObject<HTMLIFrameElement | null>;
private handlers = new Map<SDKMethods, MessageHandler>();
constructor(iframeRef: MutableRefObject<HTMLIFrameElement | null>) {
this.iframeRef = iframeRef;
window.addEventListener("message", this.handleIncomingMessage);
}
on = (method: SDKMethods, handler: MessageHandler): void => {
this.handlers.set(method, handler);
};
private isValidMessage = (msg: SDKMessageEvent): boolean => {
if (msg.data.hasOwnProperty("isCookieEnabled")) {
return true;
}
const sentFromIframe = this.iframeRef.current?.contentWindow === msg.source;
const knownMethod = Object.values(Methods).includes(msg.data.method);
return sentFromIframe && knownMethod;
};
private canHandleMessage = (msg: SDKMessageEvent): boolean => {
return Boolean(this.handlers.get(msg.data.method));
};
send = (data: unknown, requestId: RequestId, error = false): void => {
const sdkVersion = getSDKVersion();
const msg = error
? MessageFormatter.makeErrorResponse(
requestId,
data as string,
sdkVersion
)
: MessageFormatter.makeResponse(requestId, data, sdkVersion);
// console.log("send", { msg });
this.iframeRef.current?.contentWindow?.postMessage(msg, "*");
};
handleIncomingMessage = async (msg: SDKMessageEvent): Promise<void> => {
const validMessage = this.isValidMessage(msg);
const hasHandler = this.canHandleMessage(msg);
if (validMessage && hasHandler) {
// console.log("incoming", { msg: msg.data });
const handler = this.handlers.get(msg.data.method);
try {
// @ts-expect-error Handler existence is checked in this.canHandleMessage
const response = await handler(msg);
// If response is not returned, it means the response will be send somewhere else
if (typeof response !== "undefined") {
this.send(response, msg.data.id);
}
} catch (err: any) {
this.send(err.message, msg.data.id, true);
}
}
};
clear = (): void => {
window.removeEventListener("message", this.handleIncomingMessage);
};
}
const useAppCommunicator = (
iframeRef: MutableRefObject<HTMLIFrameElement | null>
): AppCommunicator | undefined => {
const [communicator, setCommunicator] = useState<AppCommunicator | undefined>(
undefined
);
useEffect(() => {
let communicatorInstance: AppCommunicator;
const initCommunicator = (
iframeRef: MutableRefObject<HTMLIFrameElement>
) => {
communicatorInstance = new AppCommunicator(iframeRef);
setCommunicator(communicatorInstance);
};
initCommunicator(iframeRef as MutableRefObject<HTMLIFrameElement>);
return () => {
communicatorInstance?.clear();
};
}, [iframeRef]);
return communicator;
};
export { useAppCommunicator };

View File

@@ -0,0 +1,51 @@
import {
ErrorResponse,
SDKRequestData,
RequestId,
SuccessResponse,
MethodToResponse,
Methods,
} from "../types";
import { getSDKVersion, generateRequestId } from "./utils";
class MessageFormatter {
static makeRequest = <M extends Methods = Methods, P = unknown>(
method: M,
params: P
): SDKRequestData<M, P> => {
const id = generateRequestId();
return {
id,
method,
params,
env: {
sdkVersion: getSDKVersion(),
},
};
};
static makeResponse = (
id: RequestId,
data: MethodToResponse[Methods],
version: string
): SuccessResponse => ({
id,
success: true,
version,
data,
});
static makeErrorResponse = (
id: RequestId,
error: string,
version: string
): ErrorResponse => ({
id,
success: false,
error,
version,
});
}
export { MessageFormatter };

20
helpers/utils.ts Normal file
View File

@@ -0,0 +1,20 @@
export const getSDKVersion = () => {
return "7.6.0"; // IMPORTANT: needs to be >= 1.0.0
};
// i.e. 0-255 -> '00'-'ff'
const dec2hex = (dec: number): string => dec.toString(16).padStart(2, "0");
const generateId = (len: number): string => {
const arr = new Uint8Array((len || 40) / 2);
window.crypto.getRandomValues(arr);
return Array.from(arr, dec2hex).join("");
};
export const generateRequestId = (): string => {
if (typeof window !== "undefined") {
return generateId(10);
}
return new Date().getTime().toString(36);
};