UNPKG

@open-condo/miniapp-utils

Version:

A set of helper functions / components / hooks used to build new condo apps fast

243 lines (240 loc) 9.93 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/helpers/embeddingContext.tsx var embeddingContext_exports = {}; __export(embeddingContext_exports, { getEmbeddingContext: () => getEmbeddingContext, useEmbeddingContext: () => useEmbeddingContext, withEmbeddingContext: () => withEmbeddingContext }); module.exports = __toCommonJS(embeddingContext_exports); var import_cookies_next = require("cookies-next"); var import_react = __toESM(require("react")); var import_zod = require("zod"); // src/helpers/uuid.ts var import_crypto = require("crypto"); function generateUUIDv4() { let randomValues; if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") { return crypto.randomUUID(); } else if (typeof window !== "undefined" && window.crypto && window.crypto.getRandomValues) { randomValues = new Uint8Array(16); window.crypto.getRandomValues(randomValues); } else { randomValues = (0, import_crypto.randomBytes)(16); } randomValues[6] = randomValues[6] & 15 | 64; randomValues[8] = randomValues[8] & 63 | 128; return [...randomValues].map((value, index) => { const hex = value.toString(16).padStart(2, "0"); if (index === 4 || index === 6 || index === 8 || index === 10) { return `-${hex}`; } return hex; }).join(""); } // src/helpers/embeddingContext.tsx var EMBEDDING_CONTEXT_COOKIE_NAME = "embeddingContext"; var EMBEDDING_CONTEXT_QUERY_PARAM = "embeddingContext"; var EMBEDDING_CONTEXT_PRIMARY_TAB_SESSION_STORAGE_KEY = "isEmbeddingContextProvider"; var EMBEDDING_CONTEXT_PROP_NAME = "__EMBEDDING_CONTEXT__"; var EMBEDDING_CONTEXT_CLEANUP_POLLING_TIMEOUT_IN_MS = 2e3; var EMBEDDING_CONTEXT_SCHEMA = import_zod.z.strictObject({ dv: import_zod.z.literal(1), app: import_zod.z.strictObject({ id: import_zod.z.string(), version: import_zod.z.string().optional(), build: import_zod.z.string().optional() }), platform: import_zod.z.enum(["iOS", "Android", "web"]), os: import_zod.z.strictObject({ name: import_zod.z.string(), version: import_zod.z.string().optional() }).optional(), device: import_zod.z.strictObject({ id: import_zod.z.string() }) }); var EMBEDDING_CONTEXT_WITH_SOURCE_SCHEMA = import_zod.z.strictObject({ ctx: EMBEDDING_CONTEXT_SCHEMA, source: import_zod.z.enum(["query", "cookie"]) }); var IS_PRIMARY_ALIVE_MESSAGE_SCHEMA = import_zod.z.object({ type: import_zod.z.literal("EmbeddingContextPrimaryPolling"), data: import_zod.z.strictObject({ requestId: import_zod.z.string() }) }); var IS_PRIMARY_ALIVE_RESPONSE_SCHEMA = import_zod.z.object({ type: import_zod.z.literal("EmbeddingContextPrimaryPollingResult"), data: import_zod.z.strictObject({ requestId: import_zod.z.string(), isPrimary: import_zod.z.boolean() }) }); var ReactEmbeddingContext = (0, import_react.createContext)(null); function useEmbeddingContext() { return (0, import_react.useContext)(ReactEmbeddingContext); } function b64toContext(b64) { try { const bytes = Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)); const decodedUTFString = new TextDecoder().decode(bytes); const parsedCtx = JSON.parse(decodedUTFString); return EMBEDDING_CONTEXT_SCHEMA.parse(parsedCtx); } catch { return null; } } function contextToB64(ctx) { const stringCtx = JSON.stringify(ctx); const bytes = new TextEncoder().encode(stringCtx); return btoa(String.fromCharCode(...bytes)); } function getEmbeddingContext(req, res) { try { const queryParamValue = req ? new URL(req.url ?? "/", "https://_").searchParams.get(EMBEDDING_CONTEXT_QUERY_PARAM) : new URLSearchParams(window.location.search).get(EMBEDDING_CONTEXT_QUERY_PARAM); if (queryParamValue) { const ctx = b64toContext(decodeURIComponent(queryParamValue)); if (ctx) return { ctx, source: "query" }; } } catch { } const cookieValue = (0, import_cookies_next.getCookie)(EMBEDDING_CONTEXT_COOKIE_NAME, { req, res }); if (cookieValue) { const ctx = b64toContext(cookieValue); if (ctx) return { ctx, source: "cookie" }; } return null; } function withEmbeddingContext(App) { const WithEmbeddingContext = (props) => { const { pageProps } = props; const propsContextWithSource = (0, import_react.useMemo)(() => { const { success, data } = EMBEDDING_CONTEXT_WITH_SOURCE_SCHEMA.safeParse(pageProps[EMBEDDING_CONTEXT_PROP_NAME]); if (!success) return null; return data; }, [pageProps]); const [embeddingContext, setEmbeddingContext] = (0, import_react.useState)((propsContextWithSource == null ? void 0 : propsContextWithSource.ctx) ?? null); const [isPrimaryTab, setIsPrimaryTab] = (0, import_react.useState)((propsContextWithSource == null ? void 0 : propsContextWithSource.source) === "query" ? true : null); const [bcChannel, setBCChannel] = (0, import_react.useState)(null); (0, import_react.useEffect)(() => { if (isPrimaryTab === true && typeof window !== "undefined") { window.sessionStorage.setItem(EMBEDDING_CONTEXT_PRIMARY_TAB_SESSION_STORAGE_KEY, "true"); } if (isPrimaryTab === null && typeof window !== "undefined") { setIsPrimaryTab(window.sessionStorage.getItem(EMBEDDING_CONTEXT_PRIMARY_TAB_SESSION_STORAGE_KEY) === "true"); } }, [isPrimaryTab]); (0, import_react.useEffect)(() => { if (typeof window === "undefined" || !("BroadcastChannel" in window)) return; const bc = new BroadcastChannel("embeddingContext"); setBCChannel(bc); return () => { bc.close(); setBCChannel(null); }; }, []); (0, import_react.useEffect)(() => { if (isPrimaryTab === null || !bcChannel) return; if (isPrimaryTab) { const primaryListener = (e) => { var _a; const { success, data } = IS_PRIMARY_ALIVE_MESSAGE_SCHEMA.safeParse(e.data); if (!success || !((_a = data == null ? void 0 : data.data) == null ? void 0 : _a.requestId)) return; const response = { type: "EmbeddingContextPrimaryPollingResult", data: { isPrimary: true, requestId: data.data.requestId } }; bcChannel.postMessage(response); }; bcChannel.addEventListener("message", primaryListener); return () => { bcChannel.removeEventListener("message", primaryListener); }; } const requestId = generateUUIDv4(); const timeout = setTimeout(() => { (0, import_cookies_next.deleteCookie)(EMBEDDING_CONTEXT_COOKIE_NAME); setEmbeddingContext(null); setIsPrimaryTab(false); }, EMBEDDING_CONTEXT_CLEANUP_POLLING_TIMEOUT_IN_MS); const secondaryListener = (e) => { const { success, data } = IS_PRIMARY_ALIVE_RESPONSE_SCHEMA.safeParse(e.data); if (!success || (data == null ? void 0 : data.data.requestId) !== requestId) return; clearTimeout(timeout); }; bcChannel.addEventListener("message", secondaryListener); const pollMessage = { type: "EmbeddingContextPrimaryPolling", data: { requestId } }; bcChannel.postMessage(pollMessage); return () => { bcChannel.removeEventListener("message", secondaryListener); clearTimeout(timeout); }; }, [bcChannel, isPrimaryTab]); return /* @__PURE__ */ import_react.default.createElement(ReactEmbeddingContext.Provider, { value: embeddingContext }, /* @__PURE__ */ import_react.default.createElement(App, { ...props })); }; const appGetInitialProps = App.getInitialProps; if (appGetInitialProps) { WithEmbeddingContext.getInitialProps = async function(context) { const appProps = await appGetInitialProps(context); const { ctx } = context; const embeddingContextWithSource = getEmbeddingContext(ctx.req, ctx.res); if (embeddingContextWithSource && embeddingContextWithSource.source === "query") { (0, import_cookies_next.setCookie)(EMBEDDING_CONTEXT_COOKIE_NAME, contextToB64(embeddingContextWithSource.ctx), { req: ctx.req, res: ctx.res }); } return { ...appProps, pageProps: { ...appProps.pageProps, [EMBEDDING_CONTEXT_PROP_NAME]: embeddingContextWithSource } }; }; } return WithEmbeddingContext; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { getEmbeddingContext, useEmbeddingContext, withEmbeddingContext }); //# sourceMappingURL=embeddingContext.js.map