{"version":3,"sources":["../../src/helpers/cookies.ts"],"sourcesContent":["import { getCookie } from 'cookies-next'\nimport { createContext, useContext } from 'react'\n\nimport type { IncomingMessage, ServerResponse } from 'http'\nimport type { Context } from 'react'\n\nconst SSR_COOKIES_DEFAULT_PROP_NAME = '__SSR_COOKIES__'\n\nexport type SSRCookiesContextValues<CookiesList extends ReadonlyArray<string>> = Record<CookiesList[number], string | null>\n\ntype Optional<T> = T | undefined\n\ntype SSRProps<PropsType extends Record<string, unknown>> = {\n    props?: PropsType\n}\n\ntype SSRPropsWithCookies<\n    PropsType extends Record<string, unknown>,\n    CookiesList extends ReadonlyArray<string>,\n    CookiesPropName extends string = typeof SSR_COOKIES_DEFAULT_PROP_NAME,\n> = {\n    props: PropsType & {\n        [K in CookiesPropName]?: SSRCookiesContextValues<CookiesList>\n    }\n}\n\nexport type UseSSRCookiesExtractor<\n    CookiesList extends ReadonlyArray<string>,\n    CookiesPropName extends string = typeof SSR_COOKIES_DEFAULT_PROP_NAME,\n> = <PropsType extends Record<string, unknown>>(pageParams: SSRPropsWithCookies<PropsType, CookiesList, CookiesPropName>['props']) => SSRCookiesContextValues<CookiesList>\n\nexport type UseSSRCookies<CookiesList extends ReadonlyArray<string>> = () => SSRCookiesContextValues<CookiesList>\n\n/**\n * Helper that allows you to pass cookies from the request directly to the SSR,\n * thus avoiding layout shifts and loading states.\n *\n * NOTE: You should not use this tool to pass secure http-only cookies to the client,\n * that's why each application must define the list of allowed cookies itself.\n *\n * @example Init helper and export utils for app\n * import { SSRCookiesHelper } from '@open-condo/miniapp-utils/helpers/cookies'\n * import type { SSRCookiesContextValues } from '@open-condo/miniapp-utils/helpers/cookies'\n *\n * import type { Context } from 'react'\n *\n * // NOTE: put here only cookies needed in SRR (hydration), does not put http-only cookies here\n * const VITAL_COOKIES = ['residentId', 'isLayoutMinified'] as const\n *\n * const cookieHelper = new SSRCookiesHelper(VITAL_COOKIES)\n *\n * export const extractSSRCookies = cookieHelper.extractSSRCookies\n * export const useSSRCookiesExtractor = cookieHelper.generateUseSSRCookiesExtractorHook()\n * export const useSSRCookies = cookieHelper.generateUseSSRCookiesHook()\n * export const SSRCookiesContext = cookieHelper.getContext() as Context<SSRCookiesContextValues<typeof VITAL_COOKIES>>\n *\n * @example Extract cookies in getServerSideProps / getInitialProps\n * import { extractSSRCookies } from '@/domains/common/utils/ssr'\n *\n * export const getServerSideProps = async ({ req, res }) => {\n *     return extractSSRCookies(req, res, {\n *         props: { ... }\n *     })\n * }\n *\n * @example Pass extracted cookies to React context in your _app.ts\n * import { SSRCookiesContext } from '@/domains/common/utils/ssr'\n *\n * export default function App ({ Component, pageProps }: AppProps): ReactNode {\n *     const ssrCookies = useSSRCookiesExtractor(pageProps)\n *\n *     return (\n *         <SSRCookiesContext.Provider value={ssrCookies}>\n *             <Component {...pageProps} />\n *         </SSRCookiesContext.Provider>\n *     )\n * }\n *\n * @example Use extracted cookies anywhere in your app.\n * // /domains/common/components/Layout.tsx\n * import { useState } from 'react'\n * import { useSSRCookies } from '@/domains/common/utils/ssr'\n *\n * import type { FC } from 'react'\n *\n * export const Layout: FC = () => {\n *     const { isLayoutMinified } = useSSRCookies()\n *\n *     const [layoutMinified, setLayoutMinified] = useState(isLayoutMinified === 'true')\n *\n *     return {\n *         // ...\n *     }\n * }\n */\nexport class SSRCookiesHelper<\n    CookiesList extends ReadonlyArray<string>,\n    CookiesPropName extends string = typeof SSR_COOKIES_DEFAULT_PROP_NAME,\n> {\n    allowedCookies: CookiesList\n    propName: CookiesPropName\n    private readonly context: Context<SSRCookiesContextValues<CookiesList>>\n    private readonly defaultValues: SSRCookiesContextValues<CookiesList>\n\n    constructor (allowedCookies: CookiesList, propName?: CookiesPropName) {\n        this.allowedCookies = allowedCookies\n        this.propName = propName || SSR_COOKIES_DEFAULT_PROP_NAME as CookiesPropName\n        this.defaultValues = Object.fromEntries(allowedCookies.map(key => [key, null])) as SSRCookiesContextValues<CookiesList>\n        this.context = createContext<SSRCookiesContextValues<CookiesList>>(this.defaultValues)\n\n        this.extractSSRCookies = this.extractSSRCookies.bind(this)\n    }\n\n    getContext (): Context<SSRCookiesContextValues<CookiesList>> {\n        return this.context\n    }\n\n    generateUseSSRCookiesExtractorHook (): UseSSRCookiesExtractor<CookiesList, CookiesPropName> {\n        const defaultValues = this.defaultValues\n        const propName = this.propName\n\n        return function useSSRCookiesExtractor<PropsType extends Record<string, unknown>> (\n            pageProps: SSRPropsWithCookies<PropsType, CookiesList, CookiesPropName>['props']\n        ): SSRCookiesContextValues<CookiesList> {\n            return pageProps[propName] || defaultValues\n        }\n    }\n\n    generateUseSSRCookiesHook (): UseSSRCookies<CookiesList> {\n        const context = this.context\n\n        return function useSSRCookies (): SSRCookiesContextValues<CookiesList> {\n            return useContext(context)\n        }\n    }\n\n    extractSSRCookies<PropsType extends Record<string, unknown>> (\n        req: Optional<IncomingMessage>,\n        res: Optional<ServerResponse>,\n        pageParams: SSRProps<PropsType>\n    ): SSRPropsWithCookies<PropsType, CookiesList, CookiesPropName>  {\n        return {\n            ...pageParams,\n            props: {\n                ...pageParams.props,\n                [this.propName]: Object.fromEntries(\n                    Object.keys(this.defaultValues).map(key => [\n                        key,\n                        getCookie(key, { req, res }) || null,\n                    ])\n                ),\n            },\n        } as SSRPropsWithCookies<PropsType, CookiesList, CookiesPropName>\n    }\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,eAAe,kBAAkB;AAK1C,IAAM,gCAAgC;AAyF/B,IAAM,mBAAN,MAGL;AAAA,EAME,YAAa,gBAA6B,UAA4B;AAClE,SAAK,iBAAiB;AACtB,SAAK,WAAW,YAAY;AAC5B,SAAK,gBAAgB,OAAO,YAAY,eAAe,IAAI,SAAO,CAAC,KAAK,IAAI,CAAC,CAAC;AAC9E,SAAK,UAAU,cAAoD,KAAK,aAAa;AAErF,SAAK,oBAAoB,KAAK,kBAAkB,KAAK,IAAI;AAAA,EAC7D;AAAA,EAEA,aAA6D;AACzD,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,qCAA4F;AACxF,UAAM,gBAAgB,KAAK;AAC3B,UAAM,WAAW,KAAK;AAEtB,WAAO,SAAS,uBACZ,WACoC;AACpC,aAAO,UAAU,QAAQ,KAAK;AAAA,IAClC;AAAA,EACJ;AAAA,EAEA,4BAAyD;AACrD,UAAM,UAAU,KAAK;AAErB,WAAO,SAAS,gBAAuD;AACnE,aAAO,WAAW,OAAO;AAAA,IAC7B;AAAA,EACJ;AAAA,EAEA,kBACI,KACA,KACA,YAC6D;AAC7D,WAAO;AAAA,MACH,GAAG;AAAA,MACH,OAAO;AAAA,QACH,GAAG,WAAW;AAAA,QACd,CAAC,KAAK,QAAQ,GAAG,OAAO;AAAA,UACpB,OAAO,KAAK,KAAK,aAAa,EAAE,IAAI,SAAO;AAAA,YACvC;AAAA,YACA,UAAU,KAAK,EAAE,KAAK,IAAI,CAAC,KAAK;AAAA,UACpC,CAAC;AAAA,QACL;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;","names":[]}